@@ -28,6 +28,7 @@ class Property:
2828
2929 name : str
3030 required : bool
31+ nullable : bool
3132 default : Optional [Any ]
3233
3334 template : ClassVar [Optional [str ]] = None
@@ -45,8 +46,13 @@ def _validate_default(self, default: Any) -> Any:
4546 raise ValidationError
4647
4748 def get_type_string (self , no_optional : bool = False ) -> str :
48- """ Get a string representation of type that should be used when declaring this property """
49- if self .required or no_optional :
49+ """
50+ Get a string representation of type that should be used when declaring this property
51+
52+ Args:
53+ no_optional: Do not include Optional even if the value is optional (needed for isinstance checks)
54+ """
55+ if no_optional or (self .required and not self .nullable ):
5056 return self ._type_string
5157 return f"Optional[{ self ._type_string } ]"
5258
@@ -213,7 +219,7 @@ class ListProperty(Property, Generic[InnerProp]):
213219
214220 def get_type_string (self , no_optional : bool = False ) -> str :
215221 """ Get a string representation of type that should be used when declaring this property """
216- if self .required or no_optional :
222+ if no_optional or ( self .required and not self . nullable ) :
217223 return f"List[{ self .inner_property .get_type_string ()} ]"
218224 return f"Optional[List[{ self .inner_property .get_type_string ()} ]]"
219225
@@ -254,7 +260,7 @@ def get_type_string(self, no_optional: bool = False) -> str:
254260 """ Get a string representation of type that should be used when declaring this property """
255261 inner_types = [p .get_type_string () for p in self .inner_properties ]
256262 inner_prop_string = ", " .join (inner_types )
257- if self .required or no_optional :
263+ if no_optional or ( self .required and not self . nullable ) :
258264 return f"Union[{ inner_prop_string } ]"
259265 return f"Optional[Union[{ inner_prop_string } ]]"
260266
@@ -321,7 +327,7 @@ def get_enum(name: str) -> Optional[EnumProperty]:
321327 def get_type_string (self , no_optional : bool = False ) -> str :
322328 """ Get a string representation of type that should be used when declaring this property """
323329
324- if self .required or no_optional :
330+ if no_optional or ( self .required and not self . nullable ) :
325331 return self .reference .class_name
326332 return f"Optional[{ self .reference .class_name } ]"
327333
@@ -376,7 +382,7 @@ def template(self) -> str: # type: ignore
376382
377383 def get_type_string (self , no_optional : bool = False ) -> str :
378384 """ Get a string representation of type that should be used when declaring this property """
379- if self .required or no_optional :
385+ if no_optional or ( self .required and not self . nullable ) :
380386 return self .reference .class_name
381387 return f"Optional[{ self .reference .class_name } ]"
382388
@@ -438,13 +444,15 @@ def _string_based_property(
438444 """ Construct a Property from the type "string" """
439445 string_format = data .schema_format
440446 if string_format == "date-time" :
441- return DateTimeProperty (name = name , required = required , default = data .default )
447+ return DateTimeProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
442448 elif string_format == "date" :
443- return DateProperty (name = name , required = required , default = data .default )
449+ return DateProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
444450 elif string_format == "binary" :
445- return FileProperty (name = name , required = required , default = data .default )
451+ return FileProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
446452 else :
447- return StringProperty (name = name , default = data .default , required = required , pattern = data .pattern )
453+ return StringProperty (
454+ name = name , default = data .default , required = required , pattern = data .pattern , nullable = data .nullable ,
455+ )
448456
449457
450458def _property_from_data (
@@ -453,14 +461,17 @@ def _property_from_data(
453461 """ Generate a Property from the OpenAPI dictionary representation of it """
454462 name = utils .remove_string_escapes (name )
455463 if isinstance (data , oai .Reference ):
456- return RefProperty (name = name , required = required , reference = Reference .from_ref (data .ref ), default = None )
464+ return RefProperty (
465+ name = name , required = required , reference = Reference .from_ref (data .ref ), default = None , nullable = False ,
466+ )
457467 if data .enum :
458468 return EnumProperty (
459469 name = name ,
460470 required = required ,
461471 values = EnumProperty .values_from_list (data .enum ),
462472 title = data .title or name ,
463473 default = data .default ,
474+ nullable = data .nullable ,
464475 )
465476 if data .anyOf or data .oneOf :
466477 sub_properties : List [Property ] = []
@@ -469,26 +480,30 @@ def _property_from_data(
469480 if isinstance (sub_prop , PropertyError ):
470481 return PropertyError (detail = f"Invalid property in union { name } " , data = sub_prop_data )
471482 sub_properties .append (sub_prop )
472- return UnionProperty (name = name , required = required , default = data .default , inner_properties = sub_properties )
483+ return UnionProperty (
484+ name = name , required = required , default = data .default , inner_properties = sub_properties , nullable = data .nullable ,
485+ )
473486 if not data .type :
474487 return PropertyError (data = data , detail = "Schemas must either have one of enum, anyOf, or type defined." )
475488 if data .type == "string" :
476489 return _string_based_property (name = name , required = required , data = data )
477490 elif data .type == "number" :
478- return FloatProperty (name = name , default = data .default , required = required )
491+ return FloatProperty (name = name , default = data .default , required = required , nullable = data . nullable , )
479492 elif data .type == "integer" :
480- return IntProperty (name = name , default = data .default , required = required )
493+ return IntProperty (name = name , default = data .default , required = required , nullable = data . nullable , )
481494 elif data .type == "boolean" :
482- return BooleanProperty (name = name , required = required , default = data .default )
495+ return BooleanProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
483496 elif data .type == "array" :
484497 if data .items is None :
485498 return PropertyError (data = data , detail = "type array must have items defined" )
486499 inner_prop = property_from_data (name = f"{ name } _item" , required = True , data = data .items )
487500 if isinstance (inner_prop , PropertyError ):
488501 return PropertyError (data = inner_prop .data , detail = f"invalid data in items of array { name } " )
489- return ListProperty (name = name , required = required , default = data .default , inner_property = inner_prop ,)
502+ return ListProperty (
503+ name = name , required = required , default = data .default , inner_property = inner_prop , nullable = data .nullable ,
504+ )
490505 elif data .type == "object" :
491- return DictProperty (name = name , required = required , default = data .default )
506+ return DictProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
492507 return PropertyError (data = data , detail = f"unknown type { data .type } " )
493508
494509
0 commit comments