diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index cfb585380..9a7ce2c11 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -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__() @@ -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 @@ -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 + 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 ( @@ -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,