@@ -27,6 +27,7 @@ class Property:
27
27
28
28
name : str
29
29
required : bool
30
+ nullable : bool
30
31
default : Optional [Any ]
31
32
32
33
template : ClassVar [Optional [str ]] = None
@@ -44,8 +45,13 @@ def _validate_default(self, default: Any) -> Any:
44
45
raise ValidationError
45
46
46
47
def get_type_string (self , no_optional : bool = False ) -> str :
47
- """ Get a string representation of type that should be used when declaring this property """
48
- if self .required or no_optional :
48
+ """
49
+ Get a string representation of type that should be used when declaring this property
50
+
51
+ Args:
52
+ no_optional: Do not include Optional even if the value is optional (needed for isinstance checks)
53
+ """
54
+ if no_optional or (self .required and not self .nullable ):
49
55
return self ._type_string
50
56
return f"Optional[{ self ._type_string } ]"
51
57
@@ -212,7 +218,7 @@ class ListProperty(Property, Generic[InnerProp]):
212
218
213
219
def get_type_string (self , no_optional : bool = False ) -> str :
214
220
""" Get a string representation of type that should be used when declaring this property """
215
- if self .required or no_optional :
221
+ if no_optional or ( self .required and not self . nullable ) :
216
222
return f"List[{ self .inner_property .get_type_string ()} ]"
217
223
return f"Optional[List[{ self .inner_property .get_type_string ()} ]]"
218
224
@@ -253,7 +259,7 @@ def get_type_string(self, no_optional: bool = False) -> str:
253
259
""" Get a string representation of type that should be used when declaring this property """
254
260
inner_types = [p .get_type_string () for p in self .inner_properties ]
255
261
inner_prop_string = ", " .join (inner_types )
256
- if self .required or no_optional :
262
+ if no_optional or ( self .required and not self . nullable ) :
257
263
return f"Union[{ inner_prop_string } ]"
258
264
return f"Optional[Union[{ inner_prop_string } ]]"
259
265
@@ -320,7 +326,7 @@ def get_enum(name: str) -> Optional[EnumProperty]:
320
326
def get_type_string (self , no_optional : bool = False ) -> str :
321
327
""" Get a string representation of type that should be used when declaring this property """
322
328
323
- if self .required or no_optional :
329
+ if no_optional or ( self .required and not self . nullable ) :
324
330
return self .reference .class_name
325
331
return f"Optional[{ self .reference .class_name } ]"
326
332
@@ -375,7 +381,7 @@ def template(self) -> str: # type: ignore
375
381
376
382
def get_type_string (self , no_optional : bool = False ) -> str :
377
383
""" Get a string representation of type that should be used when declaring this property """
378
- if self .required or no_optional :
384
+ if no_optional or ( self .required and not self . nullable ) :
379
385
return self .reference .class_name
380
386
return f"Optional[{ self .reference .class_name } ]"
381
387
@@ -437,13 +443,15 @@ def _string_based_property(
437
443
""" Construct a Property from the type "string" """
438
444
string_format = data .schema_format
439
445
if string_format == "date-time" :
440
- return DateTimeProperty (name = name , required = required , default = data .default )
446
+ return DateTimeProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
441
447
elif string_format == "date" :
442
- return DateProperty (name = name , required = required , default = data .default )
448
+ return DateProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
443
449
elif string_format == "binary" :
444
- return FileProperty (name = name , required = required , default = data .default )
450
+ return FileProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
445
451
else :
446
- return StringProperty (name = name , default = data .default , required = required , pattern = data .pattern )
452
+ return StringProperty (
453
+ name = name , default = data .default , required = required , pattern = data .pattern , nullable = data .nullable ,
454
+ )
447
455
448
456
449
457
def _property_from_data (
@@ -452,14 +460,17 @@ def _property_from_data(
452
460
""" Generate a Property from the OpenAPI dictionary representation of it """
453
461
name = utils .remove_string_escapes (name )
454
462
if isinstance (data , oai .Reference ):
455
- return RefProperty (name = name , required = required , reference = Reference .from_ref (data .ref ), default = None )
463
+ return RefProperty (
464
+ name = name , required = required , reference = Reference .from_ref (data .ref ), default = None , nullable = False ,
465
+ )
456
466
if data .enum :
457
467
return EnumProperty (
458
468
name = name ,
459
469
required = required ,
460
470
values = EnumProperty .values_from_list (data .enum ),
461
471
title = data .title or name ,
462
472
default = data .default ,
473
+ nullable = data .nullable ,
463
474
)
464
475
if data .anyOf :
465
476
sub_properties : List [Property ] = []
@@ -468,26 +479,30 @@ def _property_from_data(
468
479
if isinstance (sub_prop , PropertyError ):
469
480
return PropertyError (detail = f"Invalid property in union { name } " , data = sub_prop_data )
470
481
sub_properties .append (sub_prop )
471
- return UnionProperty (name = name , required = required , default = data .default , inner_properties = sub_properties )
482
+ return UnionProperty (
483
+ name = name , required = required , default = data .default , inner_properties = sub_properties , nullable = data .nullable ,
484
+ )
472
485
if not data .type :
473
486
return PropertyError (data = data , detail = "Schemas must either have one of enum, anyOf, or type defined." )
474
487
if data .type == "string" :
475
488
return _string_based_property (name = name , required = required , data = data )
476
489
elif data .type == "number" :
477
- return FloatProperty (name = name , default = data .default , required = required )
490
+ return FloatProperty (name = name , default = data .default , required = required , nullable = data . nullable , )
478
491
elif data .type == "integer" :
479
- return IntProperty (name = name , default = data .default , required = required )
492
+ return IntProperty (name = name , default = data .default , required = required , nullable = data . nullable , )
480
493
elif data .type == "boolean" :
481
- return BooleanProperty (name = name , required = required , default = data .default )
494
+ return BooleanProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
482
495
elif data .type == "array" :
483
496
if data .items is None :
484
497
return PropertyError (data = data , detail = "type array must have items defined" )
485
498
inner_prop = property_from_data (name = f"{ name } _item" , required = True , data = data .items )
486
499
if isinstance (inner_prop , PropertyError ):
487
500
return PropertyError (data = inner_prop .data , detail = f"invalid data in items of array { name } " )
488
- return ListProperty (name = name , required = required , default = data .default , inner_property = inner_prop ,)
501
+ return ListProperty (
502
+ name = name , required = required , default = data .default , inner_property = inner_prop , nullable = data .nullable ,
503
+ )
489
504
elif data .type == "object" :
490
- return DictProperty (name = name , required = required , default = data .default )
505
+ return DictProperty (name = name , required = required , default = data .default , nullable = data . nullable , )
491
506
return PropertyError (data = data , detail = f"unknown type { data .type } " )
492
507
493
508
0 commit comments