Skip to content

Commit 7ea91b6

Browse files
author
Constantinos Symeonides
committed
fix: Get enum default from parent schema
1 parent 81cb7c2 commit 7ea91b6

File tree

2 files changed

+117
-27
lines changed

2 files changed

+117
-27
lines changed

Diff for: openapi_python_client/parser/properties/__init__.py

+38-27
Original file line numberDiff line numberDiff line change
@@ -305,32 +305,38 @@ def build_enum_property(
305305
else:
306306
return PropertyError(data=data, detail="No values provided for Enum"), schemas
307307

308-
default = None
309-
if data.default is not None:
310-
inverse_values = {v: k for k, v in values.items()}
311-
try:
312-
default = f"{reference.class_name}.{inverse_values[data.default]}"
313-
except KeyError:
314-
return (
315-
PropertyError(
316-
detail=f"{data.default} is an invalid default for enum {reference.class_name}", data=data
317-
),
318-
schemas,
319-
)
320-
321308
prop = EnumProperty(
322309
name=name,
323310
required=required,
324-
default=default,
325311
nullable=data.nullable,
326312
reference=reference,
327313
values=values,
328314
value_type=value_type,
315+
default=None,
329316
)
317+
318+
default = get_enum_default(prop, data)
319+
if isinstance(default, PropertyError):
320+
return default, schemas
321+
prop = attr.evolve(prop, default=default)
322+
330323
schemas = attr.evolve(schemas, enums={**schemas.enums, prop.reference.class_name: prop})
331324
return prop, schemas
332325

333326

327+
def get_enum_default(prop: EnumProperty, data: oai.Schema) -> Union[Optional[Any], PropertyError]:
328+
if data.default is None:
329+
return None
330+
331+
inverse_values = {v: k for k, v in prop.values.items()}
332+
try:
333+
return f"{prop.reference.class_name}.{inverse_values[data.default]}"
334+
except KeyError:
335+
return PropertyError(
336+
detail=f"{data.default} is an invalid default for enum {prop.reference.class_name}", data=data
337+
)
338+
339+
334340
def build_union_property(
335341
*, data: oai.Schema, name: str, required: bool, schemas: Schemas, parent_name: str
336342
) -> Tuple[Union[UnionProperty, PropertyError], Schemas]:
@@ -381,18 +387,25 @@ def build_list_property(
381387
def _property_from_ref(
382388
name: str,
383389
required: bool,
384-
nullable: bool,
390+
parent: Union[oai.Schema, None],
385391
data: oai.Reference,
386392
schemas: Schemas,
387393
) -> Tuple[Union[Property, PropertyError], Schemas]:
388394
reference = Reference.from_ref(data.ref)
389395
existing = schemas.enums.get(reference.class_name) or schemas.models.get(reference.class_name)
390-
if existing:
391-
return (
392-
attr.evolve(existing, required=required, name=name, nullable=nullable),
393-
schemas,
394-
)
395-
return PropertyError(data=data, detail="Could not find reference in parsed models or enums"), schemas
396+
if not existing:
397+
return PropertyError(data=data, detail="Could not find reference in parsed models or enums"), schemas
398+
399+
prop = attr.evolve(existing, required=required, name=name)
400+
if parent:
401+
prop = attr.evolve(prop, nullable=parent.nullable)
402+
if isinstance(prop, EnumProperty):
403+
default = get_enum_default(prop, parent)
404+
if isinstance(default, PropertyError):
405+
return default, schemas
406+
prop = attr.evolve(prop, default=default)
407+
408+
return prop, schemas
396409

397410

398411
def _property_from_data(
@@ -405,21 +418,19 @@ def _property_from_data(
405418
""" Generate a Property from the OpenAPI dictionary representation of it """
406419
name = utils.remove_string_escapes(name)
407420
if isinstance(data, oai.Reference):
408-
return _property_from_ref(name=name, required=required, nullable=False, data=data, schemas=schemas)
421+
return _property_from_ref(name=name, required=required, parent=None, data=data, schemas=schemas)
409422

410423
sub_data = (data.allOf or []) + data.anyOf + data.oneOf
411424
if len(sub_data) == 1 and isinstance(sub_data[0], oai.Reference):
412-
return _property_from_ref(
413-
name=name, required=required, nullable=data.nullable, data=sub_data[0], schemas=schemas
414-
)
425+
return _property_from_ref(name=name, required=required, parent=data, data=sub_data[0], schemas=schemas)
415426

416427
if data.enum:
417428
return build_enum_property(
418429
data=data, name=name, required=required, schemas=schemas, enum=data.enum, parent_name=parent_name
419430
)
420-
if data.anyOf or data.oneOf:
431+
elif data.anyOf or data.oneOf:
421432
return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name)
422-
if data.type == "string":
433+
elif data.type == "string":
423434
return _string_based_property(name=name, required=required, data=data), schemas
424435
elif data.type == "number":
425436
return (

Diff for: tests/test_parser/test_properties/test_init.py

+79
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,85 @@ def test_property_from_data_ref_enum(self):
624624
)
625625
assert schemas == new_schemas
626626

627+
def test_property_from_data_ref_enum_with_overridden_default(self):
628+
from openapi_python_client.parser.properties import EnumProperty, Reference, Schemas, property_from_data
629+
630+
name = "some_enum"
631+
data = oai.Schema.construct(default="b", allOf=[oai.Reference.construct(ref="MyEnum")])
632+
existing_enum = EnumProperty(
633+
name="an_enum",
634+
required=True,
635+
nullable=False,
636+
default="MyEnum.A",
637+
values={"A": "a", "B": "b"},
638+
value_type=str,
639+
reference=Reference(class_name="MyEnum", module_name="my_enum"),
640+
)
641+
schemas = Schemas(enums={"MyEnum": existing_enum})
642+
643+
prop, new_schemas = property_from_data(name=name, required=False, data=data, schemas=schemas, parent_name="")
644+
645+
assert prop == EnumProperty(
646+
name="some_enum",
647+
required=False,
648+
nullable=False,
649+
default="MyEnum.B",
650+
values={"A": "a", "B": "b"},
651+
value_type=str,
652+
reference=Reference(class_name="MyEnum", module_name="my_enum"),
653+
)
654+
assert schemas == new_schemas
655+
656+
def test_property_from_data_ref_enum_with_overridden_default(self):
657+
from openapi_python_client.parser.properties import EnumProperty, Reference, Schemas, property_from_data
658+
659+
name = "some_enum"
660+
data = oai.Schema.construct(default="b", allOf=[oai.Reference.construct(ref="MyEnum")])
661+
existing_enum = EnumProperty(
662+
name="an_enum",
663+
required=True,
664+
nullable=False,
665+
default="MyEnum.A",
666+
values={"A": "a", "B": "b"},
667+
value_type=str,
668+
reference=Reference(class_name="MyEnum", module_name="my_enum"),
669+
)
670+
schemas = Schemas(enums={"MyEnum": existing_enum})
671+
672+
prop, new_schemas = property_from_data(name=name, required=False, data=data, schemas=schemas, parent_name="")
673+
674+
assert prop == EnumProperty(
675+
name="some_enum",
676+
required=False,
677+
nullable=False,
678+
default="MyEnum.B",
679+
values={"A": "a", "B": "b"},
680+
value_type=str,
681+
reference=Reference(class_name="MyEnum", module_name="my_enum"),
682+
)
683+
assert schemas == new_schemas
684+
685+
def test_property_from_data_ref_enum_with_invalid_default(self):
686+
from openapi_python_client.parser.properties import EnumProperty, Reference, Schemas, property_from_data
687+
688+
name = "some_enum"
689+
data = oai.Schema.construct(default="x", allOf=[oai.Reference.construct(ref="MyEnum")])
690+
existing_enum = EnumProperty(
691+
name="an_enum",
692+
required=True,
693+
nullable=False,
694+
default="MyEnum.A",
695+
values={"A": "a", "B": "b"},
696+
value_type=str,
697+
reference=Reference(class_name="MyEnum", module_name="my_enum"),
698+
)
699+
schemas = Schemas(enums={"MyEnum": existing_enum})
700+
701+
prop, new_schemas = property_from_data(name=name, required=False, data=data, schemas=schemas, parent_name="")
702+
703+
assert schemas == new_schemas
704+
assert prop == PropertyError(data=data, detail="x is an invalid default for enum MyEnum")
705+
627706
def test_property_from_data_ref_model(self):
628707
from openapi_python_client.parser.properties import ModelProperty, Reference, Schemas, property_from_data
629708

0 commit comments

Comments
 (0)