@@ -338,8 +338,40 @@ def _schema_map_to_type(
338338 ), state
339339
340340
341+ def _schema_freeform_object_to_type (schema : dict ) -> TypeAnnotation :
342+ return _nullable (
343+ DictAnnotation (NamedAnnotation ("str" ), AnyAnnotation ()),
344+ bool (schema .get ("nullable" )),
345+ )
346+
347+
348+ def _enum_values_for_schema (state : _TypeState , schema : dict ) -> tuple [object , ...]:
349+ if "enum" in schema and isinstance (schema ["enum" ], list ):
350+ return tuple (schema ["enum" ])
351+
352+ ref = schema .get ("$ref" )
353+ if isinstance (ref , str ) and ref .startswith ("#/components/schemas/" ):
354+ component = ref .rsplit ("/" , 1 )[- 1 ]
355+ component_schema = safe_get (state .components , "schemas" , component , type = dict )
356+ if component_schema is not None and isinstance (
357+ component_schema .get ("enum" ), list
358+ ):
359+ return tuple (component_schema ["enum" ])
360+
361+ return ()
362+
363+
364+ def _with_enum_values (
365+ state : _TypeState , schema : dict , annotation : TypeAnnotation
366+ ) -> TypeAnnotation :
367+ values = _enum_values_for_schema (state , schema )
368+ if not values :
369+ return annotation
370+ return _union ((annotation , LiteralAnnotation (values )))
371+
372+
341373def _schema_object_to_type (
342- state : _TypeState , schema : dict , hint : str
374+ state : _TypeState , schema : dict , hint : str , * , allow_enum_values : bool = False
343375) -> tuple [TypeAnnotation , _TypeState ]:
344376 nullable = bool (schema .get ("nullable" ))
345377 name = _type_name_from_hint (hint )
@@ -356,8 +388,13 @@ def _schema_object_to_type(
356388 prop_title = str (safe_get (prop_schema , "title" ) or prop_name )
357389 prop_schema = safe_get (props , prop_name , type = dict ) or {}
358390 field_type , state = _schema_to_type (
359- state , prop_schema , f"{ name } { _pascal (prop_title )} "
391+ state ,
392+ prop_schema ,
393+ f"{ name } { _pascal (prop_title )} " ,
394+ allow_enum_values = allow_enum_values ,
360395 )
396+ if allow_enum_values :
397+ field_type = _with_enum_values (state , prop_schema , field_type )
361398 fields .append (
362399 FieldDef (
363400 name = prop_name ,
@@ -385,6 +422,7 @@ def _schema_to_type(
385422 hint : str ,
386423 * ,
387424 component_name : str | None = None ,
425+ allow_enum_values : bool = False ,
388426) -> tuple [TypeAnnotation , _TypeState ]:
389427 """
390428 Takes a JSON schema object and returns the corresponding Python type
@@ -425,16 +463,17 @@ def _schema_to_type(
425463 if schema_type == "array" :
426464 return _schema_array_to_type (state , schema , hint )
427465
428- additional_properties = safe_get (schema , "additionalProperties" , type = dict )
429- if (
430- schema_type == "object"
431- and "properties" not in schema
432- and additional_properties is not None
433- ):
434- return _schema_map_to_type (state , schema , hint )
466+ additional_properties = schema .get ("additionalProperties" )
467+ if schema_type == "object" and "properties" not in schema :
468+ if additional_properties is True :
469+ return _schema_freeform_object_to_type (schema ), state
470+ if isinstance (additional_properties , dict ):
471+ return _schema_map_to_type (state , schema , hint )
435472
436473 if schema_type == "object" or "properties" in schema :
437- return _schema_object_to_type (state , schema , hint )
474+ return _schema_object_to_type (
475+ state , schema , hint , allow_enum_values = allow_enum_values
476+ )
438477
439478 base = _PRIMITIVES .get (str (schema_type ), "Any" )
440479 annotation : TypeAnnotation = (
@@ -444,9 +483,11 @@ def _schema_to_type(
444483
445484
446485def _schema_type (
447- state : _TypeState , schema : dict , hint : str
486+ state : _TypeState , schema : dict , hint : str , * , allow_enum_values : bool = False
448487) -> tuple [TypeAnnotation , _TypeState ]:
449- return _schema_to_type (state , schema or {}, hint )
488+ return _schema_to_type (
489+ state , schema or {}, hint , allow_enum_values = allow_enum_values
490+ )
450491
451492
452493def _path_symbol (path : str ) -> str :
@@ -547,6 +588,7 @@ def _bucket_type(
547588 "required" : list (bucket .required ),
548589 },
549590 hint ,
591+ allow_enum_values = True ,
550592 )
551593
552594
0 commit comments