Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

[BUG][python] Missing quotes for array property in TypedDict definition #412

Closed
5 tasks done
Marcelo00 opened this issue Apr 5, 2024 · 2 comments · Fixed by #413
Closed
5 tasks done

[BUG][python] Missing quotes for array property in TypedDict definition #412

Marcelo00 opened this issue Apr 5, 2024 · 2 comments · Fixed by #413
Labels
bug Something isn't working

Comments

@Marcelo00
Copy link

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [] [Optional] Sponsorship to speed up the bug fix or feature request
Description

The transformed name in a TypedDict definition of a property misses quotes.

See the following schema:

# coding: utf-8

"""
    the test title
    The test REST API  # noqa: E501
    The version of the OpenAPI document: 1
    Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""

from __future__ import annotations
from openapi_client.shared_imports.schema_imports import *  # pyright: ignore [reportWildcardImportFromLibrary]

AdditionalProperties: typing_extensions.TypeAlias = schemas.NotAnyTypeSchema


@dataclasses.dataclass(frozen=True)
class Property1(
    schemas.StrSchema
):
    types: typing.FrozenSet[typing.Type] = frozenset({
        str,
    })
    min_length: int = 1


@dataclasses.dataclass(frozen=True)
class Property2(
    schemas.StrSchema
):
    types: typing.FrozenSet[typing.Type] = frozenset({
        str,
    })
    min_length: int = 1


@dataclasses.dataclass(frozen=True)
class Name(
    schemas.StrSchema
):
    types: typing.FrozenSet[typing.Type] = frozenset({
        str,
    })
    min_length: int = 1
MultiPropertyTypeRequiredDictInput = typing.TypedDict(
    'MultiPropertyTypeRequiredDictInput',
    {
        "name": str,
    }
)
MultiPropertyTypeOptionalDictInput = typing.TypedDict(
    'MultiPropertyTypeOptionalDictInput',
    {
        "property1": str,
        "property2": str,
        ArrayProperty: typing.Union[
            None,
            typing.Union[
                ArrayPropertyTupleInput,
                ArrayPropertyTuple
            ],
        ],
    },
    total=False
)


class MultiPropertyTypeDict(schemas.immutabledict[str, typing.Union[
    str,
    None,
    typing.Tuple[schemas.OUTPUT_BASE_TYPES],
]]):

    __required_keys__: typing.FrozenSet[str] = frozenset({
        "name",
    })
    __optional_keys__: typing.FrozenSet[str] = frozenset({
        "property1",
        "property2",
        "ArrayProperty",
    })
    
    def __new__(
        cls,
        *,
        name: str,
        property1: typing.Union[
            str,
            schemas.Unset
        ] = schemas.unset,
        property2: typing.Union[
            str,
            schemas.Unset
        ] = schemas.unset,
        ArrayProperty: typing.Union[
            None,
            typing.Union[
                ArrayPropertyTupleInput,
                ArrayPropertyTuple
            ],
            schemas.Unset
        ] = schemas.unset,
        configuration_: typing.Optional[schema_configuration.SchemaConfiguration] = None,
    ):
        arg_: typing.Dict[str, typing.Any] = {
            "name": name,
        }
        for key_, val in (
            ("property1", property1),
            ("property2", property2),
            ("ArrayProperty", ArrayProperty),
        ):
            if isinstance(val, schemas.Unset):
                continue
            arg_[key_] = val
        used_arg_ = typing.cast(MultiPropertyTypeDictInput, arg_)
        return MultiPropertyType.validate(used_arg_, configuration=configuration_)
    
    @staticmethod
    def from_dict_(
        arg: typing.Union[
            MultiPropertyTypeDictInput,
            MultiPropertyTypeDict
        ],
        configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
    ) -> MultiPropertyTypeDict:
        return MultiPropertyType.validate(arg, configuration=configuration)
    
    @property
    def name(self) -> str:
        return typing.cast(
            str,
            self.__getitem__("name")
        )
    
    @property
    def property1(self) -> typing.Union[str, schemas.Unset]:
        val = self.get("property1", schemas.unset)
        if isinstance(val, schemas.Unset):
            return val
        return typing.cast(
            str,
            val
        )
    
    @property
    def property2(self) -> typing.Union[str, schemas.Unset]:
        val = self.get("property2", schemas.unset)
        if isinstance(val, schemas.Unset):
            return val
        return typing.cast(
            str,
            val
        )
    
    @property
    def ArrayProperty(self) -> typing.Union[
        typing.Union[None, schemas.Unset],
        typing.Union[ArrayPropertyTuple, schemas.Unset],
    ]:
        val = self.get("ArrayProperty", schemas.unset)
        if isinstance(val, schemas.Unset):
            return val
        return typing.cast(
            typing.Union[
                None,
                ArrayPropertyTuple,
            ],
            val
        )


class MultiPropertyTypeDictInput(MultiPropertyTypeRequiredDictInput, MultiPropertyTypeOptionalDictInput):
    pass

from openapi_client.components.schema import enum_type


class ArrayPropertyTuple(
    typing.Tuple[
        typing.Literal["Enum1", "Enum2"],
        ...
    ]
):

    def __new__(cls, arg: typing.Union[ArrayPropertyTupleInput, ArrayPropertyTuple], configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None):
        return ArrayProperty.validate(arg, configuration=configuration)
ArrayPropertyTupleInput = typing.Union[
    typing.List[
        typing.Literal[
            "Enum1",
            "Enum2"
        ],
    ],
    typing.Tuple[
        typing.Literal[
            "Enum1",
            "Enum2"
        ],
        ...
    ]
]


@dataclasses.dataclass(frozen=True)
class ArrayProperty(
    schemas.Schema[schemas.immutabledict[str, schemas.OUTPUT_BASE_TYPES], ArrayPropertyTuple],
):
    types: typing.FrozenSet[typing.Type] = frozenset({
        type(None),
        tuple,
    })
    items: typing.Type[enum_type.EnumType] = dataclasses.field(default_factory=lambda: enum_type.EnumType) # type: ignore
    type_to_output_cls: typing.Mapping[
        typing.Type,
        typing.Type
    ] = dataclasses.field(
        default_factory=lambda: {
            tuple: ArrayPropertyTuple,
        }
    )

    @typing.overload
    @classmethod
    def validate(
        cls,
        arg: None,
        configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
    ) -> None: ...
    @typing.overload
    @classmethod
    def validate(
        cls,
        arg: typing.Union[
            ArrayPropertyTupleInput,
            ArrayPropertyTuple,
        ],
        configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
    ) -> ArrayPropertyTuple: ...
    @classmethod
    def validate(
        cls,
        arg,
        configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
    ):
        return super().validate_base(
            arg,
            configuration=configuration,
        )

Properties = typing.TypedDict(
    'Properties',
    {
        "property1": typing.Type[Property1],
        "property2": typing.Type[Property2],
        "ArrayProperty": typing.Type[ArrayProperty],
        "name": typing.Type[Name],
    }
)


@dataclasses.dataclass(frozen=True)
class MultiPropertyType(
    schemas.Schema[MultiPropertyTypeDict, tuple]
):
    """NOTE: This class is auto generated by OpenAPI JSON Schema Generator.
    Ref: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator

    Do not edit the class manually.
    """
    types: typing.FrozenSet[typing.Type] = frozenset({schemas.immutabledict})
    required: typing.FrozenSet[str] = frozenset({
        "name",
    })
    properties: Properties = dataclasses.field(default_factory=lambda: schemas.typed_dict_to_instance(Properties)) # type: ignore
    additional_properties: typing.Type[AdditionalProperties] = dataclasses.field(default_factory=lambda: AdditionalProperties) # type: ignore
    type_to_output_cls: typing.Mapping[
        typing.Type,
        typing.Type
    ] = dataclasses.field(
        default_factory=lambda: {
            schemas.immutabledict: MultiPropertyTypeDict
        }
    )

    @classmethod
    def validate(
        cls,
        arg: typing.Union[
            MultiPropertyTypeDictInput,
            MultiPropertyTypeDict,
        ],
        configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
    ) -> MultiPropertyTypeDict:
        return super().validate_base(
            arg,
            configuration=configuration,
        )

In this schema you have following TypedDict definition

MultiPropertyTypeOptionalDictInput = typing.TypedDict(
    'MultiPropertyTypeOptionalDictInput',
    {
        "property1": str,
        "property2": str,
        ArrayProperty: typing.Union[
            None,
            typing.Union[
                ArrayPropertyTupleInput,
                ArrayPropertyTuple
            ],
        ],
    },
    total=False
)

where the property ArrayProperty miss the quotes. Consequently, running the created code will lead to a NameError on runtime.

openapi-json-schema-generator version

Version 4.1.1

OpenAPI declaration file content or url
openapi: 3.0.0
components:
    examples: {}
    headers: {}
    parameters: {}
    requestBodies: {}
    responses: {}
    schemas:
        EnumType:
            enum:
                - Enum1
                - Enum2
            type: string
        MultiPropertyType:
            properties:
                property1:
                    type: string
                    minLength: 1
                property2:
                    type: string
                    minLength: 1
                ArrayProperty:
                    items:
                        $ref: '#/components/schemas/EnumType'
                    type: array
                    nullable: true
                name:
                    type: string
                    minLength: 1
            required:
                - name
            type: object
            additionalProperties: false
info:
    title: the test title
    version: '1'
    description: 'The test REST API'
    contact: {}
paths:
    '/example/get':
        get:
            operationId: GetExample
            responses:
                '200':
                    description: Ok
Generation Details
Steps to reproduce
Related issues/PRs
Suggest a fix
@spacether
Copy link
Contributor

Thank you for reporting this. I will release a fix for this bug today

@spacether
Copy link
Contributor

@spacether spacether added the bug Something isn't working label Jun 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
2 participants