11from __future__ import annotations
22
3+ from dataclasses import dataclass
34from itertools import chain
45from typing import Any , ClassVar , NamedTuple
56
1415from .schemas import Class , ReferencePath , Schemas , parse_reference_path
1516
1617
18+ @dataclass
19+ class ModelDetails :
20+ required_properties : list [Property ] | None = None
21+ optional_properties : list [Property ] | None = None
22+ additional_properties : Property | None = None
23+ relative_imports : set [str ] | None = None
24+ lazy_imports : set [str ] | None = None
25+
26+
1727@define
1828class ModelProperty (PropertyProtocol ):
1929 """A property which refers to another Schema"""
@@ -27,11 +37,7 @@ class ModelProperty(PropertyProtocol):
2737 data : oai .Schema
2838 description : str
2939 roots : set [ReferencePath | utils .ClassName ]
30- required_properties : list [Property ] | None
31- optional_properties : list [Property ] | None
32- relative_imports : set [str ] | None
33- lazy_imports : set [str ] | None
34- additional_properties : Property | None
40+ details : ModelDetails
3541 _json_type_string : ClassVar [str ] = "Dict[str, Any]"
3642
3743 template : ClassVar [str ] = "model_property.py.jinja"
@@ -75,22 +81,18 @@ def build(
7581 class_string = title
7682 class_info = Class .from_string (string = class_string , config = config )
7783 model_roots = {* roots , class_info .name }
78- required_properties : list [Property ] | None = None
79- optional_properties : list [Property ] | None = None
80- relative_imports : set [str ] | None = None
81- lazy_imports : set [str ] | None = None
82- additional_properties : Property | None = None
84+ details = ModelDetails ()
8385 if process_properties :
8486 data_or_err , schemas = _process_property_data (
8587 data = data , schemas = schemas , class_info = class_info , config = config , roots = model_roots
8688 )
8789 if isinstance (data_or_err , PropertyError ):
8890 return data_or_err , schemas
89- property_data , additional_properties = data_or_err
90- required_properties = property_data .required_props
91- optional_properties = property_data .optional_props
92- relative_imports = property_data .relative_imports
93- lazy_imports = property_data .lazy_imports
91+ property_data , details . additional_properties = data_or_err
92+ details . required_properties = property_data .required_props
93+ details . optional_properties = property_data .optional_props
94+ details . relative_imports = property_data .relative_imports
95+ details . lazy_imports = property_data .lazy_imports
9496 for root in roots :
9597 if isinstance (root , utils .ClassName ):
9698 continue
@@ -100,11 +102,7 @@ def build(
100102 class_info = class_info ,
101103 data = data ,
102104 roots = model_roots ,
103- required_properties = required_properties ,
104- optional_properties = optional_properties ,
105- relative_imports = relative_imports ,
106- lazy_imports = lazy_imports ,
107- additional_properties = additional_properties ,
105+ details = details ,
108106 description = data .description or "" ,
109107 default = None ,
110108 required = required ,
@@ -125,14 +123,39 @@ def build(
125123 )
126124 return prop , schemas
127125
126+ def needs_processing (self ) -> bool :
127+ return not (
128+ isinstance (self .details .required_properties , list ) and isinstance (self .details .optional_properties , list )
129+ )
130+
131+ @property
132+ def required_properties (self ) -> list [Property ]:
133+ return self .details .required_properties or []
134+
135+ @property
136+ def optional_properties (self ) -> list [Property ]:
137+ return self .details .optional_properties or []
138+
139+ @property
140+ def additional_properties (self ) -> Property | None :
141+ return self .details .additional_properties
142+
143+ @property
144+ def relative_imports (self ) -> set [str ]:
145+ return self .details .relative_imports or set ()
146+
147+ @property
148+ def lazy_imports (self ) -> set [str ] | None :
149+ return self .details .lazy_imports or set ()
150+
128151 @classmethod
129152 def convert_value (cls , value : Any ) -> Value | None | PropertyError :
130153 if value is not None :
131154 return PropertyError (detail = "ModelProperty cannot have a default value" ) # pragma: no cover
132155 return None
133156
134157 def __attrs_post_init__ (self ) -> None :
135- if self .relative_imports :
158+ if self .details . relative_imports :
136159 self .set_relative_imports (self .relative_imports )
137160
138161 @property
@@ -175,15 +198,15 @@ def set_relative_imports(self, relative_imports: set[str]) -> None:
175198 Args:
176199 relative_imports: The set of relative import strings
177200 """
178- object . __setattr__ ( self , " relative_imports" , {ri for ri in relative_imports if self .self_import not in ri })
201+ self . details . relative_imports = {ri for ri in relative_imports if self .self_import not in ri }
179202
180203 def set_lazy_imports (self , lazy_imports : set [str ]) -> None :
181204 """Set the lazy imports set for this ModelProperty, filtering out self imports
182205
183206 Args:
184207 lazy_imports: The set of lazy import strings
185208 """
186- object . __setattr__ ( self , " lazy_imports" , {li for li in lazy_imports if self .self_import not in li })
209+ self . details . lazy_imports = {li for li in lazy_imports if self .self_import not in li }
187210
188211 def get_type_string (
189212 self ,
@@ -289,9 +312,7 @@ def _add_if_no_conflict(new_prop: Property) -> PropertyError | None:
289312 if not isinstance (sub_model , ModelProperty ):
290313 return PropertyError ("Cannot take allOf a non-object" )
291314 # Properties of allOf references first should be processed first
292- if not (
293- isinstance (sub_model .required_properties , list ) and isinstance (sub_model .optional_properties , list )
294- ):
315+ if sub_model .needs_processing ():
295316 return PropertyError (f"Reference { sub_model .name } in allOf was not processed" , data = sub_prop )
296317 for prop in chain (sub_model .required_properties , sub_model .optional_properties ):
297318 err = _add_if_no_conflict (prop )
@@ -437,9 +458,10 @@ def process_model(model_prop: ModelProperty, *, schemas: Schemas, config: Config
437458
438459 property_data , additional_properties = data_or_err
439460
440- object .__setattr__ (model_prop , "required_properties" , property_data .required_props )
441- object .__setattr__ (model_prop , "optional_properties" , property_data .optional_props )
461+ model_prop .details .required_properties = property_data .required_props
462+ model_prop .details .optional_properties = property_data .optional_props
463+ model_prop .details .additional_properties = additional_properties
442464 model_prop .set_relative_imports (property_data .relative_imports )
443465 model_prop .set_lazy_imports (property_data .lazy_imports )
444- object . __setattr__ ( model_prop , "additional_properties" , additional_properties )
466+
445467 return schemas
0 commit comments