Skip to content

Commit dcf5733

Browse files
author
Constantinos Symeonides
committed
fix: Get enum default from parent schema
1 parent 6e72d49 commit dcf5733

File tree

2 files changed

+90
-25
lines changed

2 files changed

+90
-25
lines changed

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

+36-25
Original file line numberDiff line numberDiff line change
@@ -318,30 +318,36 @@ def build_enum_property(
318318
else:
319319
return PropertyError(data=data, detail="No values provided for Enum"), schemas
320320

321-
default = None
322-
if data.default is not None:
323-
inverse_values = {v: k for k, v in values.items()}
324-
try:
325-
default = f"{class_info.name}.{inverse_values[data.default]}"
326-
except KeyError:
327-
return (
328-
PropertyError(detail=f"{data.default} is an invalid default for enum {class_info.name}", data=data),
329-
schemas,
330-
)
331-
332321
prop = EnumProperty(
333322
name=name,
334323
required=required,
335-
default=default,
336324
nullable=data.nullable,
337325
class_info=class_info,
338326
values=values,
339327
value_type=value_type,
328+
default=None,
340329
)
330+
331+
default = get_enum_default(prop, data)
332+
if isinstance(default, PropertyError):
333+
return default, schemas
334+
prop = attr.evolve(prop, default=default)
335+
341336
schemas = attr.evolve(schemas, classes_by_name={**schemas.classes_by_name, class_info.name: prop})
342337
return prop, schemas
343338

344339

340+
def get_enum_default(prop: EnumProperty, data: oai.Schema) -> Union[Optional[Any], PropertyError]:
341+
if data.default is None:
342+
return None
343+
344+
inverse_values = {v: k for k, v in prop.values.items()}
345+
try:
346+
return f"{prop.class_info.name}.{inverse_values[data.default]}"
347+
except KeyError:
348+
return PropertyError(detail=f"{data.default} is an invalid default for enum {prop.class_info.name}", data=data)
349+
350+
345351
def build_union_property(
346352
*, data: oai.Schema, name: str, required: bool, schemas: Schemas, parent_name: str, config: Config
347353
) -> Tuple[Union[UnionProperty, PropertyError], Schemas]:
@@ -397,20 +403,27 @@ def build_list_property(
397403
def _property_from_ref(
398404
name: str,
399405
required: bool,
400-
nullable: bool,
406+
parent: Union[oai.Schema, None],
401407
data: oai.Reference,
402408
schemas: Schemas,
403409
) -> Tuple[Union[Property, PropertyError], Schemas]:
404410
ref_path = parse_reference_path(data.ref)
405411
if isinstance(ref_path, ParseError):
406412
return PropertyError(data=data, detail=ref_path.detail), schemas
407413
existing = schemas.classes_by_reference.get(ref_path)
408-
if existing:
409-
return (
410-
attr.evolve(existing, required=required, name=name, nullable=nullable),
411-
schemas,
412-
)
413-
return PropertyError(data=data, detail="Could not find reference in parsed models or enums"), schemas
414+
if not existing:
415+
return PropertyError(data=data, detail="Could not find reference in parsed models or enums"), schemas
416+
417+
prop = attr.evolve(existing, required=required, name=name)
418+
if parent:
419+
prop = attr.evolve(prop, nullable=parent.nullable)
420+
if isinstance(prop, EnumProperty):
421+
default = get_enum_default(prop, parent)
422+
if isinstance(default, PropertyError):
423+
return default, schemas
424+
prop = attr.evolve(prop, default=default)
425+
426+
return prop, schemas
414427

415428

416429
def _property_from_data(
@@ -424,14 +437,12 @@ def _property_from_data(
424437
""" Generate a Property from the OpenAPI dictionary representation of it """
425438
name = utils.remove_string_escapes(name)
426439
if isinstance(data, oai.Reference):
427-
return _property_from_ref(name=name, required=required, nullable=False, data=data, schemas=schemas)
440+
return _property_from_ref(name=name, required=required, parent=None, data=data, schemas=schemas)
428441

429442
# A union of a single reference should just be passed through to that reference (don't create copy class)
430443
sub_data = (data.allOf or []) + data.anyOf + data.oneOf
431444
if len(sub_data) == 1 and isinstance(sub_data[0], oai.Reference):
432-
return _property_from_ref(
433-
name=name, required=required, nullable=data.nullable, data=sub_data[0], schemas=schemas
434-
)
445+
return _property_from_ref(name=name, required=required, parent=data, data=sub_data[0], schemas=schemas)
435446

436447
if data.enum:
437448
return build_enum_property(
@@ -443,11 +454,11 @@ def _property_from_data(
443454
parent_name=parent_name,
444455
config=config,
445456
)
446-
if data.anyOf or data.oneOf:
457+
elif data.anyOf or data.oneOf:
447458
return build_union_property(
448459
data=data, name=name, required=required, schemas=schemas, parent_name=parent_name, config=config
449460
)
450-
if data.type == "string":
461+
elif data.type == "string":
451462
return _string_based_property(name=name, required=required, data=data), schemas
452463
elif data.type == "number":
453464
return (

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

+54
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,60 @@ def test_property_from_data_ref_enum(self):
555555
)
556556
assert schemas == new_schemas
557557

558+
def test_property_from_data_ref_enum_with_overridden_default(self):
559+
from openapi_python_client.parser.properties import Class, EnumProperty, Schemas, property_from_data
560+
561+
name = "some_enum"
562+
data = oai.Schema.construct(default="b", allOf=[oai.Reference.construct(ref="#/components/schemas/MyEnum")])
563+
existing_enum = EnumProperty(
564+
name="an_enum",
565+
required=True,
566+
nullable=False,
567+
default="MyEnum.A",
568+
values={"A": "a", "B": "b"},
569+
value_type=str,
570+
class_info=Class(name="MyEnum", module_name="my_enum"),
571+
)
572+
schemas = Schemas(classes_by_reference={"/components/schemas/MyEnum": existing_enum})
573+
574+
prop, new_schemas = property_from_data(
575+
name=name, required=False, data=data, schemas=schemas, parent_name="", config=Config()
576+
)
577+
578+
assert prop == EnumProperty(
579+
name="some_enum",
580+
required=False,
581+
nullable=False,
582+
default="MyEnum.B",
583+
values={"A": "a", "B": "b"},
584+
value_type=str,
585+
class_info=Class(name="MyEnum", module_name="my_enum"),
586+
)
587+
assert schemas == new_schemas
588+
589+
def test_property_from_data_ref_enum_with_invalid_default(self):
590+
from openapi_python_client.parser.properties import Class, EnumProperty, Schemas, property_from_data
591+
592+
name = "some_enum"
593+
data = oai.Schema.construct(default="x", allOf=[oai.Reference.construct(ref="#/components/schemas/MyEnum")])
594+
existing_enum = EnumProperty(
595+
name="an_enum",
596+
required=True,
597+
nullable=False,
598+
default="MyEnum.A",
599+
values={"A": "a", "B": "b"},
600+
value_type=str,
601+
class_info=Class(name="MyEnum", module_name="my_enum"),
602+
)
603+
schemas = Schemas(classes_by_reference={"/components/schemas/MyEnum": existing_enum})
604+
605+
prop, new_schemas = property_from_data(
606+
name=name, required=False, data=data, schemas=schemas, parent_name="", config=Config()
607+
)
608+
609+
assert schemas == new_schemas
610+
assert prop == PropertyError(data=data, detail="x is an invalid default for enum MyEnum")
611+
558612
def test_property_from_data_ref_model(self):
559613
from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data
560614

0 commit comments

Comments
 (0)