Skip to content
20 changes: 20 additions & 0 deletions openapi_python_client/parser/properties/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ class UnionProperty(Property):
inner_properties: List[Property]
template: ClassVar[str] = "union_property.pyi"
has_properties_without_templates: bool = attr.ib(init=False)
discriminator_property: Optional[str]
discriminator_mappings: Dict[str, Property]

def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
Expand All @@ -171,6 +173,8 @@ def __attrs_post_init__(self) -> None:

def _get_inner_type_strings(self, json: bool = False) -> List[str]:
inner_types = [p.get_type_string(no_optional=True, json=json) for p in self.inner_properties]
if not json:
inner_types.append("UnknownType")
unique_inner_types = list(dict.fromkeys(inner_types))
return unique_inner_types

Expand Down Expand Up @@ -428,13 +432,27 @@ def build_union_property(
*, data: oai.Schema, name: str, required: bool, schemas: Schemas, parent_name: str
) -> Tuple[Union[UnionProperty, PropertyError], Schemas]:
sub_properties: List[Property] = []
inverted_mappings = {}
for k, v in (data.discriminator.mapping if data.discriminator else {}).items():
class_name = Reference.from_ref(v).class_name
if class_name in inverted_mappings:
raise ArgumentError(
f"Mapping more than one name to a class is currently not supported (class: {class_name})."
)
inverted_mappings[Reference.from_ref(v).class_name] = k
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AD: Check for existence, error if so, but we might want to support that case in the future (several mapped names can reference the same type, e.g. for deprecation purposes)

discriminator_mappings: Dict[str, Property] = {}
for sub_prop_data in chain(data.anyOf, data.oneOf):
sub_prop, schemas = property_from_data(
name=name, required=required, data=sub_prop_data, schemas=schemas, parent_name=parent_name
)
if isinstance(sub_prop, PropertyError):
return PropertyError(detail=f"Invalid property in union {name}", data=sub_prop_data), schemas

sub_properties.append(sub_prop)
if data.discriminator is not None:
discriminated_by = inverted_mappings.get(sub_prop.reference.class_name)
if discriminated_by is not None:
discriminator_mappings[discriminated_by] = sub_prop

default = convert_chain((prop._type_string for prop in sub_properties), data.default)
return (
Expand All @@ -444,6 +462,8 @@ def build_union_property(
default=default,
inner_properties=sub_properties,
nullable=data.nullable,
discriminator_property=data.discriminator.propertyName if data.discriminator else None,
discriminator_mappings=discriminator_mappings,
description=data.description,
),
schemas,
Expand Down