@@ -288,6 +288,16 @@ def property_from_data( # noqa: PLR0911, PLR0912
288288 process_properties = process_properties ,
289289 roots = roots ,
290290 )
291+ if data .allOf and _all_of_is_values (data .allOf , schemas ):
292+ return _property_from_values_all_of (
293+ name = name ,
294+ required = required ,
295+ data = data ,
296+ schemas = schemas ,
297+ parent_name = parent_name ,
298+ config = config ,
299+ roots = roots ,
300+ )
291301 if data .type == oai .DataType .OBJECT or data .allOf or (data .type is None and data .properties ):
292302 return ModelProperty .build (
293303 data = data ,
@@ -472,3 +482,70 @@ def build_parameters(
472482
473483 parameters .errors .extend (errors )
474484 return parameters
485+
486+
487+ def _all_of_is_values (parts : list [oai .Reference | oai .Schema ], schemas : Schemas ) -> bool :
488+ """Whether every part of an allOf describes a value (an enum, string, number...) rather than an object.
489+
490+ Such an allOf narrows a value, for example a reference to an enum plus `enum: [ONE_VALUE]`. It is merged
491+ property by property instead of being built as a model.
492+ """
493+ for part in parts :
494+ if isinstance (part , oai .Reference ):
495+ ref_path = parse_reference_path (part .ref )
496+ if isinstance (ref_path , ParseError ):
497+ return False
498+ existing = schemas .classes_by_reference .get (ref_path )
499+ if existing is None or isinstance (existing , ModelProperty ):
500+ return False
501+ continue
502+ if part .type == oai .DataType .OBJECT or part .properties or part .allOf or part .anyOf or part .oneOf :
503+ return False
504+ return True
505+
506+
507+ def _property_from_values_all_of (
508+ * ,
509+ name : UntrustedString ,
510+ required : bool ,
511+ data : oai .Schema ,
512+ schemas : Schemas ,
513+ parent_name : str ,
514+ config : Config ,
515+ roots : set [ReferencePath | strings .ClassName ],
516+ ) -> tuple [Property | PropertyError , Schemas ]:
517+ """Merge the parts of a value allOf into one property, using the same rules as merging model properties."""
518+ from .merge_properties import merge_properties # noqa: PLC0415
519+
520+ merged : Property | None = None
521+ for part in data .allOf :
522+ prop , schemas = property_from_data (
523+ name = name ,
524+ required = required ,
525+ data = part ,
526+ schemas = schemas ,
527+ parent_name = parent_name ,
528+ config = config ,
529+ roots = roots ,
530+ )
531+ if isinstance (prop , PropertyError ):
532+ return prop , schemas
533+ if merged is None :
534+ merged = prop
535+ continue
536+ result = merge_properties (merged , prop )
537+ if isinstance (result , PropertyError ):
538+ result .data = data
539+ return result , schemas
540+ merged = result
541+ assert merged is not None
542+ return (
543+ evolve (
544+ merged ,
545+ required = required ,
546+ name = name ,
547+ python_name = strings .PythonIdentifier (value = name , prefix = config .field_prefix ),
548+ description = data .description or merged .description ,
549+ ),
550+ schemas ,
551+ )
0 commit comments