@@ -28,6 +28,7 @@ class Property:
28
28
29
29
name : str
30
30
required : bool
31
+ nullable : bool
31
32
default : Optional [Any ]
32
33
33
34
template : ClassVar [Optional [str ]] = None
@@ -45,8 +46,13 @@ def _validate_default(self, default: Any) -> Any:
45
46
raise ValidationError
46
47
47
48
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 ):
50
56
return self ._type_string
51
57
return f"Optional[{ self ._type_string } ]"
52
58
@@ -213,7 +219,7 @@ class ListProperty(Property, Generic[InnerProp]):
213
219
214
220
def get_type_string (self , no_optional : bool = False ) -> str :
215
221
""" 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 ) :
217
223
return f"List[{ self .inner_property .get_type_string ()} ]"
218
224
return f"Optional[List[{ self .inner_property .get_type_string ()} ]]"
219
225
@@ -254,7 +260,7 @@ def get_type_string(self, no_optional: bool = False) -> str:
254
260
""" Get a string representation of type that should be used when declaring this property """
255
261
inner_types = [p .get_type_string () for p in self .inner_properties ]
256
262
inner_prop_string = ", " .join (inner_types )
257
- if self .required or no_optional :
263
+ if no_optional or ( self .required and not self . nullable ) :
258
264
return f"Union[{ inner_prop_string } ]"
259
265
return f"Optional[Union[{ inner_prop_string } ]]"
260
266
@@ -321,7 +327,7 @@ def get_enum(name: str) -> Optional[EnumProperty]:
321
327
def get_type_string (self , no_optional : bool = False ) -> str :
322
328
""" Get a string representation of type that should be used when declaring this property """
323
329
324
- if self .required or no_optional :
330
+ if no_optional or ( self .required and not self . nullable ) :
325
331
return self .reference .class_name
326
332
return f"Optional[{ self .reference .class_name } ]"
327
333
@@ -376,7 +382,7 @@ def template(self) -> str: # type: ignore
376
382
377
383
def get_type_string (self , no_optional : bool = False ) -> str :
378
384
""" 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 ) :
380
386
return self .reference .class_name
381
387
return f"Optional[{ self .reference .class_name } ]"
382
388
@@ -438,13 +444,15 @@ def _string_based_property(
438
444
""" Construct a Property from the type "string" """
439
445
string_format = data .schema_format
440
446
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 , )
442
448
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 , )
444
450
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 , )
446
452
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
+ )
448
456
449
457
450
458
def _property_from_data (
@@ -453,14 +461,17 @@ def _property_from_data(
453
461
""" Generate a Property from the OpenAPI dictionary representation of it """
454
462
name = utils .remove_string_escapes (name )
455
463
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
+ )
457
467
if data .enum :
458
468
return EnumProperty (
459
469
name = name ,
460
470
required = required ,
461
471
values = EnumProperty .values_from_list (data .enum ),
462
472
title = data .title or name ,
463
473
default = data .default ,
474
+ nullable = data .nullable ,
464
475
)
465
476
if data .anyOf or data .oneOf :
466
477
sub_properties : List [Property ] = []
@@ -469,26 +480,30 @@ def _property_from_data(
469
480
if isinstance (sub_prop , PropertyError ):
470
481
return PropertyError (detail = f"Invalid property in union { name } " , data = sub_prop_data )
471
482
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
+ )
473
486
if not data .type :
474
487
return PropertyError (data = data , detail = "Schemas must either have one of enum, anyOf, or type defined." )
475
488
if data .type == "string" :
476
489
return _string_based_property (name = name , required = required , data = data )
477
490
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 , )
479
492
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 , )
481
494
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 , )
483
496
elif data .type == "array" :
484
497
if data .items is None :
485
498
return PropertyError (data = data , detail = "type array must have items defined" )
486
499
inner_prop = property_from_data (name = f"{ name } _item" , required = True , data = data .items )
487
500
if isinstance (inner_prop , PropertyError ):
488
501
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
+ )
490
505
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 , )
492
507
return PropertyError (data = data , detail = f"unknown type { data .type } " )
493
508
494
509
0 commit comments