|
38 | 38 | '_add_unevaluated_items_to_fixed_len_tuple_schema', |
39 | 39 | '_is_builtin_primitive_or_compound', |
40 | 40 | '_is_default_value_compatible', |
41 | | - '_parse_schema_from_parameter', |
42 | 41 | '_get_required_fields', |
43 | 42 | ] |
44 | 43 |
|
@@ -137,189 +136,16 @@ def _is_default_value_compatible( |
137 | 136 | return False |
138 | 137 |
|
139 | 138 |
|
140 | | -def _parse_schema_from_parameter( # type: ignore[return] |
141 | | - api_option: Literal['VERTEX_AI', 'GEMINI_API'], |
142 | | - param: inspect.Parameter, |
143 | | - func_name: str, |
144 | | -) -> types.Schema: |
145 | | - """parse schema from parameter. |
146 | | -
|
147 | | - from the simplest case to the most complex case. |
148 | | - """ |
149 | | - schema = types.Schema() |
150 | | - default_value_error_msg = ( |
151 | | - f'Default value {param.default} of parameter {param} of function' |
152 | | - f' {func_name} is not compatible with the parameter annotation' |
153 | | - f' {param.annotation}.' |
154 | | - ) |
155 | | - if _is_builtin_primitive_or_compound(param.annotation): |
156 | | - if param.default is not inspect.Parameter.empty: |
157 | | - if not _is_default_value_compatible(param.default, param.annotation): |
158 | | - raise ValueError(default_value_error_msg) |
159 | | - schema.default = param.default |
160 | | - schema.type = _py_builtin_type_to_schema_type[param.annotation] |
161 | | - return schema |
162 | | - if ( |
163 | | - isinstance(param.annotation, VersionedUnionType) |
164 | | - # only parse simple UnionType, example int | str | float | bool |
165 | | - # complex UnionType will be invoked in raise branch |
166 | | - and all( |
167 | | - (_is_builtin_primitive_or_compound(arg) or arg is type(None)) |
168 | | - for arg in get_args(param.annotation) |
169 | | - ) |
170 | | - ): |
171 | | - schema.type = _py_builtin_type_to_schema_type[dict] |
172 | | - schema.any_of = [] |
173 | | - unique_types = set() |
174 | | - for arg in get_args(param.annotation): |
175 | | - if arg.__name__ == 'NoneType': # Optional type |
176 | | - schema.nullable = True |
177 | | - continue |
178 | | - schema_in_any_of = _parse_schema_from_parameter( |
179 | | - api_option, |
180 | | - inspect.Parameter( |
181 | | - 'item', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=arg |
182 | | - ), |
183 | | - func_name, |
184 | | - ) |
185 | | - if ( |
186 | | - schema_in_any_of.model_dump_json(exclude_none=True) |
187 | | - not in unique_types |
188 | | - ): |
189 | | - schema.any_of.append(schema_in_any_of) |
190 | | - unique_types.add(schema_in_any_of.model_dump_json(exclude_none=True)) |
191 | | - if len(schema.any_of) == 1: # param: list | None -> Array |
192 | | - schema.type = schema.any_of[0].type |
193 | | - schema.any_of = None |
194 | | - if ( |
195 | | - param.default is not inspect.Parameter.empty |
196 | | - and param.default is not None |
197 | | - ): |
198 | | - if not _is_default_value_compatible(param.default, param.annotation): |
199 | | - raise ValueError(default_value_error_msg) |
200 | | - schema.default = param.default |
201 | | - return schema |
202 | | - if isinstance(param.annotation, _GenericAlias) or isinstance( |
203 | | - param.annotation, builtin_types.GenericAlias |
204 | | - ): |
205 | | - origin = get_origin(param.annotation) |
206 | | - args = get_args(param.annotation) |
207 | | - if origin is dict: |
208 | | - schema.type = _py_builtin_type_to_schema_type[dict] |
209 | | - if param.default is not inspect.Parameter.empty: |
210 | | - if not _is_default_value_compatible(param.default, param.annotation): |
211 | | - raise ValueError(default_value_error_msg) |
212 | | - schema.default = param.default |
213 | | - return schema |
214 | | - if origin is Literal: |
215 | | - if not all(isinstance(arg, str) for arg in args): |
216 | | - raise ValueError( |
217 | | - f'Literal type {param.annotation} must be a list of strings.' |
218 | | - ) |
219 | | - schema.type = _py_builtin_type_to_schema_type[str] |
220 | | - schema.enum = list(args) |
221 | | - if param.default is not inspect.Parameter.empty: |
222 | | - if not _is_default_value_compatible(param.default, param.annotation): |
223 | | - raise ValueError(default_value_error_msg) |
224 | | - schema.default = param.default |
225 | | - return schema |
226 | | - if origin is list: |
227 | | - schema.type = _py_builtin_type_to_schema_type[list] |
228 | | - schema.items = _parse_schema_from_parameter( |
229 | | - api_option, |
230 | | - inspect.Parameter( |
231 | | - 'item', |
232 | | - inspect.Parameter.POSITIONAL_OR_KEYWORD, |
233 | | - annotation=args[0], |
234 | | - ), |
235 | | - func_name, |
236 | | - ) |
237 | | - if param.default is not inspect.Parameter.empty: |
238 | | - if not _is_default_value_compatible(param.default, param.annotation): |
239 | | - raise ValueError(default_value_error_msg) |
240 | | - schema.default = param.default |
241 | | - return schema |
242 | | - if origin is Union: |
243 | | - schema.any_of = [] |
244 | | - schema.type = _py_builtin_type_to_schema_type[dict] |
245 | | - unique_types = set() |
246 | | - for arg in args: |
247 | | - # The first check is for NoneType in Python 3.9, since the __name__ |
248 | | - # attribute is not available in Python 3.9 |
249 | | - if type(arg) is type(None) or ( |
250 | | - hasattr(arg, '__name__') and arg.__name__ == 'NoneType' |
251 | | - ): # Optional type |
252 | | - schema.nullable = True |
253 | | - continue |
254 | | - schema_in_any_of = _parse_schema_from_parameter( |
255 | | - api_option, |
256 | | - inspect.Parameter( |
257 | | - 'item', |
258 | | - inspect.Parameter.POSITIONAL_OR_KEYWORD, |
259 | | - annotation=arg, |
260 | | - ), |
261 | | - func_name, |
262 | | - ) |
263 | | - if ( |
264 | | - len(param.annotation.__args__) == 2 |
265 | | - and type(None) in param.annotation.__args__ |
266 | | - ): # Optional type |
267 | | - for optional_arg in param.annotation.__args__: |
268 | | - if ( |
269 | | - hasattr(optional_arg, '__origin__') |
270 | | - and optional_arg.__origin__ is list |
271 | | - ): |
272 | | - # Optional type with list, for example Optional[list[str]] |
273 | | - schema.items = schema_in_any_of.items |
274 | | - if ( |
275 | | - schema_in_any_of.model_dump_json(exclude_none=True) |
276 | | - not in unique_types |
277 | | - ): |
278 | | - schema.any_of.append(schema_in_any_of) |
279 | | - unique_types.add(schema_in_any_of.model_dump_json(exclude_none=True)) |
280 | | - if len(schema.any_of) == 1: # param: Union[List, None] -> Array |
281 | | - schema.type = schema.any_of[0].type |
282 | | - schema.any_of = None |
283 | | - if ( |
284 | | - param.default is not None |
285 | | - and param.default is not inspect.Parameter.empty |
286 | | - ): |
287 | | - if not _is_default_value_compatible(param.default, param.annotation): |
288 | | - raise ValueError(default_value_error_msg) |
289 | | - schema.default = param.default |
290 | | - return schema |
291 | | - # all other generic alias will be invoked in raise branch |
292 | | - if ( |
293 | | - # for user defined class, we only support pydantic model |
294 | | - _extra_utils.is_annotation_pydantic_model(param.annotation) |
295 | | - ): |
296 | | - if ( |
297 | | - param.default is not inspect.Parameter.empty |
298 | | - and param.default is not None |
299 | | - ): |
300 | | - schema.default = param.default |
301 | | - schema.type = _py_builtin_type_to_schema_type[dict] |
302 | | - schema.properties = {} |
303 | | - for field_name, field_info in param.annotation.model_fields.items(): |
304 | | - schema.properties[field_name] = _parse_schema_from_parameter( |
305 | | - api_option, |
306 | | - inspect.Parameter( |
307 | | - field_name, |
308 | | - inspect.Parameter.POSITIONAL_OR_KEYWORD, |
309 | | - annotation=field_info.annotation, |
310 | | - ), |
311 | | - func_name, |
312 | | - ) |
313 | | - schema.required = _get_required_fields(schema) |
314 | | - return schema |
315 | | - _raise_for_unsupported_param(param, func_name, ValueError) |
316 | | - |
317 | | - |
318 | | -def _get_required_fields(schema: types.Schema) -> Optional[list[str]]: |
319 | | - if not schema.properties: |
| 139 | +def _get_required_fields(json_schema: dict[str, Any]) -> Optional[list[str]]: |
| 140 | + properties = json_schema.get('properties', {}) |
| 141 | + if not properties: |
320 | 142 | return None |
321 | | - return [ |
322 | | - field_name |
323 | | - for field_name, field_schema in schema.properties.items() |
324 | | - if not field_schema.nullable and field_schema.default is None |
325 | | - ] |
| 143 | + required_fields = [] |
| 144 | + for field_name, field_schema in properties.items(): |
| 145 | + if not field_schema: |
| 146 | + continue |
| 147 | + if 'nullable' in field_schema and not field_schema['nullable']: |
| 148 | + required_fields.append(field_name) |
| 149 | + if 'default' not in field_schema and field_name not in required_fields: |
| 150 | + required_fields.append(field_name) |
| 151 | + return required_fields |
0 commit comments