From 7ea8421a6dc08a90d416a816e73c138c5931106b Mon Sep 17 00:00:00 2001 From: Packy Gallagher Date: Tue, 8 Dec 2020 15:47:17 -0800 Subject: [PATCH 01/18] feat: Add allOf support for model definitions BNCH-18722 (#12) Collapses the child elements into one, without class heirarchy, mixins, etc This is a replaying of 2670d11 (first implementation) and 9f5b95a (a bugfix) onto the new `main-v.0.7.0`, modified for the refactored upstream. This should bring `main-v.0.7.1` up to par with `main` for the features we implemented in our fork (dropping our `Unset` implementation for theirs) --- .../parser/properties/__init__.py | 28 +++++++- .../parser/properties/model_property.py | 55 +++++++++++++++- .../test_parser/test_properties/test_init.py | 23 +++++-- .../test_properties/test_model_property.py | 66 +++++++++++++++++++ 4 files changed, 163 insertions(+), 9 deletions(-) diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index 427276692..487f5b464 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -250,14 +250,27 @@ def build_model_property( required_properties: List[Property] = [] optional_properties: List[Property] = [] relative_imports: Set[str] = set() + references: List[oai.Reference] = [] class_name = data.title or name if parent_name: class_name = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_name)}" ref = Reference.from_ref(class_name) - for key, value in (data.properties or {}).items(): + all_props = data.properties or {} + if not isinstance(data, oai.Reference) and data.allOf: + for sub_prop in data.allOf: + if isinstance(sub_prop, oai.Reference): + references += [sub_prop] + else: + all_props.update(sub_prop.properties or {}) + required_set.update(sub_prop.required or []) + + for key, value in all_props.items(): prop_required = key in required_set + if not isinstance(value, oai.Reference) and value.allOf: + # resolved later + continue prop, schemas = property_from_data( name=key, required=prop_required, data=value, schemas=schemas, parent_name=class_name ) @@ -292,6 +305,7 @@ def build_model_property( prop = ModelProperty( reference=ref, + references=references, required_properties=required_properties, optional_properties=optional_properties, relative_imports=relative_imports, @@ -544,6 +558,16 @@ def build_schemas(*, components: Dict[str, Union[oai.Reference, oai.Schema]]) -> schemas = schemas_or_err processing = True # We made some progress this round, do another after it's done to_process = next_round - schemas.errors.extend(errors) + resolve_errors: List[PropertyError] = [] + models = list(schemas.models.values()) + for model in models: + schemas_or_err = model.resolve_references(components=components, schemas=schemas) + if isinstance(schemas_or_err, PropertyError): + resolve_errors.append(schemas_or_err) + else: + schemas = schemas_or_err + + schemas.errors.extend(errors) + schemas.errors.extend(resolve_errors) return schemas diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 084017a41..40d1f930b 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -1,17 +1,25 @@ -from typing import ClassVar, List, Set, Union +from __future__ import annotations + +from collections.abc import Iterable +from typing import TYPE_CHECKING, ClassVar, Dict, List, Set, Union import attr +from ... import schema as oai +from ..errors import PropertyError from ..reference import Reference from .property import Property +if TYPE_CHECKING: + from .schemas import Schemas + @attr.s(auto_attribs=True, frozen=True) class ModelProperty(Property): """ A property which refers to another Schema """ reference: Reference - + references: List[oai.Reference] required_properties: List[Property] optional_properties: List[Property] description: str @@ -20,6 +28,49 @@ class ModelProperty(Property): template: ClassVar[str] = "model_property.pyi" + def resolve_references( + self, components: Dict[str, Union[oai.Reference, oai.Schema]], schemas: Schemas + ) -> Union[Schemas, PropertyError]: + from ..properties import property_from_data + + required_set = set() + props = {} + while self.references: + reference = self.references.pop() + source_name = Reference.from_ref(reference.ref).class_name + referenced_prop = components[source_name] + assert isinstance(referenced_prop, oai.Schema) + for p, val in (referenced_prop.properties or {}).items(): + props[p] = (val, source_name) + for sub_prop in referenced_prop.allOf or []: + if isinstance(sub_prop, oai.Reference): + self.references.append(sub_prop) + else: + for p, val in (sub_prop.properties or {}).items(): + props[p] = (val, source_name) + if isinstance(referenced_prop.required, Iterable): + for sub_prop_name in referenced_prop.required: + required_set.add(sub_prop_name) + + for key, (value, source_name) in (props or {}).items(): + required = key in required_set + prop, schemas = property_from_data( + name=key, required=required, data=value, schemas=schemas, parent_name=source_name + ) + if isinstance(prop, PropertyError): + return prop + if required: + self.required_properties.append(prop) + # Remove the optional version + new_optional_props = [op for op in self.optional_properties if op.name != prop.name] + self.optional_properties.clear() + self.optional_properties.extend(new_optional_props) + elif not any(ep for ep in (self.optional_properties + self.required_properties) if ep.name == prop.name): + self.optional_properties.append(prop) + self.relative_imports.update(prop.get_imports(prefix="..")) + + return schemas + def get_type_string(self, no_optional: bool = False) -> str: """ Get a string representation of type that should be used when declaring this property """ type_string = self.reference.class_name diff --git a/tests/test_parser/test_properties/test_init.py b/tests/test_parser/test_properties/test_init.py index a7ea05881..2f3c13676 100644 --- a/tests/test_parser/test_properties/test_init.py +++ b/tests/test_parser/test_properties/test_init.py @@ -586,6 +586,7 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), + references=[], required_properties=[], optional_properties=[], description="", @@ -602,6 +603,7 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), + references=[], required_properties=[], optional_properties=[], description="", @@ -988,19 +990,25 @@ def test__string_based_property_unsupported_format(self, mocker): def test_build_schemas(mocker): build_model_property = mocker.patch(f"{MODULE_NAME}.build_model_property") in_data = {"1": mocker.MagicMock(enum=None), "2": mocker.MagicMock(enum=None), "3": mocker.MagicMock(enum=None)} + model_1 = mocker.MagicMock() schemas_1 = mocker.MagicMock() model_2 = mocker.MagicMock() schemas_2 = mocker.MagicMock(errors=[]) - error = PropertyError() + schemas_2.models = {"1": model_1, "2": model_2} + error_1 = PropertyError() schemas_3 = mocker.MagicMock() + schemas_4 = mocker.MagicMock(errors=[]) + model_1.resolve_references.return_value = schemas_4 + error_2 = PropertyError() + model_2.resolve_references.return_value = error_2 # This loops through one for each, then again to retry the error build_model_property.side_effect = [ (model_1, schemas_1), (model_2, schemas_2), - (error, schemas_3), - (error, schemas_3), + (error_1, schemas_3), + (error_1, schemas_3), ] from openapi_python_client.parser.properties import Schemas, build_schemas @@ -1016,8 +1024,12 @@ def test_build_schemas(mocker): ] ) # schemas_3 was the last to come back from build_model_property, but it should be ignored because it's an error - assert result == schemas_2 - assert result.errors == [error] + model_1.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_2) + # schemas_4 came from resolving model_1 + model_2.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_4) + # resolving model_2 resulted in err, so no schemas_5 + assert result == schemas_4 + assert result.errors == [error_1, error_2] def test_build_parse_error_on_reference(): @@ -1091,6 +1103,7 @@ def test_build_model_property(additional_properties_schema, expected_additional_ nullable=False, default=None, reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"), + references=[], required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)], optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)], description=data.description, diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 1024ef179..97458c322 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -23,6 +23,7 @@ def test_get_type_string(no_optional, nullable, required, expected): nullable=nullable, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), + references=[], description="", optional_properties=[], required_properties=[], @@ -42,6 +43,7 @@ def test_get_imports(): nullable=True, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), + references=[], description="", optional_properties=[], required_properties=[], @@ -57,3 +59,67 @@ def test_get_imports(): "from typing import Dict", "from typing import cast", } + + +def test_resolve_references(mocker): + import openapi_python_client.schema as oai + from openapi_python_client.parser.properties import build_model_property + + schemas = { + "RefA": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["String"], + properties={ + "String": oai.Schema.construct(type="string"), + "Enum": oai.Schema.construct(type="string", enum=["aValue"]), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + }, + ), + "RefB": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["DateTime"], + properties={ + "Int": oai.Schema.construct(type="integer"), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + # Intentionally no properties defined + "RefC": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + ), + } + + model_schema = oai.Schema.construct( + allOf=[ + oai.Reference.construct(ref="#/components/schemas/RefA"), + oai.Reference.construct(ref="#/components/schemas/RefB"), + oai.Reference.construct(ref="#/components/schemas/RefC"), + oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["Float"], + properties={ + "String": oai.Schema.construct(type="string"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + ] + ) + + components = {**schemas, "Model": model_schema} + + from openapi_python_client.parser.properties import Schemas + + schemas_holder = Schemas() + model, schemas_holder = build_model_property( + data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None + ) + model.resolve_references(components, schemas_holder) + assert sorted(p.name for p in model.required_properties) == ["DateTime", "Float", "String"] + assert all(p.required for p in model.required_properties) + assert sorted(p.name for p in model.optional_properties) == ["Enum", "Int"] + assert all(not p.required for p in model.optional_properties) From 70cb4bb2c8bc5c118ebfa8278b13219aa4e9b1b5 Mon Sep 17 00:00:00 2001 From: Packy Gallagher Date: Fri, 4 Dec 2020 14:04:12 -0800 Subject: [PATCH 02/18] feat: Add setup.py support BNCH-18722 (#11) Add support for generating setup.py and the initially generated one --- pyproject.toml | 6 ++++++ setup.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index a1de2316c..3c6f98df0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,12 @@ task regen\ && task regen_custom\ && task e2e\ """ +gen-setuppy = """ +poetry build \ +&& tar --strip-components=1 -xvf "$(ls -1 dist/*tar.gz | tail -1)" '*/setup.py' \ +&& isort setup.py \ +&& black setup.py +""" [tool.black] line-length = 120 diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..c38ef4ea0 --- /dev/null +++ b/setup.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +from setuptools import setup + +packages = [ + "openapi_python_client", + "openapi_python_client.parser", + "openapi_python_client.parser.properties", + "openapi_python_client.schema", + "openapi_python_client.templates", +] + +package_data = {"": ["*"], "openapi_python_client.templates": ["property_templates/*"]} + +install_requires = [ + "attrs>=20.1.0,<21.0.0", + "autoflake>=1.4,<2.0", + "black>=20.8b1", + "httpx>=0.15.4,<0.17.0", + "isort>=5.0.5,<6.0.0", + "jinja2>=2.11.1,<3.0.0", + "pydantic>=1.6.1,<2.0.0", + "python-dateutil>=2.8.1,<3.0.0", + "pyyaml>=5.3.1,<6.0.0", + "shellingham>=1.3.2,<2.0.0", + "stringcase>=1.2.0,<2.0.0", + "typer>=0.3,<0.4", +] + +extras_require = { + ':python_version < "3.8"': ["importlib_metadata>=2.0.0,<3.0.0"], + ':sys_platform == "win32"': ["colorama>=0.4.3,<0.5.0"], +} + +entry_points = {"console_scripts": ["openapi-python-client = openapi_python_client.cli:app"]} + +setup_kwargs = { + "name": "openapi-python-client", + "version": "0.7.0", + "description": "Generate modern Python clients from OpenAPI", + "long_description": '[![triaxtec](https://circleci.com/gh/triaxtec/openapi-python-client.svg?style=svg)](https://circleci.com/gh/triaxtec/openapi-python-client)\n[![codecov](https://codecov.io/gh/triaxtec/openapi-python-client/branch/main/graph/badge.svg)](https://codecov.io/gh/triaxtec/openapi-python-client)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)\n[![Generic badge](https://img.shields.io/badge/type_checked-mypy-informational.svg)](https://mypy.readthedocs.io/en/stable/introduction.html)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n[![PyPI version shields.io](https://img.shields.io/pypi/v/openapi-python-client.svg)](https://pypi.python.org/pypi/openapi-python-client/)\n[![Downloads](https://static.pepy.tech/personalized-badge/openapi-python-client?period=total&units=international_system&left_color=blue&right_color=green&left_text=Downloads)](https://pepy.tech/project/openapi-python-client)\n\n# openapi-python-client\n\nGenerate modern Python clients from OpenAPI 3.x documents.\n\n_This generator does not support OpenAPI 2.x FKA Swagger. If you need to use an older document, try upgrading it to\nversion 3 first with one of many available converters._\n\n**This project is still in development and does not support all OpenAPI features**\n\n## Why This?\n\nThe Python clients generated by openapi-generator support Python 2 and therefore come with a lot of baggage. This tool\naims to generate clients which:\n\n1. Use all the latest and greatest Python features like type annotations and dataclasses\n1. Don\'t carry around a bunch of compatibility code for older version of Python (e.g. the `six` package)\n1. Have better documentation and more obvious usage instructions\n\nAdditionally, because this generator is written in Python, it should be more accessible to contribution by the people\nusing it (Python developers).\n\n## Installation\n\nI recommend you install with [pipx](https://pipxproject.github.io/pipx/) so you don\'t conflict with any other packages\nyou might have: `pipx install openapi-python-client`.\n\nBetter yet, use `pipx run openapi-python-client ` to always use the latest version of the generator.\n\nYou can install with normal pip if you want to though: `pip install openapi-python-client`\n\nThen, if you want tab completion: `openapi-python-client --install-completion`\n\n## Usage\n\n### Create a new client\n\n`openapi-python-client generate --url https://my.api.com/openapi.json`\n\nThis will generate a new client library named based on the title in your OpenAPI spec. For example, if the title\nof your API is "My API", the expected output will be "my-api-client". If a folder already exists by that name, you\'ll\nget an error.\n\n### Update an existing client\n\n`openapi-python-client update --url https://my.api.com/openapi.json`\n\n> For more usage details run `openapi-python-client --help` or read [usage](usage.md)\n\n### Using custom templates\n\nThis feature leverages Jinja2\'s [ChoiceLoader](https://jinja.palletsprojects.com/en/2.11.x/api/#jinja2.ChoiceLoader) and [FileSystemLoader](https://jinja.palletsprojects.com/en/2.11.x/api/#jinja2.FileSystemLoader). This means you do _not_ need to customize every template. Simply copy the template(s) you want to customize from [the default template directory](openapi_python_client/templates) to your own custom template directory (file names _must_ match exactly) and pass the template directory through the `custom-template-path` flag to the `generate` and `update` commands. For instance,\n\n```\nopenapi-python-client update \\\n --url https://my.api.com/openapi.json \\\n --custom-template-path=relative/path/to/mytemplates\n```\n\n_Be forewarned, this is a beta-level feature in the sense that the API exposed in the templates is undocumented and unstable._\n\n## What You Get\n\n1. A `pyproject.toml` file with some basic metadata intended to be used with [Poetry].\n1. A `README.md` you\'ll most definitely need to update with your project\'s details\n1. A Python module named just like the auto-generated project name (e.g. "my_api_client") which contains:\n 1. A `client` module which will have both a `Client` class and an `AuthenticatedClient` class. You\'ll need these\n for calling the functions in the `api` module.\n 1. An `api` module which will contain one module for each tag in your OpenAPI spec, as well as a `default` module\n for endpoints without a tag. Each of these modules in turn contains one function for calling each endpoint.\n 1. A `models` module which has all the classes defined by the various schemas in your OpenAPI spec\n\nFor a full example you can look at the `end_to_end_tests` directory which has an `openapi.json` file.\n"golden-record" in that same directory is the generated client from that OpenAPI document.\n\n## OpenAPI features supported\n\n1. All HTTP Methods\n1. JSON and form bodies, path and query parameters\n1. File uploads with multipart/form-data bodies\n1. float, string, int, date, datetime, string enums, and custom schemas or lists containing any of those\n1. html/text or application/json responses containing any of the previous types\n1. Bearer token security\n\n## Configuration\n\nYou can pass a YAML (or JSON) file to openapi-python-client with the `--config` option in order to change some behavior.\nThe following parameters are supported:\n\n### class_overrides\n\nUsed to change the name of generated model classes. This param should be a mapping of existing class name\n(usually a key in the "schemas" section of your OpenAPI document) to class_name and module_name. As an example, if the\nname of the a model in OpenAPI (and therefore the generated class name) was something like "\\_PrivateInternalLongName"\nand you want the generated client\'s model to be called "ShortName" in a module called "short_name" you could do this:\n\nExample:\n\n```yaml\nclass_overrides:\n _PrivateInternalLongName:\n class_name: ShortName\n module_name: short_name\n```\n\nThe easiest way to find what needs to be overridden is probably to generate your client and go look at everything in the\nmodels folder.\n\n### project_name_override and package_name_override\n\nUsed to change the name of generated client library project/package. If the project name is changed but an override for the package name\nisn\'t provided, the package name will be converted from the project name using the standard convention (replacing `-`\'s with `_`\'s).\n\nExample:\n\n```yaml\nproject_name_override: my-special-project-name\npackage_name_override: my_extra_special_package_name\n```\n\n### field_prefix\n\nWhen generating properties, the `name` attribute of the OpenAPI schema will be used. When the `name` is not a valid\nPython identifier (e.g. begins with a number) this string will be prepended. Defaults to "field\\_".\n\nExample:\n\n```yaml\nfield_prefix: attr_\n```\n\n### package_version_override\n\nSpecify the package version of the generated client. If unset, the client will use the version of the OpenAPI spec.\n\nExample:\n\n```yaml\npackage_version_override: 1.2.3\n```\n\n[changelog.md]: CHANGELOG.md\n[poetry]: https://python-poetry.org/\n', + "author": "Dylan Anthony", + "author_email": "danthony@triaxtec.com", + "maintainer": None, + "maintainer_email": None, + "url": "https://github.com/triaxtec/openapi-python-client", + "packages": packages, + "package_data": package_data, + "install_requires": install_requires, + "extras_require": extras_require, + "entry_points": entry_points, + "python_requires": ">=3.6,<4.0", +} + + +setup(**setup_kwargs) From ce30b4c5018e790deceb95d9fa8be1d1713d2fed Mon Sep 17 00:00:00 2001 From: Packy Gallagher Date: Tue, 8 Dec 2020 18:17:01 -0800 Subject: [PATCH 03/18] fix: require setuptools >50 in pyproject.toml --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3c6f98df0..222b69561 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,5 +98,8 @@ skip = [".venv", "tests/test_templates"] omit = ["openapi_python_client/templates/*"] [build-system] -requires = ["poetry>=1.0"] +requires = [ + "setuptools>=30.3.0,<50", + "poetry>=1.0" +] build-backend = "poetry.masonry.api" From 0b9a99aa40cbf0df340a9a93de6c8f36991ec096 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 14 Jan 2021 18:53:44 -0500 Subject: [PATCH 04/18] fix: Fix bug parsing `allOf` in nested keys BNCH-20174 (#29) --- .../parser/properties/__init__.py | 10 +-- .../test_properties/test_model_property.py | 76 +++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index 487f5b464..f6289ce7c 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -268,9 +268,6 @@ def build_model_property( for key, value in all_props.items(): prop_required = key in required_set - if not isinstance(value, oai.Reference) and value.allOf: - # resolved later - continue prop, schemas = property_from_data( name=key, required=prop_required, data=value, schemas=schemas, parent_name=class_name ) @@ -463,9 +460,6 @@ def _property_from_data( ) if data.anyOf or data.oneOf: return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - if not data.type: - return NoneProperty(name=name, required=required, nullable=False, default=None), schemas - if data.type == "string": return _string_based_property(name=name, required=required, data=data), schemas elif data.type == "number": @@ -500,8 +494,10 @@ def _property_from_data( ) elif data.type == "array": return build_list_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - elif data.type == "object": + elif data.type == "object" or data.allOf: return build_model_property(data=data, name=name, schemas=schemas, required=required, parent_name=parent_name) + elif not data.type: + return NoneProperty(name=name, required=required, nullable=False, default=None), schemas return PropertyError(data=data, detail=f"unknown type {data.type}"), schemas diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 97458c322..5a40f9e74 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -123,3 +123,79 @@ def test_resolve_references(mocker): assert all(p.required for p in model.required_properties) assert sorted(p.name for p in model.optional_properties) == ["Enum", "Int"] assert all(not p.required for p in model.optional_properties) + + +def test_resolve_references_nested_allof(mocker): + import openapi_python_client.schema as oai + from openapi_python_client.parser.properties import build_model_property + + schemas = { + "RefA": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["String"], + properties={ + "String": oai.Schema.construct(type="string"), + "Enum": oai.Schema.construct(type="string", enum=["aValue"]), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + }, + ), + "RefB": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["DateTime"], + properties={ + "Int": oai.Schema.construct(type="integer"), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + # Intentionally no properties defined + "RefC": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + ), + } + + model_schema = oai.Schema.construct( + type="object", + properties={ + "Key": oai.Schema.construct( + allOf=[ + oai.Reference.construct(ref="#/components/schemas/RefA"), + oai.Reference.construct(ref="#/components/schemas/RefB"), + oai.Reference.construct(ref="#/components/schemas/RefC"), + oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["Float"], + properties={ + "String": oai.Schema.construct(type="string"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + ] + ), + } + ) + + components = {**schemas, "Model": model_schema} + + from openapi_python_client.parser.properties import ModelProperty, Schemas + + schemas_holder = Schemas() + model, schemas_holder = build_model_property( + data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None + ) + model.resolve_references(components, schemas_holder) + assert sorted(p.name for p in model.required_properties) == [] + assert sorted(p.name for p in model.optional_properties) == ["Key"] + assert all(not p.required for p in model.optional_properties) + + key_property = model.optional_properties[0] + assert isinstance(key_property, ModelProperty) + key_property.resolve_references(components, schemas_holder) + assert sorted(p.name for p in key_property.required_properties) == ["DateTime", "Float", "String"] + assert all(p.required for p in key_property.required_properties) + assert sorted(p.name for p in key_property.optional_properties) == ["Enum", "Int"] + assert all(not p.required for p in key_property.optional_properties) \ No newline at end of file From f49d0bc188e85920bb4968fa4ee8c9c72cb93900 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 09:35:41 -0500 Subject: [PATCH 05/18] fix: Fix optional model properties BNCH-20284 (#35) --- .../custom_e2e/models/__init__.py | 4 + .../custom_e2e/models/a_model.py | 50 +++++++++++ .../custom_e2e/models/a_model_model.py | 85 +++++++++++++++++++ .../models/a_model_not_required_model.py | 85 +++++++++++++++++++ .../a_model_not_required_nullable_model.py | 85 +++++++++++++++++++ .../models/a_model_nullable_model.py | 85 +++++++++++++++++++ ...el_with_primitive_additional_properties.py | 2 +- .../my_test_api_client/models/__init__.py | 4 + .../my_test_api_client/models/a_model.py | 50 +++++++++++ .../models/a_model_model.py | 85 +++++++++++++++++++ .../models/a_model_not_required_model.py | 85 +++++++++++++++++++ .../a_model_not_required_nullable_model.py | 85 +++++++++++++++++++ .../models/a_model_nullable_model.py | 85 +++++++++++++++++++ ...el_with_primitive_additional_properties.py | 2 +- end_to_end_tests/openapi.json | 38 ++++++++- .../property_templates/model_property.pyi | 4 +- .../test_properties/test_model_property.py | 4 +- 17 files changed, 831 insertions(+), 7 deletions(-) create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py index d3ca924b3..6f5ac7423 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py @@ -1,6 +1,10 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel +from .a_model_model import AModelModel +from .a_model_not_required_model import AModelNotRequiredModel +from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 2bf3e140d..15a7cc68c 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -4,6 +4,10 @@ import attr from dateutil.parser import isoparse +from ..models.a_model_model import AModelModel +from ..models.a_model_not_required_model import AModelNotRequiredModel +from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -17,12 +21,16 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str + model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] + nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, Optional[str]] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET + not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -35,6 +43,8 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable + model = self.model.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -52,6 +62,17 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable + nullable_model = self.nullable_model.to_dict() if self.nullable_model else None + + not_required_model: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_model, Unset): + not_required_model = self.not_required_model.to_dict() + + not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_nullable_model, Unset): + not_required_nullable_model = ( + self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None + ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -60,8 +81,10 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, + "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, + "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -72,6 +95,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable + if not_required_model is not UNSET: + field_dict["not_required_model"] = not_required_model + if not_required_nullable_model is not UNSET: + field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -99,6 +126,8 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") + model = AModelModel.from_dict(d.pop("model")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -124,17 +153,38 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) + nullable_model = None + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) + + not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + _not_required_model = d.pop("not_required_model", UNSET) + if not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + + not_required_nullable_model = None + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_model) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, + model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, + nullable_model=nullable_model, + not_required_model=not_required_model, + not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py new file mode 100644 index 000000000..c1a00c152 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_model = AModelModel( + a_property=a_property, + ) + + a_model_model.additional_properties = d + return a_model_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py new file mode 100644 index 000000000..adecb4225 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_model = AModelNotRequiredModel( + a_property=a_property, + ) + + a_model_not_required_model.additional_properties = d + return a_model_not_required_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py new file mode 100644 index 000000000..9de2e3798 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_nullable_model = AModelNotRequiredNullableModel( + a_property=a_property, + ) + + a_model_not_required_nullable_model.additional_properties = d + return a_model_not_required_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py new file mode 100644 index 000000000..cbcf120f8 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_nullable_model = AModelNullableModel( + a_property=a_property, + ) + + a_model_nullable_model.additional_properties = d + return a_model_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index 47d65d90b..797c1ce31 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -33,7 +33,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index d3ca924b3..6f5ac7423 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -1,6 +1,10 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel +from .a_model_model import AModelModel +from .a_model_not_required_model import AModelNotRequiredModel +from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 2bf3e140d..15a7cc68c 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -4,6 +4,10 @@ import attr from dateutil.parser import isoparse +from ..models.a_model_model import AModelModel +from ..models.a_model_not_required_model import AModelNotRequiredModel +from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -17,12 +21,16 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str + model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] + nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, Optional[str]] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET + not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -35,6 +43,8 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable + model = self.model.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -52,6 +62,17 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable + nullable_model = self.nullable_model.to_dict() if self.nullable_model else None + + not_required_model: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_model, Unset): + not_required_model = self.not_required_model.to_dict() + + not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_nullable_model, Unset): + not_required_nullable_model = ( + self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None + ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -60,8 +81,10 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, + "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, + "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -72,6 +95,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable + if not_required_model is not UNSET: + field_dict["not_required_model"] = not_required_model + if not_required_nullable_model is not UNSET: + field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -99,6 +126,8 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") + model = AModelModel.from_dict(d.pop("model")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -124,17 +153,38 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) + nullable_model = None + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) + + not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + _not_required_model = d.pop("not_required_model", UNSET) + if not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + + not_required_nullable_model = None + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_model) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, + model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, + nullable_model=nullable_model, + not_required_model=not_required_model, + not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py new file mode 100644 index 000000000..c1a00c152 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_model = AModelModel( + a_property=a_property, + ) + + a_model_model.additional_properties = d + return a_model_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py new file mode 100644 index 000000000..adecb4225 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_model = AModelNotRequiredModel( + a_property=a_property, + ) + + a_model_not_required_model.additional_properties = d + return a_model_not_required_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py new file mode 100644 index 000000000..9de2e3798 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_nullable_model = AModelNotRequiredNullableModel( + a_property=a_property, + ) + + a_model_not_required_nullable_model.additional_properties = d + return a_model_not_required_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py new file mode 100644 index 000000000..cbcf120f8 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_nullable_model = AModelNullableModel( + a_property=a_property, + ) + + a_model_nullable_model.additional_properties = d + return a_model_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index 47d65d90b..797c1ce31 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -33,7 +33,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 9e3d78908..196538f19 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -622,7 +622,7 @@ "schemas": { "AModel": { "title": "AModel", - "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable"], + "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable", "model", "nullable_model"], "type": "object", "properties": { "an_enum_value": { @@ -686,6 +686,42 @@ "title": "NOT Required AND NOT Nullable", "type": "string", "nullable": false + }, + "model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "nullable_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true + }, + "not_required_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "not_required_nullable_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true } }, "description": "A Model for testing all the ways custom objects can be used ", diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index e6746cb24..b41289409 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -1,5 +1,5 @@ {% macro construct(property, source, initial_value=None) %} -{% if property.required %} +{% if property.required and not property.nullable %} {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% else %} {% if initial_value != None %} @@ -10,7 +10,7 @@ {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} _{{ property.python_name }} = {{source}} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}: {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], _{{ property.python_name }})) {% endif %} {% endmacro %} diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 5a40f9e74..421f40d48 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -176,7 +176,7 @@ def test_resolve_references_nested_allof(mocker): ), ] ), - } + }, ) components = {**schemas, "Model": model_schema} @@ -198,4 +198,4 @@ def test_resolve_references_nested_allof(mocker): assert sorted(p.name for p in key_property.required_properties) == ["DateTime", "Float", "String"] assert all(p.required for p in key_property.required_properties) assert sorted(p.name for p in key_property.optional_properties) == ["Enum", "Int"] - assert all(not p.required for p in key_property.optional_properties) \ No newline at end of file + assert all(not p.required for p in key_property.optional_properties) From b0109cdb816fab310c741a0214283219d5124e05 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 17:39:51 -0500 Subject: [PATCH 06/18] feat: Serialize model query parameters with `style=form, explode=true` BNCH-18023 (#39) --- .../api/tests/defaults_tests_defaults_post.py | 28 +++++++++------ ...tional_value_tests_optional_query_param.py | 2 +- .../api/tests/defaults_tests_defaults_post.py | 36 +++++++++++++------ ...tional_value_tests_optional_query_param.py | 2 +- end_to_end_tests/openapi.json | 8 +++++ .../parser/properties/model_property.py | 1 + .../parser/properties/property.py | 1 + .../templates/endpoint_macros.pyi | 9 ++--- 8 files changed, 61 insertions(+), 26 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index 574d5018b..f87ad3e1b 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -13,6 +13,7 @@ from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError +from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Unset @@ -50,6 +51,7 @@ def httpx_request( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: json_datetime_prop: Union[Unset, str] = UNSET @@ -89,27 +91,33 @@ def httpx_request( if not isinstance(enum_prop, Unset): json_enum_prop = enum_prop + json_model_prop: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(model_prop, Unset): + json_model_prop = model_prop.to_dict() + params: Dict[str, Any] = {} - if string_prop is not UNSET: + if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if datetime_prop is not UNSET: + if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: params["datetime_prop"] = json_datetime_prop - if date_prop is not UNSET: + if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop - if float_prop is not UNSET: + if not isinstance(float_prop, Unset) and float_prop is not None: params["float_prop"] = float_prop - if int_prop is not UNSET: + if not isinstance(int_prop, Unset) and int_prop is not None: params["int_prop"] = int_prop - if boolean_prop is not UNSET: + if not isinstance(boolean_prop, Unset) and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if list_prop is not UNSET: + if not isinstance(json_list_prop, Unset) and json_list_prop is not None: params["list_prop"] = json_list_prop - if union_prop is not UNSET: + if not isinstance(json_union_prop, Unset) and json_union_prop is not None: params["union_prop"] = json_union_prop - if union_prop_with_ref is not UNSET: + if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if enum_prop is not UNSET: + if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: params["enum_prop"] = json_enum_prop + if not isinstance(json_model_prop, Unset) and json_model_prop is not None: + params.update(json_model_prop) response = client.request( "post", diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py index bff43cc10..616dc4252 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py @@ -44,7 +44,7 @@ def httpx_request( json_query_param = query_param params: Dict[str, Any] = {} - if query_param is not UNSET: + if not isinstance(json_query_param, Unset) and json_query_param is not None: params["query_param"] = json_query_param response = client.request( diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index 9242cddaa..ff6ef2409 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -7,6 +7,7 @@ from ...client import Client from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError +from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Response, Unset @@ -23,6 +24,7 @@ def _get_kwargs( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/defaults".format(client.base_url) @@ -65,27 +67,33 @@ def _get_kwargs( if not isinstance(enum_prop, Unset): json_enum_prop = enum_prop + json_model_prop: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(model_prop, Unset): + json_model_prop = model_prop.to_dict() + params: Dict[str, Any] = {} - if string_prop is not UNSET: + if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if datetime_prop is not UNSET: + if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: params["datetime_prop"] = json_datetime_prop - if date_prop is not UNSET: + if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop - if float_prop is not UNSET: + if not isinstance(float_prop, Unset) and float_prop is not None: params["float_prop"] = float_prop - if int_prop is not UNSET: + if not isinstance(int_prop, Unset) and int_prop is not None: params["int_prop"] = int_prop - if boolean_prop is not UNSET: + if not isinstance(boolean_prop, Unset) and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if list_prop is not UNSET: + if not isinstance(json_list_prop, Unset) and json_list_prop is not None: params["list_prop"] = json_list_prop - if union_prop is not UNSET: + if not isinstance(json_union_prop, Unset) and json_union_prop is not None: params["union_prop"] = json_union_prop - if union_prop_with_ref is not UNSET: + if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if enum_prop is not UNSET: + if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: params["enum_prop"] = json_enum_prop + if not isinstance(json_model_prop, Unset) and json_model_prop is not None: + params.update(json_model_prop) return { "url": url, @@ -130,6 +138,7 @@ def sync_detailed( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -143,6 +152,7 @@ def sync_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) response = httpx.post( @@ -165,6 +175,7 @@ def sync( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -180,6 +191,7 @@ def sync( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ).parsed @@ -196,6 +208,7 @@ async def asyncio_detailed( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -209,6 +222,7 @@ async def asyncio_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) async with httpx.AsyncClient() as _client: @@ -230,6 +244,7 @@ async def asyncio( union_prop: Union[Unset, float, str] = "not a float", union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, enum_prop: Union[Unset, AnEnum] = UNSET, + model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -246,5 +261,6 @@ async def asyncio( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 751f48e03..576a770fe 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -21,7 +21,7 @@ def _get_kwargs( json_query_param = query_param params: Dict[str, Any] = {} - if query_param is not UNSET: + if not isinstance(json_query_param, Unset) and json_query_param is not None: params["query_param"] = json_query_param return { diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 196538f19..8562f6796 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -396,6 +396,14 @@ }, "name": "enum_prop", "in": "query" + }, + { + "required": false, + "schema": { + "$ref": "#/components/schemas/ModelWithUnionProperty" + }, + "name": "model_prop", + "in": "query" } ], "responses": { diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 40d1f930b..4bcbe4695 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -27,6 +27,7 @@ class ModelProperty(Property): additional_properties: Union[bool, Property] template: ClassVar[str] = "model_property.pyi" + json_is_dict: ClassVar[bool] = True def resolve_references( self, components: Dict[str, Union[oai.Reference, oai.Schema]], schemas: Schemas diff --git a/openapi_python_client/parser/properties/property.py b/openapi_python_client/parser/properties/property.py index 0b7047551..a94af72ba 100644 --- a/openapi_python_client/parser/properties/property.py +++ b/openapi_python_client/parser/properties/property.py @@ -28,6 +28,7 @@ class Property: python_name: str = attr.ib(init=False) template: ClassVar[Optional[str]] = None + json_is_dict: ClassVar[bool] = False def __attrs_post_init__(self) -> None: object.__setattr__(self, "python_name", utils.to_valid_python_identifier(utils.snake_case(self.name))) diff --git a/openapi_python_client/templates/endpoint_macros.pyi b/openapi_python_client/templates/endpoint_macros.pyi index 5819714d8..8d3d464c3 100644 --- a/openapi_python_client/templates/endpoint_macros.pyi +++ b/openapi_python_client/templates/endpoint_macros.pyi @@ -33,11 +33,12 @@ params: Dict[str, Any] = { } {% for property in endpoint.query_parameters %} {% if not property.required %} -if {{ property.python_name }} is not UNSET: - {% if property.template %} - params["{{ property.name }}"] = {{ "json_" + property.python_name }} + {% set property_name = "json_" + property.python_name if property.template else property.python_name %} +if {% if not property.required %}not isinstance({{ property_name }}, Unset) and {% endif %}{{ property_name }} is not None: + {% if property.json_is_dict %} + params.update({{ property_name }}) {% else %} - params["{{ property.name }}"] = {{ property.python_name }} + params["{{ property.name }}"] = {{ property_name }} {% endif %} {% endif %} {% endfor %} From f469553d42eb1d977064af60343c88737f09d3f8 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:09:24 -0500 Subject: [PATCH 07/18] Cherry-pick optional params --- end_to_end_tests/openapi.json | 87 +++++----- .../parser/properties/__init__.py | 94 +++++----- .../parser/properties/enum_property.py | 14 +- .../parser/properties/model_property.py | 69 +------- .../parser/properties/property.py | 49 ++++-- .../templates/endpoint_macros.pyi | 17 +- .../property_templates/date_property.pyi | 6 +- .../property_templates/datetime_property.pyi | 6 +- .../property_templates/enum_property.pyi | 10 +- .../property_templates/file_property.pyi | 6 +- .../property_templates/list_property.pyi | 8 +- .../property_templates/model_property.pyi | 10 +- .../property_templates/union_property.pyi | 10 +- openapi_python_client/templates/types.py | 5 +- pyproject.toml | 16 +- .../test_parser/test_properties/test_init.py | 163 ++++++++---------- .../test_properties/test_model_property.py | 146 +--------------- .../test_date_property/optional_nullable.py | 2 +- 18 files changed, 254 insertions(+), 464 deletions(-) diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 8562f6796..931fc481e 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -290,12 +290,49 @@ { "required": false, "schema": { - "title": "Datetime Prop", + "title": "Not Required, Not Nullable Datetime Prop", + "nullable": false, "type": "string", "format": "date-time", "default": "1010-10-10T00:00:00" }, - "name": "datetime_prop", + "name": "not_required_not_nullable_datetime_prop", + "in": "query" + }, + { + "required": false, + "schema": { + "title": "Not Required, Nullable Datetime Prop", + "nullable": true, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "not_required_nullable_datetime_prop", + "in": "query" + }, + { + "required": true, + "schema": { + "title": "Required, Not Nullable Datetime Prop", + "nullable": false, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "required_not_nullable_datetime_prop", + "in": "query" + }, + { + "required": true, + "schema": { + "title": "Required, Nullable Datetime Prop", + "nullable": true, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "required_nullable_datetime_prop", "in": "query" }, { @@ -396,14 +433,6 @@ }, "name": "enum_prop", "in": "query" - }, - { - "required": false, - "schema": { - "$ref": "#/components/schemas/ModelWithUnionProperty" - }, - "name": "model_prop", - "in": "query" } ], "responses": { @@ -630,7 +659,7 @@ "schemas": { "AModel": { "title": "AModel", - "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable", "model", "nullable_model"], + "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable"], "type": "object", "properties": { "an_enum_value": { @@ -694,42 +723,6 @@ "title": "NOT Required AND NOT Nullable", "type": "string", "nullable": false - }, - "model": { - "type": "object", - "allOf": [ - { - "ref": "#/components/schemas/ModelWithUnionProperty" - } - ], - "nullable": false - }, - "nullable_model": { - "type": "object", - "allOf": [ - { - "ref": "#/components/schemas/ModelWithUnionProperty" - } - ], - "nullable": true - }, - "not_required_model": { - "type": "object", - "allOf": [ - { - "ref": "#/components/schemas/ModelWithUnionProperty" - } - ], - "nullable": false - }, - "not_required_nullable_model": { - "type": "object", - "allOf": [ - { - "ref": "#/components/schemas/ModelWithUnionProperty" - } - ], - "nullable": true } }, "description": "A Model for testing all the ways custom objects can be used ", diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index f6289ce7c..e3a3f69b7 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -19,6 +19,7 @@ class NoneProperty(Property): """ A property that is always None (used for empty schemas) """ _type_string: ClassVar[str] = "None" + _json_type_string: ClassVar[str] = "None" template: ClassVar[Optional[str]] = "none_property.pyi" @@ -29,6 +30,7 @@ class StringProperty(Property): max_length: Optional[int] = None pattern: Optional[str] = None _type_string: ClassVar[str] = "str" + _json_type_string: ClassVar[str] = "str" @attr.s(auto_attribs=True, frozen=True) @@ -38,6 +40,7 @@ class DateTimeProperty(Property): """ _type_string: ClassVar[str] = "datetime.datetime" + _json_type_string: ClassVar[str] = "str" template: ClassVar[str] = "datetime_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -58,6 +61,7 @@ class DateProperty(Property): """ A property of type datetime.date """ _type_string: ClassVar[str] = "datetime.date" + _json_type_string: ClassVar[str] = "str" template: ClassVar[str] = "date_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -78,6 +82,8 @@ class FileProperty(Property): """ A property used for uploading files """ _type_string: ClassVar[str] = "File" + # Return type of File.to_tuple() + _json_type_string: ClassVar[str] = "Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]" template: ClassVar[str] = "file_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -98,6 +104,7 @@ class FloatProperty(Property): """ A property of type float """ _type_string: ClassVar[str] = "float" + _json_type_string: ClassVar[str] = "float" @attr.s(auto_attribs=True, frozen=True) @@ -105,6 +112,7 @@ class IntProperty(Property): """ A property of type int """ _type_string: ClassVar[str] = "int" + _json_type_string: ClassVar[str] = "int" @attr.s(auto_attribs=True, frozen=True) @@ -112,6 +120,7 @@ class BooleanProperty(Property): """ Property for bool """ _type_string: ClassVar[str] = "bool" + _json_type_string: ClassVar[str] = "bool" InnerProp = TypeVar("InnerProp", bound=Property) @@ -122,18 +131,11 @@ class ListProperty(Property, Generic[InnerProp]): """ A property representing a list (array) of other properties """ inner_property: InnerProp + _json_type_string: ClassVar[str] = "List[Any]" template: ClassVar[str] = "list_property.pyi" - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - type_string = f"List[{self.inner_property.get_type_string()}]" - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + def get_base_type_string(self) -> str: + return f"List[{self.inner_property.get_type_string()}]" def get_instance_type_string(self) -> str: """Get a string representation of runtime type that should be used for `isinstance` checks""" @@ -167,18 +169,38 @@ def __attrs_post_init__(self) -> None: self, "has_properties_without_templates", any(prop.template is None for prop in self.inner_properties) ) - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - inner_types = [p.get_type_string(no_optional=True) for p in self.inner_properties] - inner_prop_string = ", ".join(inner_types) - type_string = f"Union[{inner_prop_string}]" + def _get_inner_prop_string(self, json: bool = False) -> str: + inner_types = [p.get_type_string(no_optional=True, json=json) for p in self.inner_properties] + unique_inner_types = list(dict.fromkeys(inner_types)) + return ", ".join(unique_inner_types) + + def get_base_type_string(self, json: bool = False) -> str: + return f"Union[{self._get_inner_prop_string(json=json)}]" + + def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: + """ + Get a string representation of type that should be used when declaring this property. + + This implementation differs slightly from `Property.get_type_string` in order to collapse + nested union types. + """ + type_string = self.get_base_type_string(json=json) if no_optional: return type_string - if not self.required: - type_string = f"Union[Unset, {inner_prop_string}]" - if self.nullable: - type_string = f"Optional[{type_string}]" - return type_string + if self.required: + if self.nullable: + return f"Union[None, {self._get_inner_prop_string(json=json)}]" + else: + return type_string + else: + if self.nullable: + return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + else: + if query_parameter: + # For query parameters, None has the same meaning as Unset + return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + else: + return f"Union[Unset, {self._get_inner_prop_string(json=json)}]" def get_imports(self, *, prefix: str) -> Set[str]: """ @@ -250,23 +272,13 @@ def build_model_property( required_properties: List[Property] = [] optional_properties: List[Property] = [] relative_imports: Set[str] = set() - references: List[oai.Reference] = [] class_name = data.title or name if parent_name: class_name = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_name)}" ref = Reference.from_ref(class_name) - all_props = data.properties or {} - if not isinstance(data, oai.Reference) and data.allOf: - for sub_prop in data.allOf: - if isinstance(sub_prop, oai.Reference): - references += [sub_prop] - else: - all_props.update(sub_prop.properties or {}) - required_set.update(sub_prop.required or []) - - for key, value in all_props.items(): + for key, value in (data.properties or {}).items(): prop_required = key in required_set prop, schemas = property_from_data( name=key, required=prop_required, data=value, schemas=schemas, parent_name=class_name @@ -302,7 +314,6 @@ def build_model_property( prop = ModelProperty( reference=ref, - references=references, required_properties=required_properties, optional_properties=optional_properties, relative_imports=relative_imports, @@ -460,6 +471,9 @@ def _property_from_data( ) if data.anyOf or data.oneOf: return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) + if not data.type: + return NoneProperty(name=name, required=required, nullable=False, default=None), schemas + if data.type == "string": return _string_based_property(name=name, required=required, data=data), schemas elif data.type == "number": @@ -494,10 +508,8 @@ def _property_from_data( ) elif data.type == "array": return build_list_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - elif data.type == "object" or data.allOf: + elif data.type == "object": return build_model_property(data=data, name=name, schemas=schemas, required=required, parent_name=parent_name) - elif not data.type: - return NoneProperty(name=name, required=required, nullable=False, default=None), schemas return PropertyError(data=data, detail=f"unknown type {data.type}"), schemas @@ -554,16 +566,6 @@ def build_schemas(*, components: Dict[str, Union[oai.Reference, oai.Schema]]) -> schemas = schemas_or_err processing = True # We made some progress this round, do another after it's done to_process = next_round - - resolve_errors: List[PropertyError] = [] - models = list(schemas.models.values()) - for model in models: - schemas_or_err = model.resolve_references(components=components, schemas=schemas) - if isinstance(schemas_or_err, PropertyError): - resolve_errors.append(schemas_or_err) - else: - schemas = schemas_or_err - schemas.errors.extend(errors) - schemas.errors.extend(resolve_errors) + return schemas diff --git a/openapi_python_client/parser/properties/enum_property.py b/openapi_python_client/parser/properties/enum_property.py index 1217f23ee..6938dd716 100644 --- a/openapi_python_client/parser/properties/enum_property.py +++ b/openapi_python_client/parser/properties/enum_property.py @@ -18,21 +18,13 @@ class EnumProperty(Property): values: Dict[str, ValueType] reference: Reference value_type: Type[ValueType] + _json_type_string: ClassVar[str] = "int" default: Optional[Any] = attr.ib() template: ClassVar[str] = "enum_property.pyi" - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - - type_string = self.reference.class_name - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + def get_base_type_string(self) -> str: + return self.reference.class_name def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 4bcbe4695..3ab145af4 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -1,87 +1,28 @@ -from __future__ import annotations - -from collections.abc import Iterable -from typing import TYPE_CHECKING, ClassVar, Dict, List, Set, Union +from typing import ClassVar, List, Set, Union import attr -from ... import schema as oai -from ..errors import PropertyError from ..reference import Reference from .property import Property -if TYPE_CHECKING: - from .schemas import Schemas - @attr.s(auto_attribs=True, frozen=True) class ModelProperty(Property): """ A property which refers to another Schema """ reference: Reference - references: List[oai.Reference] + required_properties: List[Property] optional_properties: List[Property] description: str relative_imports: Set[str] additional_properties: Union[bool, Property] + _json_type_string: ClassVar[str] = "Dict[str, Any]" template: ClassVar[str] = "model_property.pyi" - json_is_dict: ClassVar[bool] = True - - def resolve_references( - self, components: Dict[str, Union[oai.Reference, oai.Schema]], schemas: Schemas - ) -> Union[Schemas, PropertyError]: - from ..properties import property_from_data - - required_set = set() - props = {} - while self.references: - reference = self.references.pop() - source_name = Reference.from_ref(reference.ref).class_name - referenced_prop = components[source_name] - assert isinstance(referenced_prop, oai.Schema) - for p, val in (referenced_prop.properties or {}).items(): - props[p] = (val, source_name) - for sub_prop in referenced_prop.allOf or []: - if isinstance(sub_prop, oai.Reference): - self.references.append(sub_prop) - else: - for p, val in (sub_prop.properties or {}).items(): - props[p] = (val, source_name) - if isinstance(referenced_prop.required, Iterable): - for sub_prop_name in referenced_prop.required: - required_set.add(sub_prop_name) - - for key, (value, source_name) in (props or {}).items(): - required = key in required_set - prop, schemas = property_from_data( - name=key, required=required, data=value, schemas=schemas, parent_name=source_name - ) - if isinstance(prop, PropertyError): - return prop - if required: - self.required_properties.append(prop) - # Remove the optional version - new_optional_props = [op for op in self.optional_properties if op.name != prop.name] - self.optional_properties.clear() - self.optional_properties.extend(new_optional_props) - elif not any(ep for ep in (self.optional_properties + self.required_properties) if ep.name == prop.name): - self.optional_properties.append(prop) - self.relative_imports.update(prop.get_imports(prefix="..")) - - return schemas - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - type_string = self.reference.class_name - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[{type_string}, Unset]" - return type_string + def get_base_type_string(self) -> str: + return self.reference.class_name def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/parser/properties/property.py b/openapi_python_client/parser/properties/property.py index a94af72ba..651370ae2 100644 --- a/openapi_python_client/parser/properties/property.py +++ b/openapi_python_client/parser/properties/property.py @@ -24,30 +24,48 @@ class Property: required: bool nullable: bool _type_string: ClassVar[str] = "" + _json_type_string: ClassVar[str] = "" # Type of the property after JSON serialization default: Optional[str] = attr.ib() python_name: str = attr.ib(init=False) template: ClassVar[Optional[str]] = None - json_is_dict: ClassVar[bool] = False def __attrs_post_init__(self) -> None: object.__setattr__(self, "python_name", utils.to_valid_python_identifier(utils.snake_case(self.name))) - def get_type_string(self, no_optional: bool = False) -> str: + def get_base_type_string(self) -> str: + return self._type_string + + def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: """ Get a string representation of type that should be used when declaring this property Args: no_optional: Do not include Optional or Unset even if the value is optional (needed for isinstance checks) + query_parameter: True if the property's type is being used for a query parameter + json: True if the type refers to the property after JSON serialization """ - type_string = self._type_string + if json: + type_string = self._json_type_string + else: + type_string = self.get_base_type_string() + if no_optional: - return self._type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + return type_string + if self.required: + if self.nullable: + return f"Optional[{type_string}]" + else: + return type_string + else: + if self.nullable: + return f"Union[Unset, None, {type_string}]" + else: + if query_parameter: + # For query parameters, None has the same meaning as Unset + return f"Union[Unset, None, {type_string}]" + else: + return f"Union[Unset, {type_string}]" def get_instance_type_string(self) -> str: """Get a string representation of runtime type that should be used for `isinstance` checks""" @@ -70,8 +88,13 @@ def get_imports(self, *, prefix: str) -> Set[str]: imports.add(f"from {prefix}types import UNSET, Unset") return imports - def to_string(self) -> str: - """ How this should be declared in a dataclass """ + def to_string(self, query_parameter: bool = False) -> str: + """ + How this should be declared in a dataclass + + Args: + query_parameter: True if the property's type is being used for a query parameter + """ default: Optional[str] if self.default is not None: default = self.default @@ -81,6 +104,6 @@ def to_string(self) -> str: default = None if default is not None: - return f"{self.python_name}: {self.get_type_string()} = {default}" + return f"{self.python_name}: {self.get_type_string(query_parameter=query_parameter)} = {default}" else: - return f"{self.python_name}: {self.get_type_string()}" + return f"{self.python_name}: {self.get_type_string(query_parameter=query_parameter)}" diff --git a/openapi_python_client/templates/endpoint_macros.pyi b/openapi_python_client/templates/endpoint_macros.pyi index 8d3d464c3..7a1862be3 100644 --- a/openapi_python_client/templates/endpoint_macros.pyi +++ b/openapi_python_client/templates/endpoint_macros.pyi @@ -17,12 +17,12 @@ if {{ parameter.python_name }} is not UNSET: {% set destination = "json_" + property.python_name %} {% if property.template %} {% from "property_templates/" + property.template import transform %} -{{ transform(property, property.python_name, destination) }} +{{ transform(property, property.python_name, destination, query_parameter=True) }} {% endif %} {% endfor %} params: Dict[str, Any] = { {% for property in endpoint.query_parameters %} - {% if property.required %} + {% if property.required and not property.nullable %} {% if property.template %} "{{ property.name }}": {{ "json_" + property.python_name }}, {% else %} @@ -32,13 +32,12 @@ params: Dict[str, Any] = { {% endfor %} } {% for property in endpoint.query_parameters %} - {% if not property.required %} - {% set property_name = "json_" + property.python_name if property.template else property.python_name %} -if {% if not property.required %}not isinstance({{ property_name }}, Unset) and {% endif %}{{ property_name }} is not None: - {% if property.json_is_dict %} - params.update({{ property_name }}) + {% if not property.required or property.nullable %} +if {% if not property.required %}{{ property.python_name }} is not UNSET and {% endif %}{{ property.python_name }} is not None: + {% if property.template %} + params["{{ property.name }}"] = {{ "json_" + property.python_name }} {% else %} - params["{{ property.name }}"] = {{ property_name }} + params["{{ property.name }}"] = {{ property.python_name }} {% endif %} {% endif %} {% endfor %} @@ -97,7 +96,7 @@ json_body: {{ endpoint.json_body.get_type_string() }}, {% endif %} {# query parameters #} {% for parameter in endpoint.query_parameters %} -{{ parameter.to_string() }}, +{{ parameter.to_string(query_parameter=True) }}, {% endfor %} {% for parameter in endpoint.header_parameters %} {{ parameter.to_string() }}, diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index a3a980c8f..bc2cae912 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -9,13 +9,13 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {{ destination }} = {{ source }}.isoformat() {% if property.nullable %}if {{ source }} else None {%endif%} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.isoformat() diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index b8e1b8ff0..91ce0cacc 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -14,7 +14,7 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None @@ -22,9 +22,9 @@ if _{{ property.python_name }} is not None: {{ destination }} = {{ source }}.isoformat() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.isoformat() diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 4765a6fd5..831f633d5 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -9,7 +9,7 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.value if {{ source }} else None @@ -17,12 +17,12 @@ if _{{ property.python_name }} is not None: {{ destination }} = {{ source }}.value {% endif %} {% else %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} - {{ destination }} = {{ source }} if {{ source }} else None +{% if property.nullable or query_parameter %} + {{ destination }} = {{ source }}.value if {{ source }} else None {% else %} - {{ destination }} = {{ source }} + {{ destination }} = {{ source }}.value {% endif %} {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/file_property.pyi b/openapi_python_client/templates/property_templates/file_property.pyi index ffa3c20d9..50a331851 100644 --- a/openapi_python_client/templates/property_templates/file_property.pyi +++ b/openapi_python_client/templates/property_templates/file_property.pyi @@ -4,7 +4,7 @@ ) {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None @@ -12,9 +12,9 @@ {{ destination }} = {{ source }}.to_tuple() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.to_tuple() diff --git a/openapi_python_client/templates/property_templates/list_property.pyi b/openapi_python_client/templates/property_templates/list_property.pyi index d05a13960..5f58bcd30 100644 --- a/openapi_python_client/templates/property_templates/list_property.pyi +++ b/openapi_python_client/templates/property_templates/list_property.pyi @@ -32,7 +32,7 @@ for {{ inner_source }} in {{ source }}: {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% set inner_property = property.inner_property %} {% if property.required %} {% if property.nullable %} @@ -44,13 +44,13 @@ else: {{ _transform(property, source, destination) }} {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, List[Any]]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} if {{ source }} is None: {{ destination }} = None else: - {{ _transform(property, source, destination) | indent(4)}} + {{ _transform(property, source, destination) | indent(8)}} {% else %} {{ _transform(property, source, destination) | indent(4)}} {% endif %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index b41289409..dfda61d97 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -1,5 +1,5 @@ {% macro construct(property, source, initial_value=None) %} -{% if property.required and not property.nullable %} +{% if property.required %} {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% else %} {% if initial_value != None %} @@ -10,12 +10,12 @@ {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} _{{ property.python_name }} = {{source}} -if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}: +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], _{{ property.python_name }})) {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None @@ -23,9 +23,9 @@ if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{ {{ destination }} = {{ source }}.to_dict() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[{% if property.nullable %}None, {% endif %}Unset, Dict[str, Any]]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.to_dict() diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index 4c632c60a..509c7f34e 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -24,20 +24,20 @@ def _parse_{{ property.python_name }}(data: Any) -> {{ property.get_type_string( {{ property.python_name }} = _parse_{{ property.python_name }}({{ source }}) {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} -{% if not property.required %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} +{% if not property.required or property.nullable %} +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} if isinstance({{ source }}, Unset): {{ destination }} = UNSET {% endif %} -{% if property.nullable %} +{% if property.nullable or (query_parameter and not property.required) %} {% if property.required %} if {{ source }} is None: {% else %}{# There's an if UNSET statement before this #} elif {{ source }} is None: {% endif %} - {{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = None + {{ destination }} = None {% endif %} {% for inner_property in property.inner_properties_with_template() %} {% if loop.first and property.required and not property.nullable %}{# No if UNSET or if None statement before this #} diff --git a/openapi_python_client/templates/types.py b/openapi_python_client/templates/types.py index 2061b9f08..a354a2192 100644 --- a/openapi_python_client/templates/types.py +++ b/openapi_python_client/templates/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type diff --git a/pyproject.toml b/pyproject.toml index 222b69561..4be8d93db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ safety = "*" pytest-cov = "*" python-multipart = "*" flake8 = "*" +typer-cli = "^0.0.11" [tool.taskipy.tasks] check = """ @@ -55,8 +56,9 @@ isort .\ && flake8 openapi_python_client\ && safety check --bare\ && mypy openapi_python_client\ - && pytest --cov openapi_python_client tests --cov-report=term-missing\ + && task unit\ """ +unit = "pytest --cov openapi_python_client tests --cov-report=term-missing" regen = "python -m end_to_end_tests.regen_golden_record" regen_custom = "python -m end_to_end_tests.regen_golden_record custom" e2e = "pytest openapi_python_client end_to_end_tests/test_end_to_end.py" @@ -65,12 +67,7 @@ task regen\ && task regen_custom\ && task e2e\ """ -gen-setuppy = """ -poetry build \ -&& tar --strip-components=1 -xvf "$(ls -1 dist/*tar.gz | tail -1)" '*/setup.py' \ -&& isort setup.py \ -&& black setup.py -""" +docs = "typer openapi_python_client/cli.py utils docs > usage.md" [tool.black] line-length = 120 @@ -98,8 +95,5 @@ skip = [".venv", "tests/test_templates"] omit = ["openapi_python_client/templates/*"] [build-system] -requires = [ - "setuptools>=30.3.0,<50", - "poetry>=1.0" -] +requires = ["poetry>=1.0"] build-backend = "poetry.masonry.api" diff --git a/tests/test_parser/test_properties/test_init.py b/tests/test_parser/test_properties/test_init.py index 2f3c13676..2f1c71cc5 100644 --- a/tests/test_parser/test_properties/test_init.py +++ b/tests/test_parser/test_properties/test_init.py @@ -16,45 +16,55 @@ class TestProperty: - def test_get_type_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,nullable,required,no_optional,expected", + [ + (False, False, False, False, "Union[Unset, TestType]"), + (False, False, False, True, "TestType"), + (False, False, True, False, "TestType"), + (False, False, True, True, "TestType"), + (False, True, False, False, "Union[Unset, None, TestType]"), + (False, True, False, True, "TestType"), + (False, True, True, False, "Optional[TestType]"), + (False, True, True, True, "TestType"), + (True, False, False, False, "Union[Unset, None, TestType]"), + (True, False, False, True, "TestType"), + (True, False, True, False, "TestType"), + (True, False, True, True, "TestType"), + (True, True, False, False, "Union[Unset, None, TestType]"), + (True, True, False, True, "TestType"), + (True, True, True, False, "Optional[TestType]"), + (True, True, True, True, "TestType"), + ], + ) + def test_get_type_string(self, mocker, query_parameter, nullable, required, no_optional, expected): from openapi_python_client.parser.properties import Property mocker.patch.object(Property, "_type_string", "TestType") - p = Property(name="test", required=True, default=None, nullable=False) - - base_type_string = f"TestType" - - assert p.get_type_string() == base_type_string + p = Property(name="test", required=required, default=None, nullable=nullable) + assert p.get_type_string(no_optional=no_optional, query_parameter=query_parameter) == expected - p = Property(name="test", required=True, default=None, nullable=True) - assert p.get_type_string() == f"Optional[{base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - p = Property(name="test", required=False, default=None, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" - assert p.get_type_string(no_optional=True) == base_type_string - - p = Property(name="test", required=False, default=None, nullable=False) - assert p.get_type_string() == f"Union[Unset, {base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - def test_to_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,default,required,expected", + [ + (False, None, False, "test: Union[Unset, TestType] = UNSET"), + (False, None, True, "test: TestType"), + (False, "Test", False, "test: Union[Unset, TestType] = Test"), + (False, "Test", True, "test: TestType = Test"), + (True, None, False, "test: Union[Unset, None, TestType] = UNSET"), + (True, None, True, "test: TestType"), + (True, "Test", False, "test: Union[Unset, None, TestType] = Test"), + (True, "Test", True, "test: TestType = Test"), + ], + ) + def test_to_string(self, mocker, query_parameter, default, required, expected): from openapi_python_client.parser.properties import Property name = "test" - get_type_string = mocker.patch.object(Property, "get_type_string") - p = Property(name=name, required=True, default=None, nullable=False) - - assert p.to_string() == f"{name}: {get_type_string()}" - - p = Property(name=name, required=False, default=None, nullable=False) - assert p.to_string() == f"{name}: {get_type_string()} = UNSET" - - p = Property(name=name, required=True, default=None, nullable=False) - assert p.to_string() == f"{name}: {get_type_string()}" + mocker.patch.object(Property, "_type_string", "TestType") + p = Property(name=name, required=required, default=default, nullable=False) - p = Property(name=name, required=True, default="TEST", nullable=False) - assert p.to_string() == f"{name}: {get_type_string()} = TEST" + assert p.to_string(query_parameter=query_parameter) == expected def test_get_imports(self): from openapi_python_client.parser.properties import Property @@ -87,7 +97,7 @@ def test_get_type_string(self): assert p.get_type_string() == f"Optional[{base_type_string}]" p = StringProperty(name="test", required=False, default=None, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" p = StringProperty(name="test", required=False, default=None, nullable=False) assert p.get_type_string() == f"Union[Unset, {base_type_string}]" @@ -202,7 +212,7 @@ def test_get_type_string(self, mocker): assert p.get_type_string(no_optional=True) == base_type_string p = ListProperty(name="test", required=False, default=None, inner_property=inner_property, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" assert p.get_type_string(no_optional=True) == base_type_string p = ListProperty(name="test", required=False, default=None, inner_property=inner_property, nullable=False) @@ -242,7 +252,28 @@ def test_get_type_imports(self, mocker): class TestUnionProperty: - def test_get_type_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,nullable,required,no_optional,expected", + [ + (False, False, False, False, "Union[Unset, inner_type_string_1, inner_type_string_2]"), + (False, False, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, False, True, False, "Union[inner_type_string_1, inner_type_string_2]"), + (False, False, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, True, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (False, True, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, True, True, False, "Union[None, inner_type_string_1, inner_type_string_2]"), + (False, True, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (True, False, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, True, False, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, True, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (True, True, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, True, True, False, "Union[None, inner_type_string_1, inner_type_string_2]"), + (True, True, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + ], + ) + def test_get_type_string(self, mocker, query_parameter, nullable, required, no_optional, expected): from openapi_python_client.parser.properties import UnionProperty inner_property_1 = mocker.MagicMock() @@ -251,46 +282,13 @@ def test_get_type_string(self, mocker): inner_property_2.get_type_string.return_value = "inner_type_string_2" p = UnionProperty( name="test", - required=True, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=False, - ) - - base_type_string = f"Union[inner_type_string_1, inner_type_string_2]" - - assert p.get_type_string() == base_type_string - - p = UnionProperty( - name="test", - required=True, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=True, - ) - assert p.get_type_string() == f"Optional[{base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - base_type_string_with_unset = f"Union[Unset, inner_type_string_1, inner_type_string_2]" - p = UnionProperty( - name="test", - required=False, + required=required, default=None, inner_properties=[inner_property_1, inner_property_2], - nullable=True, + nullable=nullable, ) - assert p.get_type_string() == f"Optional[{base_type_string_with_unset}]" - assert p.get_type_string(no_optional=True) == base_type_string - p = UnionProperty( - name="test", - required=False, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=False, - ) - assert p.get_type_string() == base_type_string_with_unset - assert p.get_type_string(no_optional=True) == base_type_string + assert p.get_type_string(query_parameter=query_parameter, no_optional=no_optional) == expected def test_get_imports(self, mocker): from openapi_python_client.parser.properties import UnionProperty @@ -389,7 +387,7 @@ def test_get_type_string(self, mocker): reference=fake_reference, value_type=str, ) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" assert p.get_type_string(no_optional=True) == base_type_string p = properties.EnumProperty( @@ -586,7 +584,6 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), - references=[], required_properties=[], optional_properties=[], description="", @@ -603,7 +600,6 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), - references=[], required_properties=[], optional_properties=[], description="", @@ -990,25 +986,19 @@ def test__string_based_property_unsupported_format(self, mocker): def test_build_schemas(mocker): build_model_property = mocker.patch(f"{MODULE_NAME}.build_model_property") in_data = {"1": mocker.MagicMock(enum=None), "2": mocker.MagicMock(enum=None), "3": mocker.MagicMock(enum=None)} - model_1 = mocker.MagicMock() schemas_1 = mocker.MagicMock() model_2 = mocker.MagicMock() schemas_2 = mocker.MagicMock(errors=[]) - schemas_2.models = {"1": model_1, "2": model_2} - error_1 = PropertyError() + error = PropertyError() schemas_3 = mocker.MagicMock() - schemas_4 = mocker.MagicMock(errors=[]) - model_1.resolve_references.return_value = schemas_4 - error_2 = PropertyError() - model_2.resolve_references.return_value = error_2 # This loops through one for each, then again to retry the error build_model_property.side_effect = [ (model_1, schemas_1), (model_2, schemas_2), - (error_1, schemas_3), - (error_1, schemas_3), + (error, schemas_3), + (error, schemas_3), ] from openapi_python_client.parser.properties import Schemas, build_schemas @@ -1024,12 +1014,8 @@ def test_build_schemas(mocker): ] ) # schemas_3 was the last to come back from build_model_property, but it should be ignored because it's an error - model_1.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_2) - # schemas_4 came from resolving model_1 - model_2.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_4) - # resolving model_2 resulted in err, so no schemas_5 - assert result == schemas_4 - assert result.errors == [error_1, error_2] + assert result == schemas_2 + assert result.errors == [error] def test_build_parse_error_on_reference(): @@ -1103,7 +1089,6 @@ def test_build_model_property(additional_properties_schema, expected_additional_ nullable=False, default=None, reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"), - references=[], required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)], optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)], description=data.description, diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 421f40d48..410112666 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -4,9 +4,9 @@ @pytest.mark.parametrize( "no_optional,nullable,required,expected", [ - (False, False, False, "Union[MyClass, Unset]"), + (False, False, False, "Union[Unset, MyClass]"), (False, False, True, "MyClass"), - (False, True, False, "Union[Optional[MyClass], Unset]"), + (False, True, False, "Union[Unset, None, MyClass]"), (False, True, True, "Optional[MyClass]"), (True, False, False, "MyClass"), (True, False, True, "MyClass"), @@ -23,7 +23,6 @@ def test_get_type_string(no_optional, nullable, required, expected): nullable=nullable, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), - references=[], description="", optional_properties=[], required_properties=[], @@ -43,7 +42,6 @@ def test_get_imports(): nullable=True, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), - references=[], description="", optional_properties=[], required_properties=[], @@ -59,143 +57,3 @@ def test_get_imports(): "from typing import Dict", "from typing import cast", } - - -def test_resolve_references(mocker): - import openapi_python_client.schema as oai - from openapi_python_client.parser.properties import build_model_property - - schemas = { - "RefA": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["String"], - properties={ - "String": oai.Schema.construct(type="string"), - "Enum": oai.Schema.construct(type="string", enum=["aValue"]), - "DateTime": oai.Schema.construct(type="string", format="date-time"), - }, - ), - "RefB": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["DateTime"], - properties={ - "Int": oai.Schema.construct(type="integer"), - "DateTime": oai.Schema.construct(type="string", format="date-time"), - "Float": oai.Schema.construct(type="number", format="float"), - }, - ), - # Intentionally no properties defined - "RefC": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - ), - } - - model_schema = oai.Schema.construct( - allOf=[ - oai.Reference.construct(ref="#/components/schemas/RefA"), - oai.Reference.construct(ref="#/components/schemas/RefB"), - oai.Reference.construct(ref="#/components/schemas/RefC"), - oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["Float"], - properties={ - "String": oai.Schema.construct(type="string"), - "Float": oai.Schema.construct(type="number", format="float"), - }, - ), - ] - ) - - components = {**schemas, "Model": model_schema} - - from openapi_python_client.parser.properties import Schemas - - schemas_holder = Schemas() - model, schemas_holder = build_model_property( - data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None - ) - model.resolve_references(components, schemas_holder) - assert sorted(p.name for p in model.required_properties) == ["DateTime", "Float", "String"] - assert all(p.required for p in model.required_properties) - assert sorted(p.name for p in model.optional_properties) == ["Enum", "Int"] - assert all(not p.required for p in model.optional_properties) - - -def test_resolve_references_nested_allof(mocker): - import openapi_python_client.schema as oai - from openapi_python_client.parser.properties import build_model_property - - schemas = { - "RefA": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["String"], - properties={ - "String": oai.Schema.construct(type="string"), - "Enum": oai.Schema.construct(type="string", enum=["aValue"]), - "DateTime": oai.Schema.construct(type="string", format="date-time"), - }, - ), - "RefB": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["DateTime"], - properties={ - "Int": oai.Schema.construct(type="integer"), - "DateTime": oai.Schema.construct(type="string", format="date-time"), - "Float": oai.Schema.construct(type="number", format="float"), - }, - ), - # Intentionally no properties defined - "RefC": oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - ), - } - - model_schema = oai.Schema.construct( - type="object", - properties={ - "Key": oai.Schema.construct( - allOf=[ - oai.Reference.construct(ref="#/components/schemas/RefA"), - oai.Reference.construct(ref="#/components/schemas/RefB"), - oai.Reference.construct(ref="#/components/schemas/RefC"), - oai.Schema.construct( - title=mocker.MagicMock(), - description=mocker.MagicMock(), - required=["Float"], - properties={ - "String": oai.Schema.construct(type="string"), - "Float": oai.Schema.construct(type="number", format="float"), - }, - ), - ] - ), - }, - ) - - components = {**schemas, "Model": model_schema} - - from openapi_python_client.parser.properties import ModelProperty, Schemas - - schemas_holder = Schemas() - model, schemas_holder = build_model_property( - data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None - ) - model.resolve_references(components, schemas_holder) - assert sorted(p.name for p in model.required_properties) == [] - assert sorted(p.name for p in model.optional_properties) == ["Key"] - assert all(not p.required for p in model.optional_properties) - - key_property = model.optional_properties[0] - assert isinstance(key_property, ModelProperty) - key_property.resolve_references(components, schemas_holder) - assert sorted(p.name for p in key_property.required_properties) == ["DateTime", "Float", "String"] - assert all(p.required for p in key_property.required_properties) - assert sorted(p.name for p in key_property.optional_properties) == ["Enum", "Int"] - assert all(not p.required for p in key_property.optional_properties) diff --git a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py index cf8780024..be32cfbd3 100644 --- a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py +++ b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py @@ -6,7 +6,7 @@ some_source = date(2020, 10, 12) -some_destination: Union[Unset, str] = UNSET +some_destination: Union[Unset, None, str] = UNSET if not isinstance(some_source, Unset): some_destination = some_source.isoformat() if some_source else None From a5d09f412a7520040efd763bb3d3c4b08f0d9975 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:11:39 -0500 Subject: [PATCH 08/18] Regenerate tests --- .../api/tests/defaults_tests_defaults_post.py | 114 +++++---- ...tional_value_tests_optional_query_param.py | 11 +- .../custom_e2e/models/__init__.py | 4 - .../custom_e2e/models/a_model.py | 52 +--- .../custom_e2e/models/a_model_model.py | 85 ------- .../models/a_model_not_required_model.py | 85 ------- .../a_model_not_required_nullable_model.py | 85 ------- .../models/a_model_nullable_model.py | 85 ------- ...el_with_primitive_additional_properties.py | 6 +- .../models/model_with_union_property.py | 6 +- .../golden-record-custom/custom_e2e/types.py | 5 +- .../api/tests/defaults_tests_defaults_post.py | 232 ++++++++++-------- ...tional_value_tests_optional_query_param.py | 19 +- .../my_test_api_client/models/__init__.py | 4 - .../my_test_api_client/models/a_model.py | 52 +--- .../models/a_model_model.py | 85 ------- .../models/a_model_not_required_model.py | 85 ------- .../a_model_not_required_nullable_model.py | 85 ------- .../models/a_model_nullable_model.py | 85 ------- ...el_with_primitive_additional_properties.py | 6 +- .../models/model_with_union_property.py | 6 +- .../golden-record/my_test_api_client/types.py | 5 +- 22 files changed, 243 insertions(+), 959 deletions(-) delete mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py delete mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py delete mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py delete mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py delete mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index f87ad3e1b..4a2c9074b 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -7,13 +7,12 @@ Client = httpx.Client import datetime -from typing import Dict, List, Union +from typing import Dict, List, Optional, Union from dateutil.parser import isoparse from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError -from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Unset @@ -41,83 +40,106 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def httpx_request( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: - json_datetime_prop: Union[Unset, str] = UNSET - if not isinstance(datetime_prop, Unset): - json_datetime_prop = datetime_prop.isoformat() + json_not_required_not_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_not_nullable_datetime_prop, Unset): + json_not_required_not_nullable_datetime_prop = ( + not_required_not_nullable_datetime_prop.isoformat() if not_required_not_nullable_datetime_prop else None + ) - json_date_prop: Union[Unset, str] = UNSET + json_not_required_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_nullable_datetime_prop, Unset): + json_not_required_nullable_datetime_prop = ( + not_required_nullable_datetime_prop.isoformat() if not_required_nullable_datetime_prop else None + ) + + json_required_not_nullable_datetime_prop = required_not_nullable_datetime_prop.isoformat() + + json_required_nullable_datetime_prop = ( + required_nullable_datetime_prop.isoformat() if required_nullable_datetime_prop else None + ) + + json_date_prop: Union[Unset, None, str] = UNSET if not isinstance(date_prop, Unset): - json_date_prop = date_prop.isoformat() + json_date_prop = date_prop.isoformat() if date_prop else None - json_list_prop: Union[Unset, List[Any]] = UNSET + json_list_prop: Union[Unset, None, List[Any]] = UNSET if not isinstance(list_prop, Unset): - json_list_prop = [] - for list_prop_item_data in list_prop: - list_prop_item = list_prop_item_data.value + if list_prop is None: + json_list_prop = None + else: + json_list_prop = [] + for list_prop_item_data in list_prop: + list_prop_item = list_prop_item_data.value - json_list_prop.append(list_prop_item) + json_list_prop.append(list_prop_item) - json_union_prop: Union[Unset, float, str] + json_union_prop: Union[Unset, None, float, str] if isinstance(union_prop, Unset): json_union_prop = UNSET + elif union_prop is None: + json_union_prop = None else: json_union_prop = union_prop - json_union_prop_with_ref: Union[Unset, float, AnEnum] + json_union_prop_with_ref: Union[Unset, None, float, int] if isinstance(union_prop_with_ref, Unset): json_union_prop_with_ref = UNSET + elif union_prop_with_ref is None: + json_union_prop_with_ref = None elif isinstance(union_prop_with_ref, AnEnum): json_union_prop_with_ref = UNSET if not isinstance(union_prop_with_ref, Unset): - json_union_prop_with_ref = union_prop_with_ref + json_union_prop_with_ref = union_prop_with_ref.value else: json_union_prop_with_ref = union_prop_with_ref - json_enum_prop: Union[Unset, AnEnum] = UNSET + json_enum_prop: Union[Unset, None, int] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop - - json_model_prop: Union[Unset, Dict[str, Any]] = UNSET - if not isinstance(model_prop, Unset): - json_model_prop = model_prop.to_dict() + json_enum_prop = enum_prop.value if enum_prop else None - params: Dict[str, Any] = {} - if not isinstance(string_prop, Unset) and string_prop is not None: + params: Dict[str, Any] = { + "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, + } + if string_prop is not UNSET and string_prop is not None: params["string_prop"] = string_prop - if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: - params["datetime_prop"] = json_datetime_prop - if not isinstance(json_date_prop, Unset) and json_date_prop is not None: + if not_required_not_nullable_datetime_prop is not UNSET and not_required_not_nullable_datetime_prop is not None: + params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop + if not_required_nullable_datetime_prop is not UNSET and not_required_nullable_datetime_prop is not None: + params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop + if required_nullable_datetime_prop is not None: + params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop + if date_prop is not UNSET and date_prop is not None: params["date_prop"] = json_date_prop - if not isinstance(float_prop, Unset) and float_prop is not None: + if float_prop is not UNSET and float_prop is not None: params["float_prop"] = float_prop - if not isinstance(int_prop, Unset) and int_prop is not None: + if int_prop is not UNSET and int_prop is not None: params["int_prop"] = int_prop - if not isinstance(boolean_prop, Unset) and boolean_prop is not None: + if boolean_prop is not UNSET and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if not isinstance(json_list_prop, Unset) and json_list_prop is not None: + if list_prop is not UNSET and list_prop is not None: params["list_prop"] = json_list_prop - if not isinstance(json_union_prop, Unset) and json_union_prop is not None: + if union_prop is not UNSET and union_prop is not None: params["union_prop"] = json_union_prop - if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: + if union_prop_with_ref is not UNSET and union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: + if enum_prop is not UNSET and enum_prop is not None: params["enum_prop"] = json_enum_prop - if not isinstance(json_model_prop, Unset) and json_model_prop is not None: - params.update(json_model_prop) response = client.request( "post", diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py index 616dc4252..8ff5a52a3 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py @@ -36,15 +36,18 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def httpx_request( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: - json_query_param: Union[Unset, List[Any]] = UNSET + json_query_param: Union[Unset, None, List[Any]] = UNSET if not isinstance(query_param, Unset): - json_query_param = query_param + if query_param is None: + json_query_param = None + else: + json_query_param = query_param params: Dict[str, Any] = {} - if not isinstance(json_query_param, Unset) and json_query_param is not None: + if query_param is not UNSET and query_param is not None: params["query_param"] = json_query_param response = client.request( diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py index 6f5ac7423..d3ca924b3 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py @@ -1,10 +1,6 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel -from .a_model_model import AModelModel -from .a_model_not_required_model import AModelNotRequiredModel -from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel -from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 15a7cc68c..f811d4712 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -4,10 +4,6 @@ import attr from dateutil.parser import isoparse -from ..models.a_model_model import AModelModel -from ..models.a_model_not_required_model import AModelNotRequiredModel -from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel -from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -21,16 +17,12 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str - model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] - nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET - not_required_nullable: Union[Unset, Optional[str]] = UNSET + not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -43,8 +35,6 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable - model = self.model.to_dict() - nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -62,17 +52,6 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable - nullable_model = self.nullable_model.to_dict() if self.nullable_model else None - - not_required_model: Union[Unset, Dict[str, Any]] = UNSET - if not isinstance(self.not_required_model, Unset): - not_required_model = self.not_required_model.to_dict() - - not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET - if not isinstance(self.not_required_nullable_model, Unset): - not_required_nullable_model = ( - self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None - ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -81,10 +60,8 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, - "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, - "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -95,10 +72,6 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable - if not_required_model is not UNSET: - field_dict["not_required_model"] = not_required_model - if not_required_nullable_model is not UNSET: - field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -126,8 +99,6 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") - model = AModelModel.from_dict(d.pop("model")) - nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -153,38 +124,17 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) - nullable_model = None - _nullable_model = d.pop("nullable_model") - if _nullable_model is not None: - nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) - - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - _not_required_model = d.pop("not_required_model", UNSET) - if not isinstance(_not_required_model, Unset): - not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) - - not_required_nullable_model = None - _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) - if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_model) - ) - a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, - model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, - nullable_model=nullable_model, - not_required_model=not_required_model, - not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py deleted file mode 100644 index c1a00c152..000000000 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_model = AModelModel( - a_property=a_property, - ) - - a_model_model.additional_properties = d - return a_model_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py deleted file mode 100644 index adecb4225..000000000 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNotRequiredModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_not_required_model = AModelNotRequiredModel( - a_property=a_property, - ) - - a_model_not_required_model.additional_properties = d - return a_model_not_required_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py deleted file mode 100644 index 9de2e3798..000000000 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNotRequiredNullableModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_not_required_nullable_model = AModelNotRequiredNullableModel( - a_property=a_property, - ) - - a_model_not_required_nullable_model.additional_properties = d - return a_model_not_required_nullable_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py deleted file mode 100644 index cbcf120f8..000000000 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNullableModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_nullable_model = AModelNullableModel( - a_property=a_property, - ) - - a_model_nullable_model.additional_properties = d - return a_model_nullable_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index 797c1ce31..feb30878d 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -12,7 +12,7 @@ class ModelWithPrimitiveAdditionalProperties: """ """ - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET additional_properties: Dict[str, str] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -31,9 +31,9 @@ def to_dict(self) -> Dict[str, Any]: @staticmethod def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if not isinstance(_a_date_holder, Unset): + if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index cbecc7c90..35bc2a853 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -14,18 +14,18 @@ class ModelWithUnionProperty: a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update({}) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/types.py b/end_to_end_tests/golden-record-custom/custom_e2e/types.py index 2061b9f08..a354a2192 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/types.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index ff6ef2409..1f865570d 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -7,93 +7,115 @@ from ...client import Client from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError -from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Response, Unset def _get_kwargs( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/defaults".format(client.base_url) headers: Dict[str, Any] = client.get_headers() - json_datetime_prop: Union[Unset, str] = UNSET - if not isinstance(datetime_prop, Unset): - json_datetime_prop = datetime_prop.isoformat() + json_not_required_not_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_not_nullable_datetime_prop, Unset): + json_not_required_not_nullable_datetime_prop = ( + not_required_not_nullable_datetime_prop.isoformat() if not_required_not_nullable_datetime_prop else None + ) + + json_not_required_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_nullable_datetime_prop, Unset): + json_not_required_nullable_datetime_prop = ( + not_required_nullable_datetime_prop.isoformat() if not_required_nullable_datetime_prop else None + ) + + json_required_not_nullable_datetime_prop = required_not_nullable_datetime_prop.isoformat() - json_date_prop: Union[Unset, str] = UNSET + json_required_nullable_datetime_prop = ( + required_nullable_datetime_prop.isoformat() if required_nullable_datetime_prop else None + ) + + json_date_prop: Union[Unset, None, str] = UNSET if not isinstance(date_prop, Unset): - json_date_prop = date_prop.isoformat() + json_date_prop = date_prop.isoformat() if date_prop else None - json_list_prop: Union[Unset, List[Any]] = UNSET + json_list_prop: Union[Unset, None, List[Any]] = UNSET if not isinstance(list_prop, Unset): - json_list_prop = [] - for list_prop_item_data in list_prop: - list_prop_item = list_prop_item_data.value + if list_prop is None: + json_list_prop = None + else: + json_list_prop = [] + for list_prop_item_data in list_prop: + list_prop_item = list_prop_item_data.value - json_list_prop.append(list_prop_item) + json_list_prop.append(list_prop_item) - json_union_prop: Union[Unset, float, str] + json_union_prop: Union[Unset, None, float, str] if isinstance(union_prop, Unset): json_union_prop = UNSET + elif union_prop is None: + json_union_prop = None else: json_union_prop = union_prop - json_union_prop_with_ref: Union[Unset, float, AnEnum] + json_union_prop_with_ref: Union[Unset, None, float, int] if isinstance(union_prop_with_ref, Unset): json_union_prop_with_ref = UNSET + elif union_prop_with_ref is None: + json_union_prop_with_ref = None elif isinstance(union_prop_with_ref, AnEnum): json_union_prop_with_ref = UNSET if not isinstance(union_prop_with_ref, Unset): - json_union_prop_with_ref = union_prop_with_ref + json_union_prop_with_ref = union_prop_with_ref.value else: json_union_prop_with_ref = union_prop_with_ref - json_enum_prop: Union[Unset, AnEnum] = UNSET + json_enum_prop: Union[Unset, None, int] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop + json_enum_prop = enum_prop.value if enum_prop else None - json_model_prop: Union[Unset, Dict[str, Any]] = UNSET - if not isinstance(model_prop, Unset): - json_model_prop = model_prop.to_dict() - - params: Dict[str, Any] = {} - if not isinstance(string_prop, Unset) and string_prop is not None: + params: Dict[str, Any] = { + "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, + } + if string_prop is not UNSET and string_prop is not None: params["string_prop"] = string_prop - if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: - params["datetime_prop"] = json_datetime_prop - if not isinstance(json_date_prop, Unset) and json_date_prop is not None: + if not_required_not_nullable_datetime_prop is not UNSET and not_required_not_nullable_datetime_prop is not None: + params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop + if not_required_nullable_datetime_prop is not UNSET and not_required_nullable_datetime_prop is not None: + params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop + if required_nullable_datetime_prop is not None: + params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop + if date_prop is not UNSET and date_prop is not None: params["date_prop"] = json_date_prop - if not isinstance(float_prop, Unset) and float_prop is not None: + if float_prop is not UNSET and float_prop is not None: params["float_prop"] = float_prop - if not isinstance(int_prop, Unset) and int_prop is not None: + if int_prop is not UNSET and int_prop is not None: params["int_prop"] = int_prop - if not isinstance(boolean_prop, Unset) and boolean_prop is not None: + if boolean_prop is not UNSET and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if not isinstance(json_list_prop, Unset) and json_list_prop is not None: + if list_prop is not UNSET and list_prop is not None: params["list_prop"] = json_list_prop - if not isinstance(json_union_prop, Unset) and json_union_prop is not None: + if union_prop is not UNSET and union_prop is not None: params["union_prop"] = json_union_prop - if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: + if union_prop_with_ref is not UNSET and union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: + if enum_prop is not UNSET and enum_prop is not None: params["enum_prop"] = json_enum_prop - if not isinstance(json_model_prop, Unset) and json_model_prop is not None: - params.update(json_model_prop) return { "url": url, @@ -128,22 +150,27 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def sync_detailed( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -152,7 +179,6 @@ def sync_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, - model_prop=model_prop, ) response = httpx.post( @@ -165,24 +191,29 @@ def sync_detailed( def sync( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ return sync_detailed( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -191,29 +222,33 @@ def sync( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, - model_prop=model_prop, ).parsed async def asyncio_detailed( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -222,7 +257,6 @@ async def asyncio_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, - model_prop=model_prop, ) async with httpx.AsyncClient() as _client: @@ -234,17 +268,19 @@ async def asyncio_detailed( async def asyncio( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -252,7 +288,10 @@ async def asyncio( await asyncio_detailed( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -261,6 +300,5 @@ async def asyncio( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, - model_prop=model_prop, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 576a770fe..2c14c2949 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -10,18 +10,21 @@ def _get_kwargs( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/optional_query_param/".format(client.base_url) headers: Dict[str, Any] = client.get_headers() - json_query_param: Union[Unset, List[Any]] = UNSET + json_query_param: Union[Unset, None, List[Any]] = UNSET if not isinstance(query_param, Unset): - json_query_param = query_param + if query_param is None: + json_query_param = None + else: + json_query_param = query_param params: Dict[str, Any] = {} - if not isinstance(json_query_param, Unset) and json_query_param is not None: + if query_param is not UNSET and query_param is not None: params["query_param"] = json_query_param return { @@ -57,7 +60,7 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def sync_detailed( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -74,7 +77,7 @@ def sync_detailed( def sync( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ Test optional query parameters """ @@ -87,7 +90,7 @@ def sync( async def asyncio_detailed( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -103,7 +106,7 @@ async def asyncio_detailed( async def asyncio( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ Test optional query parameters """ diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index 6f5ac7423..d3ca924b3 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -1,10 +1,6 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel -from .a_model_model import AModelModel -from .a_model_not_required_model import AModelNotRequiredModel -from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel -from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 15a7cc68c..f811d4712 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -4,10 +4,6 @@ import attr from dateutil.parser import isoparse -from ..models.a_model_model import AModelModel -from ..models.a_model_not_required_model import AModelNotRequiredModel -from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel -from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -21,16 +17,12 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str - model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] - nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET - not_required_nullable: Union[Unset, Optional[str]] = UNSET + not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -43,8 +35,6 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable - model = self.model.to_dict() - nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -62,17 +52,6 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable - nullable_model = self.nullable_model.to_dict() if self.nullable_model else None - - not_required_model: Union[Unset, Dict[str, Any]] = UNSET - if not isinstance(self.not_required_model, Unset): - not_required_model = self.not_required_model.to_dict() - - not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET - if not isinstance(self.not_required_nullable_model, Unset): - not_required_nullable_model = ( - self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None - ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -81,10 +60,8 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, - "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, - "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -95,10 +72,6 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable - if not_required_model is not UNSET: - field_dict["not_required_model"] = not_required_model - if not_required_nullable_model is not UNSET: - field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -126,8 +99,6 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") - model = AModelModel.from_dict(d.pop("model")) - nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -153,38 +124,17 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) - nullable_model = None - _nullable_model = d.pop("nullable_model") - if _nullable_model is not None: - nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) - - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - _not_required_model = d.pop("not_required_model", UNSET) - if not isinstance(_not_required_model, Unset): - not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) - - not_required_nullable_model = None - _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) - if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_model) - ) - a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, - model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, - nullable_model=nullable_model, - not_required_model=not_required_model, - not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py deleted file mode 100644 index c1a00c152..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_model = AModelModel( - a_property=a_property, - ) - - a_model_model.additional_properties = d - return a_model_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py deleted file mode 100644 index adecb4225..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNotRequiredModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_not_required_model = AModelNotRequiredModel( - a_property=a_property, - ) - - a_model_not_required_model.additional_properties = d - return a_model_not_required_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py deleted file mode 100644 index 9de2e3798..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNotRequiredNullableModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_not_required_nullable_model = AModelNotRequiredNullableModel( - a_property=a_property, - ) - - a_model_not_required_nullable_model.additional_properties = d - return a_model_not_required_nullable_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py deleted file mode 100644 index cbcf120f8..000000000 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, Dict, List, Union - -import attr - -from ..models.an_enum import AnEnum -from ..models.an_int_enum import AnIntEnum -from ..types import UNSET, Unset - - -@attr.s(auto_attribs=True) -class AModelNullableModel: - """ """ - - a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET - additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) - - def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] - if isinstance(self.a_property, Unset): - a_property = UNSET - elif isinstance(self.a_property, AnEnum): - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - else: - a_property = UNSET - if not isinstance(self.a_property, Unset): - a_property = self.a_property - - field_dict: Dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if a_property is not UNSET: - field_dict["a_property"] = a_property - - return field_dict - - @staticmethod - def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": - d = src_dict.copy() - - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data - a_property: Union[Unset, AnEnum, AnIntEnum] - try: - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnEnum(_a_property) - - return a_property - except: # noqa: E722 - pass - a_property = UNSET - _a_property = data - if _a_property is not None: - a_property = AnIntEnum(_a_property) - - return a_property - - a_property = _parse_a_property(d.pop("a_property", UNSET)) - - a_model_nullable_model = AModelNullableModel( - a_property=a_property, - ) - - a_model_nullable_model.additional_properties = d - return a_model_nullable_model - - @property - def additional_keys(self) -> List[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index 797c1ce31..feb30878d 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -12,7 +12,7 @@ class ModelWithPrimitiveAdditionalProperties: """ """ - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET additional_properties: Dict[str, str] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -31,9 +31,9 @@ def to_dict(self) -> Dict[str, Any]: @staticmethod def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if not isinstance(_a_date_holder, Unset): + if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index cbecc7c90..35bc2a853 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -14,18 +14,18 @@ class ModelWithUnionProperty: a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update({}) diff --git a/end_to_end_tests/golden-record/my_test_api_client/types.py b/end_to_end_tests/golden-record/my_test_api_client/types.py index 2061b9f08..a354a2192 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/types.py +++ b/end_to_end_tests/golden-record/my_test_api_client/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type From b33df4d67af350dc710bd9aa59f35561b7e5c4a9 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:19:49 -0500 Subject: [PATCH 09/18] Undo diffs --- .../api/tests/defaults_tests_defaults_post.py | 8 ++ .../custom_e2e/models/__init__.py | 4 + .../custom_e2e/models/a_model.py | 47 ++++++++++ .../custom_e2e/models/a_model_model.py | 85 +++++++++++++++++++ .../models/a_model_not_required_model.py | 85 +++++++++++++++++++ .../a_model_not_required_nullable_model.py | 85 +++++++++++++++++++ .../models/a_model_nullable_model.py | 85 +++++++++++++++++++ .../api/tests/defaults_tests_defaults_post.py | 16 ++++ .../my_test_api_client/models/__init__.py | 4 + .../my_test_api_client/models/a_model.py | 47 ++++++++++ .../models/a_model_model.py | 85 +++++++++++++++++++ .../models/a_model_not_required_model.py | 85 +++++++++++++++++++ .../a_model_not_required_nullable_model.py | 85 +++++++++++++++++++ .../models/a_model_nullable_model.py | 85 +++++++++++++++++++ end_to_end_tests/openapi.json | 46 +++++++++- .../parser/properties/__init__.py | 32 +++++-- .../parser/properties/model_property.py | 55 +++++++++++- .../parser/properties/property.py | 1 + pyproject.toml | 13 ++- 19 files changed, 942 insertions(+), 11 deletions(-) create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py create mode 100644 end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py create mode 100644 end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index 4a2c9074b..e4b71e321 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -13,6 +13,7 @@ from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError +from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Unset @@ -53,6 +54,7 @@ def httpx_request( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: json_not_required_not_nullable_datetime_prop: Union[Unset, None, str] = UNSET @@ -113,6 +115,10 @@ def httpx_request( if not isinstance(enum_prop, Unset): json_enum_prop = enum_prop.value if enum_prop else None + json_model_prop: Union[Unset, None, Dict[str, Any]] = UNSET + if not isinstance(model_prop, Unset): + json_model_prop = model_prop.to_dict() if model_prop else None + params: Dict[str, Any] = { "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, } @@ -140,6 +146,8 @@ def httpx_request( params["union_prop_with_ref"] = json_union_prop_with_ref if enum_prop is not UNSET and enum_prop is not None: params["enum_prop"] = json_enum_prop + if model_prop is not UNSET and model_prop is not None: + params["model_prop"] = json_model_prop response = client.request( "post", diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py index d3ca924b3..6f5ac7423 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/__init__.py @@ -1,6 +1,10 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel +from .a_model_model import AModelModel +from .a_model_not_required_model import AModelNotRequiredModel +from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index f811d4712..3e46992a4 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -4,6 +4,10 @@ import attr from dateutil.parser import isoparse +from ..models.a_model_model import AModelModel +from ..models.a_model_not_required_model import AModelNotRequiredModel +from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -17,12 +21,16 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str + model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] + nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -35,6 +43,8 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable + model = self.model.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -52,6 +62,17 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable + nullable_model = self.nullable_model.to_dict() if self.nullable_model else None + + not_required_model: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_model, Unset): + not_required_model = self.not_required_model.to_dict() + + not_required_nullable_model: Union[Unset, None, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_nullable_model, Unset): + not_required_nullable_model = ( + self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None + ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -60,8 +81,10 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, + "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, + "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -72,6 +95,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable + if not_required_model is not UNSET: + field_dict["not_required_model"] = not_required_model + if not_required_nullable_model is not UNSET: + field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -99,6 +126,8 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") + model = AModelModel.from_dict(d.pop("model")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -124,17 +153,35 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) + nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + _not_required_model = d.pop("not_required_model", UNSET) + if _not_required_model is not None and not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + + not_required_nullable_model = None + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_model) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, + model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, + nullable_model=nullable_model, + not_required_model=not_required_model, + not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py new file mode 100644 index 000000000..0700798c8 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_model = AModelModel( + a_property=a_property, + ) + + a_model_model.additional_properties = d + return a_model_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py new file mode 100644 index 000000000..a08f547aa --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_model = AModelNotRequiredModel( + a_property=a_property, + ) + + a_model_not_required_model.additional_properties = d + return a_model_not_required_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py new file mode 100644 index 000000000..52ee2ddc3 --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_nullable_model = AModelNotRequiredNullableModel( + a_property=a_property, + ) + + a_model_not_required_nullable_model.additional_properties = d + return a_model_not_required_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py new file mode 100644 index 000000000..2f21cc5ac --- /dev/null +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_nullable_model = AModelNullableModel( + a_property=a_property, + ) + + a_model_nullable_model.additional_properties = d + return a_model_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index 1f865570d..540f68b44 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -7,6 +7,7 @@ from ...client import Client from ...models.an_enum import AnEnum from ...models.http_validation_error import HTTPValidationError +from ...models.model_with_union_property import ModelWithUnionProperty from ...types import UNSET, Response, Unset @@ -26,6 +27,7 @@ def _get_kwargs( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/defaults".format(client.base_url) @@ -89,6 +91,10 @@ def _get_kwargs( if not isinstance(enum_prop, Unset): json_enum_prop = enum_prop.value if enum_prop else None + json_model_prop: Union[Unset, None, Dict[str, Any]] = UNSET + if not isinstance(model_prop, Unset): + json_model_prop = model_prop.to_dict() if model_prop else None + params: Dict[str, Any] = { "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, } @@ -116,6 +122,8 @@ def _get_kwargs( params["union_prop_with_ref"] = json_union_prop_with_ref if enum_prop is not UNSET and enum_prop is not None: params["enum_prop"] = json_enum_prop + if model_prop is not UNSET and model_prop is not None: + params["model_prop"] = json_model_prop return { "url": url, @@ -163,6 +171,7 @@ def sync_detailed( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -179,6 +188,7 @@ def sync_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) response = httpx.post( @@ -204,6 +214,7 @@ def sync( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -222,6 +233,7 @@ def sync( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ).parsed @@ -241,6 +253,7 @@ async def asyncio_detailed( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -257,6 +270,7 @@ async def asyncio_detailed( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) async with httpx.AsyncClient() as _client: @@ -281,6 +295,7 @@ async def asyncio( union_prop: Union[Unset, None, float, str] = "not a float", union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -300,5 +315,6 @@ async def asyncio( union_prop=union_prop, union_prop_with_ref=union_prop_with_ref, enum_prop=enum_prop, + model_prop=model_prop, ) ).parsed diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py index d3ca924b3..6f5ac7423 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/__init__.py @@ -1,6 +1,10 @@ """ Contains all the data models used in inputs/outputs """ from .a_model import AModel +from .a_model_model import AModelModel +from .a_model_not_required_model import AModelNotRequiredModel +from .a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from .a_model_nullable_model import AModelNullableModel from .an_enum import AnEnum from .an_int_enum import AnIntEnum from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index f811d4712..3e46992a4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -4,6 +4,10 @@ import attr from dateutil.parser import isoparse +from ..models.a_model_model import AModelModel +from ..models.a_model_not_required_model import AModelNotRequiredModel +from ..models.a_model_not_required_nullable_model import AModelNotRequiredNullableModel +from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum from ..types import UNSET, Unset @@ -17,12 +21,16 @@ class AModel: a_camel_date_time: Union[datetime.datetime, datetime.date] a_date: datetime.date required_not_nullable: str + model: AModelModel a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] + nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -35,6 +43,8 @@ def to_dict(self) -> Dict[str, Any]: a_date = self.a_date.isoformat() required_not_nullable = self.required_not_nullable + model = self.model.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -52,6 +62,17 @@ def to_dict(self) -> Dict[str, Any]: required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable + nullable_model = self.nullable_model.to_dict() if self.nullable_model else None + + not_required_model: Union[Unset, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_model, Unset): + not_required_model = self.not_required_model.to_dict() + + not_required_nullable_model: Union[Unset, None, Dict[str, Any]] = UNSET + if not isinstance(self.not_required_nullable_model, Unset): + not_required_nullable_model = ( + self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None + ) field_dict: Dict[str, Any] = {} field_dict.update( @@ -60,8 +81,10 @@ def to_dict(self) -> Dict[str, Any]: "aCamelDateTime": a_camel_date_time, "a_date": a_date, "required_not_nullable": required_not_nullable, + "model": model, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, + "nullable_model": nullable_model, } ) if nested_list_of_enums is not UNSET: @@ -72,6 +95,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: field_dict["not_required_not_nullable"] = not_required_not_nullable + if not_required_model is not UNSET: + field_dict["not_required_model"] = not_required_model + if not_required_nullable_model is not UNSET: + field_dict["not_required_nullable_model"] = not_required_nullable_model return field_dict @@ -99,6 +126,8 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat required_not_nullable = d.pop("required_not_nullable") + model = AModelModel.from_dict(d.pop("model")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -124,17 +153,35 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) + nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + _not_required_model = d.pop("not_required_model", UNSET) + if _not_required_model is not None and not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + + not_required_nullable_model = None + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_model) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, + model=model, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, + nullable_model=nullable_model, + not_required_model=not_required_model, + not_required_nullable_model=not_required_nullable_model, ) return a_model diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py new file mode 100644 index 000000000..0700798c8 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_model = AModelModel( + a_property=a_property, + ) + + a_model_model.additional_properties = d + return a_model_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py new file mode 100644 index 000000000..a08f547aa --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_model = AModelNotRequiredModel( + a_property=a_property, + ) + + a_model_not_required_model.additional_properties = d + return a_model_not_required_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py new file mode 100644 index 000000000..52ee2ddc3 --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNotRequiredNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_not_required_nullable_model = AModelNotRequiredNullableModel( + a_property=a_property, + ) + + a_model_not_required_nullable_model.additional_properties = d + return a_model_not_required_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py new file mode 100644 index 000000000..2f21cc5ac --- /dev/null +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -0,0 +1,85 @@ +from typing import Any, Dict, List, Union + +import attr + +from ..models.an_enum import AnEnum +from ..models.an_int_enum import AnIntEnum +from ..types import UNSET, Unset + + +@attr.s(auto_attribs=True) +class AModelNullableModel: + """ """ + + a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET + additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + a_property: Union[Unset, int] + if isinstance(self.a_property, Unset): + a_property = UNSET + elif isinstance(self.a_property, AnEnum): + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + else: + a_property = UNSET + if not isinstance(self.a_property, Unset): + a_property = self.a_property.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if a_property is not UNSET: + field_dict["a_property"] = a_property + + return field_dict + + @staticmethod + def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": + d = src_dict.copy() + + def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: + data = None if isinstance(data, Unset) else data + a_property: Union[Unset, AnEnum, AnIntEnum] + try: + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnEnum(_a_property) + + return a_property + except: # noqa: E722 + pass + a_property = UNSET + _a_property = data + if _a_property is not None: + a_property = AnIntEnum(_a_property) + + return a_property + + a_property = _parse_a_property(d.pop("a_property", UNSET)) + + a_model_nullable_model = AModelNullableModel( + a_property=a_property, + ) + + a_model_nullable_model.additional_properties = d + return a_model_nullable_model + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 931fc481e..6d7d15c6c 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -433,6 +433,14 @@ }, "name": "enum_prop", "in": "query" + }, + { + "required": false, + "schema": { + "$ref": "#/components/schemas/ModelWithUnionProperty" + }, + "name": "model_prop", + "in": "query" } ], "responses": { @@ -659,7 +667,7 @@ "schemas": { "AModel": { "title": "AModel", - "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable"], + "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable", "model", "nullable_model"], "type": "object", "properties": { "an_enum_value": { @@ -723,6 +731,42 @@ "title": "NOT Required AND NOT Nullable", "type": "string", "nullable": false + }, + "model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "nullable_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true + }, + "not_required_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "not_required_nullable_model": { + "type": "object", + "allOf": [ + { + "ref": "#/components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true } }, "description": "A Model for testing all the ways custom objects can be used ", diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index e3a3f69b7..a5ebf00d4 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -272,13 +272,23 @@ def build_model_property( required_properties: List[Property] = [] optional_properties: List[Property] = [] relative_imports: Set[str] = set() + references: List[oai.Reference] = [] class_name = data.title or name if parent_name: class_name = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_name)}" ref = Reference.from_ref(class_name) - for key, value in (data.properties or {}).items(): + all_props = data.properties or {} + if not isinstance(data, oai.Reference) and data.allOf: + for sub_prop in data.allOf: + if isinstance(sub_prop, oai.Reference): + references += [sub_prop] + else: + all_props.update(sub_prop.properties or {}) + required_set.update(sub_prop.required or []) + + for key, value in all_props.items(): prop_required = key in required_set prop, schemas = property_from_data( name=key, required=prop_required, data=value, schemas=schemas, parent_name=class_name @@ -314,6 +324,7 @@ def build_model_property( prop = ModelProperty( reference=ref, + references=references, required_properties=required_properties, optional_properties=optional_properties, relative_imports=relative_imports, @@ -471,9 +482,7 @@ def _property_from_data( ) if data.anyOf or data.oneOf: return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - if not data.type: - return NoneProperty(name=name, required=required, nullable=False, default=None), schemas - + if data.type == "string": return _string_based_property(name=name, required=required, data=data), schemas elif data.type == "number": @@ -508,8 +517,10 @@ def _property_from_data( ) elif data.type == "array": return build_list_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - elif data.type == "object": + elif data.type == "object" or data.allOf: return build_model_property(data=data, name=name, schemas=schemas, required=required, parent_name=parent_name) + elif not data.type: + return NoneProperty(name=name, required=required, nullable=False, default=None), schemas return PropertyError(data=data, detail=f"unknown type {data.type}"), schemas @@ -566,6 +577,15 @@ def build_schemas(*, components: Dict[str, Union[oai.Reference, oai.Schema]]) -> schemas = schemas_or_err processing = True # We made some progress this round, do another after it's done to_process = next_round - schemas.errors.extend(errors) + resolve_errors: List[PropertyError] = [] + models = list(schemas.models.values()) + for model in models: + schemas_or_err = model.resolve_references(components=components, schemas=schemas) + if isinstance(schemas_or_err, PropertyError): + resolve_errors.append(schemas_or_err) + else: + schemas = schemas_or_err + + schemas.errors.extend(resolve_errors) return schemas diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 3ab145af4..421259b9d 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -1,16 +1,25 @@ -from typing import ClassVar, List, Set, Union +from __future__ import annotations + +from collections.abc import Iterable +from typing import TYPE_CHECKING, ClassVar, Dict, List, Set, Union import attr +from ... import schema as oai +from ..errors import PropertyError from ..reference import Reference from .property import Property +if TYPE_CHECKING: + from .schemas import Schemas + @attr.s(auto_attribs=True, frozen=True) class ModelProperty(Property): """ A property which refers to another Schema """ reference: Reference + references: List[oai.Reference] required_properties: List[Property] optional_properties: List[Property] @@ -20,6 +29,50 @@ class ModelProperty(Property): _json_type_string: ClassVar[str] = "Dict[str, Any]" template: ClassVar[str] = "model_property.pyi" + json_is_dict: ClassVar[bool] = True + + def resolve_references( + self, components: Dict[str, Union[oai.Reference, oai.Schema]], schemas: Schemas + ) -> Union[Schemas, PropertyError]: + from ..properties import property_from_data + + required_set = set() + props = {} + while self.references: + reference = self.references.pop() + source_name = Reference.from_ref(reference.ref).class_name + referenced_prop = components[source_name] + assert isinstance(referenced_prop, oai.Schema) + for p, val in (referenced_prop.properties or {}).items(): + props[p] = (val, source_name) + for sub_prop in referenced_prop.allOf or []: + if isinstance(sub_prop, oai.Reference): + self.references.append(sub_prop) + else: + for p, val in (sub_prop.properties or {}).items(): + props[p] = (val, source_name) + if isinstance(referenced_prop.required, Iterable): + for sub_prop_name in referenced_prop.required: + required_set.add(sub_prop_name) + + for key, (value, source_name) in (props or {}).items(): + required = key in required_set + prop, schemas = property_from_data( + name=key, required=required, data=value, schemas=schemas, parent_name=source_name + ) + if isinstance(prop, PropertyError): + return prop + if required: + self.required_properties.append(prop) + # Remove the optional version + new_optional_props = [op for op in self.optional_properties if op.name != prop.name] + self.optional_properties.clear() + self.optional_properties.extend(new_optional_props) + elif not any(ep for ep in (self.optional_properties + self.required_properties) if ep.name == prop.name): + self.optional_properties.append(prop) + self.relative_imports.update(prop.get_imports(prefix="..")) + + return schemas def get_base_type_string(self) -> str: return self.reference.class_name diff --git a/openapi_python_client/parser/properties/property.py b/openapi_python_client/parser/properties/property.py index 651370ae2..c0ec0d56e 100644 --- a/openapi_python_client/parser/properties/property.py +++ b/openapi_python_client/parser/properties/property.py @@ -29,6 +29,7 @@ class Property: python_name: str = attr.ib(init=False) template: ClassVar[Optional[str]] = None + json_is_dict: ClassVar[bool] = False def __attrs_post_init__(self) -> None: object.__setattr__(self, "python_name", utils.to_valid_python_identifier(utils.snake_case(self.name))) diff --git a/pyproject.toml b/pyproject.toml index 4be8d93db..4d74fea82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ safety = "*" pytest-cov = "*" python-multipart = "*" flake8 = "*" -typer-cli = "^0.0.11" [tool.taskipy.tasks] check = """ @@ -67,7 +66,12 @@ task regen\ && task regen_custom\ && task e2e\ """ -docs = "typer openapi_python_client/cli.py utils docs > usage.md" +gen-setuppy = """ +poetry build \ +&& tar --strip-components=1 -xvf "$(ls -1 dist/*tar.gz | tail -1)" '*/setup.py' \ +&& isort setup.py \ +&& black setup.py +""" [tool.black] line-length = 120 @@ -95,5 +99,8 @@ skip = [".venv", "tests/test_templates"] omit = ["openapi_python_client/templates/*"] [build-system] -requires = ["poetry>=1.0"] +requires = [ + "setuptools>=30.3.0,<50", + "poetry>=1.0" +] build-backend = "poetry.masonry.api" From 97063d576e6f1cf4a2772c3e11659122def9d2a2 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:33:57 -0500 Subject: [PATCH 10/18] Fix tests --- .../parser/properties/__init__.py | 2 +- .../parser/properties/model_property.py | 1 - .../templates/endpoint_macros.pyi | 9 +- .../property_templates/model_property.pyi | 4 +- .../test_parser/test_properties/test_init.py | 22 ++- .../test_properties/test_model_property.py | 142 ++++++++++++++++++ 6 files changed, 167 insertions(+), 13 deletions(-) diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index a5ebf00d4..b84166f23 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -482,7 +482,6 @@ def _property_from_data( ) if data.anyOf or data.oneOf: return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name) - if data.type == "string": return _string_based_property(name=name, required=required, data=data), schemas elif data.type == "number": @@ -587,5 +586,6 @@ def build_schemas(*, components: Dict[str, Union[oai.Reference, oai.Schema]]) -> else: schemas = schemas_or_err + schemas.errors.extend(errors) schemas.errors.extend(resolve_errors) return schemas diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 421259b9d..c4c203a5d 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -20,7 +20,6 @@ class ModelProperty(Property): reference: Reference references: List[oai.Reference] - required_properties: List[Property] optional_properties: List[Property] description: str diff --git a/openapi_python_client/templates/endpoint_macros.pyi b/openapi_python_client/templates/endpoint_macros.pyi index 7a1862be3..6586ecd70 100644 --- a/openapi_python_client/templates/endpoint_macros.pyi +++ b/openapi_python_client/templates/endpoint_macros.pyi @@ -33,11 +33,12 @@ params: Dict[str, Any] = { } {% for property in endpoint.query_parameters %} {% if not property.required or property.nullable %} -if {% if not property.required %}{{ property.python_name }} is not UNSET and {% endif %}{{ property.python_name }} is not None: - {% if property.template %} - params["{{ property.name }}"] = {{ "json_" + property.python_name }} + {% set property_name = "json_" + property.python_name if property.template else property.python_name %} +if {% if not property.required %}not isinstance({{ property_name }}, Unset) and {% endif %}{{ property_name }} is not None: + {% if property.json_is_dict %} + params.update({{ property_name }}) {% else %} - params["{{ property.name }}"] = {{ property.python_name }} + params["{{ property.name }}"] = {{ property_name }} {% endif %} {% endif %} {% endfor %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index dfda61d97..6aef71d0f 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -1,5 +1,5 @@ {% macro construct(property, source, initial_value=None) %} -{% if property.required %} +{% if property.required and not property.nullable %} {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% else %} {% if initial_value != None %} @@ -10,7 +10,7 @@ {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} _{{ property.python_name }} = {{source}} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}: {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], _{{ property.python_name }})) {% endif %} {% endmacro %} diff --git a/tests/test_parser/test_properties/test_init.py b/tests/test_parser/test_properties/test_init.py index 2f1c71cc5..604b1bd1d 100644 --- a/tests/test_parser/test_properties/test_init.py +++ b/tests/test_parser/test_properties/test_init.py @@ -584,6 +584,7 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), + references=[], required_properties=[], optional_properties=[], description="", @@ -600,6 +601,7 @@ def test_property_from_data_ref_model(self): nullable=False, default=None, reference=Reference(class_name=class_name, module_name="my_model"), + references=[], required_properties=[], optional_properties=[], description="", @@ -990,15 +992,20 @@ def test_build_schemas(mocker): schemas_1 = mocker.MagicMock() model_2 = mocker.MagicMock() schemas_2 = mocker.MagicMock(errors=[]) - error = PropertyError() + schemas_2.models = {"1": model_1, "2": model_2} + error_1 = PropertyError() schemas_3 = mocker.MagicMock() + schemas_4 = mocker.MagicMock(errors=[]) + model_1.resolve_references.return_value = schemas_4 + error_2 = PropertyError() + model_2.resolve_references.return_value = error_2 # This loops through one for each, then again to retry the error build_model_property.side_effect = [ (model_1, schemas_1), (model_2, schemas_2), - (error, schemas_3), - (error, schemas_3), + (error_1, schemas_3), + (error_1, schemas_3), ] from openapi_python_client.parser.properties import Schemas, build_schemas @@ -1014,8 +1021,12 @@ def test_build_schemas(mocker): ] ) # schemas_3 was the last to come back from build_model_property, but it should be ignored because it's an error - assert result == schemas_2 - assert result.errors == [error] + model_1.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_2) + # schemas_4 came from resolving model_1 + model_2.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_4) + # resolving model_2 resulted in err, so no schemas_5 + assert result == schemas_4 + assert result.errors == [error_1, error_2] def test_build_parse_error_on_reference(): @@ -1089,6 +1100,7 @@ def test_build_model_property(additional_properties_schema, expected_additional_ nullable=False, default=None, reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"), + references=[], required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)], optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)], description=data.description, diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 410112666..83d521ab1 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -23,6 +23,7 @@ def test_get_type_string(no_optional, nullable, required, expected): nullable=nullable, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), + references=[], description="", optional_properties=[], required_properties=[], @@ -42,6 +43,7 @@ def test_get_imports(): nullable=True, default=None, reference=Reference(class_name="MyClass", module_name="my_module"), + references=[], description="", optional_properties=[], required_properties=[], @@ -57,3 +59,143 @@ def test_get_imports(): "from typing import Dict", "from typing import cast", } + + +def test_resolve_references(mocker): + import openapi_python_client.schema as oai + from openapi_python_client.parser.properties import build_model_property + + schemas = { + "RefA": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["String"], + properties={ + "String": oai.Schema.construct(type="string"), + "Enum": oai.Schema.construct(type="string", enum=["aValue"]), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + }, + ), + "RefB": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["DateTime"], + properties={ + "Int": oai.Schema.construct(type="integer"), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + # Intentionally no properties defined + "RefC": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + ), + } + + model_schema = oai.Schema.construct( + allOf=[ + oai.Reference.construct(ref="#/components/schemas/RefA"), + oai.Reference.construct(ref="#/components/schemas/RefB"), + oai.Reference.construct(ref="#/components/schemas/RefC"), + oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["Float"], + properties={ + "String": oai.Schema.construct(type="string"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + ] + ) + + components = {**schemas, "Model": model_schema} + + from openapi_python_client.parser.properties import Schemas + + schemas_holder = Schemas() + model, schemas_holder = build_model_property( + data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None + ) + model.resolve_references(components, schemas_holder) + assert sorted(p.name for p in model.required_properties) == ["DateTime", "Float", "String"] + assert all(p.required for p in model.required_properties) + assert sorted(p.name for p in model.optional_properties) == ["Enum", "Int"] + assert all(not p.required for p in model.optional_properties) + + +def test_resolve_references_nested_allof(mocker): + import openapi_python_client.schema as oai + from openapi_python_client.parser.properties import build_model_property + + schemas = { + "RefA": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["String"], + properties={ + "String": oai.Schema.construct(type="string"), + "Enum": oai.Schema.construct(type="string", enum=["aValue"]), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + }, + ), + "RefB": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["DateTime"], + properties={ + "Int": oai.Schema.construct(type="integer"), + "DateTime": oai.Schema.construct(type="string", format="date-time"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + # Intentionally no properties defined + "RefC": oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + ), + } + + model_schema = oai.Schema.construct( + type="object", + properties={ + "Key": oai.Schema.construct( + allOf=[ + oai.Reference.construct(ref="#/components/schemas/RefA"), + oai.Reference.construct(ref="#/components/schemas/RefB"), + oai.Reference.construct(ref="#/components/schemas/RefC"), + oai.Schema.construct( + title=mocker.MagicMock(), + description=mocker.MagicMock(), + required=["Float"], + properties={ + "String": oai.Schema.construct(type="string"), + "Float": oai.Schema.construct(type="number", format="float"), + }, + ), + ] + ), + }, + ) + + components = {**schemas, "Model": model_schema} + + from openapi_python_client.parser.properties import ModelProperty, Schemas + + schemas_holder = Schemas() + model, schemas_holder = build_model_property( + data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None + ) + model.resolve_references(components, schemas_holder) + assert sorted(p.name for p in model.required_properties) == [] + assert sorted(p.name for p in model.optional_properties) == ["Key"] + assert all(not p.required for p in model.optional_properties) + + key_property = model.optional_properties[0] + assert isinstance(key_property, ModelProperty) + key_property.resolve_references(components, schemas_holder) + assert sorted(p.name for p in key_property.required_properties) == ["DateTime", "Float", "String"] + assert all(p.required for p in key_property.required_properties) + assert sorted(p.name for p in key_property.optional_properties) == ["Enum", "Int"] + assert all(not p.required for p in key_property.optional_properties) From 67bce4180461c10a76f2355a7efaaae167b62d8d Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:34:26 -0500 Subject: [PATCH 11/18] Regen --- .../api/tests/defaults_tests_defaults_post.py | 34 +++++++++++-------- ...tional_value_tests_optional_query_param.py | 2 +- .../custom_e2e/models/a_model.py | 7 ++-- ...el_with_primitive_additional_properties.py | 2 +- .../api/tests/defaults_tests_defaults_post.py | 34 +++++++++++-------- ...tional_value_tests_optional_query_param.py | 2 +- .../my_test_api_client/models/a_model.py | 7 ++-- ...el_with_primitive_additional_properties.py | 2 +- 8 files changed, 54 insertions(+), 36 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index e4b71e321..d61560254 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -122,32 +122,38 @@ def httpx_request( params: Dict[str, Any] = { "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, } - if string_prop is not UNSET and string_prop is not None: + if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if not_required_not_nullable_datetime_prop is not UNSET and not_required_not_nullable_datetime_prop is not None: + if ( + not isinstance(json_not_required_not_nullable_datetime_prop, Unset) + and json_not_required_not_nullable_datetime_prop is not None + ): params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop - if not_required_nullable_datetime_prop is not UNSET and not_required_nullable_datetime_prop is not None: + if ( + not isinstance(json_not_required_nullable_datetime_prop, Unset) + and json_not_required_nullable_datetime_prop is not None + ): params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop - if required_nullable_datetime_prop is not None: + if json_required_nullable_datetime_prop is not None: params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop - if date_prop is not UNSET and date_prop is not None: + if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop - if float_prop is not UNSET and float_prop is not None: + if not isinstance(float_prop, Unset) and float_prop is not None: params["float_prop"] = float_prop - if int_prop is not UNSET and int_prop is not None: + if not isinstance(int_prop, Unset) and int_prop is not None: params["int_prop"] = int_prop - if boolean_prop is not UNSET and boolean_prop is not None: + if not isinstance(boolean_prop, Unset) and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if list_prop is not UNSET and list_prop is not None: + if not isinstance(json_list_prop, Unset) and json_list_prop is not None: params["list_prop"] = json_list_prop - if union_prop is not UNSET and union_prop is not None: + if not isinstance(json_union_prop, Unset) and json_union_prop is not None: params["union_prop"] = json_union_prop - if union_prop_with_ref is not UNSET and union_prop_with_ref is not None: + if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if enum_prop is not UNSET and enum_prop is not None: + if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: params["enum_prop"] = json_enum_prop - if model_prop is not UNSET and model_prop is not None: - params["model_prop"] = json_model_prop + if not isinstance(json_model_prop, Unset) and json_model_prop is not None: + params.update(json_model_prop) response = client.request( "post", diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py index 8ff5a52a3..279ce8ca8 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py @@ -47,7 +47,7 @@ def httpx_request( json_query_param = query_param params: Dict[str, Any] = {} - if query_param is not UNSET and query_param is not None: + if not isinstance(json_query_param, Unset) and json_query_param is not None: params["query_param"] = json_query_param response = client.request( diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 3e46992a4..9462c38b9 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -153,11 +153,14 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) - nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + nullable_model = None + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) - if _not_required_model is not None and not isinstance(_not_required_model, Unset): + if not isinstance(_not_required_model, Unset): not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) not_required_nullable_model = None diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index feb30878d..1ba447347 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -33,7 +33,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index 540f68b44..f87317ead 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -98,32 +98,38 @@ def _get_kwargs( params: Dict[str, Any] = { "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, } - if string_prop is not UNSET and string_prop is not None: + if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if not_required_not_nullable_datetime_prop is not UNSET and not_required_not_nullable_datetime_prop is not None: + if ( + not isinstance(json_not_required_not_nullable_datetime_prop, Unset) + and json_not_required_not_nullable_datetime_prop is not None + ): params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop - if not_required_nullable_datetime_prop is not UNSET and not_required_nullable_datetime_prop is not None: + if ( + not isinstance(json_not_required_nullable_datetime_prop, Unset) + and json_not_required_nullable_datetime_prop is not None + ): params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop - if required_nullable_datetime_prop is not None: + if json_required_nullable_datetime_prop is not None: params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop - if date_prop is not UNSET and date_prop is not None: + if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop - if float_prop is not UNSET and float_prop is not None: + if not isinstance(float_prop, Unset) and float_prop is not None: params["float_prop"] = float_prop - if int_prop is not UNSET and int_prop is not None: + if not isinstance(int_prop, Unset) and int_prop is not None: params["int_prop"] = int_prop - if boolean_prop is not UNSET and boolean_prop is not None: + if not isinstance(boolean_prop, Unset) and boolean_prop is not None: params["boolean_prop"] = boolean_prop - if list_prop is not UNSET and list_prop is not None: + if not isinstance(json_list_prop, Unset) and json_list_prop is not None: params["list_prop"] = json_list_prop - if union_prop is not UNSET and union_prop is not None: + if not isinstance(json_union_prop, Unset) and json_union_prop is not None: params["union_prop"] = json_union_prop - if union_prop_with_ref is not UNSET and union_prop_with_ref is not None: + if not isinstance(json_union_prop_with_ref, Unset) and json_union_prop_with_ref is not None: params["union_prop_with_ref"] = json_union_prop_with_ref - if enum_prop is not UNSET and enum_prop is not None: + if not isinstance(json_enum_prop, Unset) and json_enum_prop is not None: params["enum_prop"] = json_enum_prop - if model_prop is not UNSET and model_prop is not None: - params["model_prop"] = json_model_prop + if not isinstance(json_model_prop, Unset) and json_model_prop is not None: + params.update(json_model_prop) return { "url": url, diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 2c14c2949..23bd9e741 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -24,7 +24,7 @@ def _get_kwargs( json_query_param = query_param params: Dict[str, Any] = {} - if query_param is not UNSET and query_param is not None: + if not isinstance(json_query_param, Unset) and json_query_param is not None: params["query_param"] = json_query_param return { diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 3e46992a4..9462c38b9 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -153,11 +153,14 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) - nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + nullable_model = None + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) - if _not_required_model is not None and not isinstance(_not_required_model, Unset): + if not isinstance(_not_required_model, Unset): not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) not_required_nullable_model = None diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index feb30878d..1ba447347 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -33,7 +33,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( cast(Dict[str, Any], _a_date_holder) ) From f02e943d374bbbef7dd170798a3c338f3465e8a3 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 18:40:25 -0500 Subject: [PATCH 12/18] Add tests for union --- .../custom_e2e/models/a_model.py | 145 ++++++++++++++++++ .../my_test_api_client/models/a_model.py | 145 ++++++++++++++++++ end_to_end_tests/openapi.json | 57 ++++++- 3 files changed, 346 insertions(+), 1 deletion(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 9462c38b9..e3410d097 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -10,6 +10,8 @@ from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum +from ..models.free_form_model import FreeFormModel +from ..models.model_with_union_property import ModelWithUnionProperty from ..types import UNSET, Unset @@ -22,15 +24,19 @@ class AModel: a_date: datetime.date required_not_nullable: str model: AModelModel + one_of_models: Union[FreeFormModel, ModelWithUnionProperty] a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] nullable_model: Optional[AModelNullableModel] + nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET + not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] = UNSET + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -45,6 +51,12 @@ def to_dict(self) -> Dict[str, Any]: required_not_nullable = self.required_not_nullable model = self.model.to_dict() + if isinstance(self.one_of_models, FreeFormModel): + one_of_models = self.one_of_models.to_dict() + + else: + one_of_models = self.one_of_models.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -74,6 +86,45 @@ def to_dict(self) -> Dict[str, Any]: self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None ) + nullable_one_of_models: Union[None, Dict[str, Any]] + if isinstance(self.nullable_one_of_models, Unset): + nullable_one_of_models = UNSET + if self.nullable_one_of_models is None: + nullable_one_of_models = None + elif isinstance(self.nullable_one_of_models, FreeFormModel): + nullable_one_of_models = self.nullable_one_of_models.to_dict() + + else: + nullable_one_of_models = self.nullable_one_of_models.to_dict() + + not_required_one_of_models: Union[Unset, Dict[str, Any]] + if isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = UNSET + elif isinstance(self.not_required_one_of_models, FreeFormModel): + not_required_one_of_models = UNSET + if not isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = self.not_required_one_of_models.to_dict() + + else: + not_required_one_of_models = UNSET + if not isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = self.not_required_one_of_models.to_dict() + + not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any]] + if isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = UNSET + elif self.not_required_nullable_one_of_models is None: + not_required_nullable_one_of_models = None + elif isinstance(self.not_required_nullable_one_of_models, FreeFormModel): + not_required_nullable_one_of_models = UNSET + if not isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + + else: + not_required_nullable_one_of_models = UNSET + if not isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + field_dict: Dict[str, Any] = {} field_dict.update( { @@ -82,9 +133,11 @@ def to_dict(self) -> Dict[str, Any]: "a_date": a_date, "required_not_nullable": required_not_nullable, "model": model, + "one_of_models": one_of_models, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, "nullable_model": nullable_model, + "nullable_one_of_models": nullable_one_of_models, } ) if nested_list_of_enums is not UNSET: @@ -99,6 +152,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_model"] = not_required_model if not_required_nullable_model is not UNSET: field_dict["not_required_nullable_model"] = not_required_nullable_model + if not_required_one_of_models is not UNSET: + field_dict["not_required_one_of_models"] = not_required_one_of_models + if not_required_nullable_one_of_models is not UNSET: + field_dict["not_required_nullable_one_of_models"] = not_required_nullable_one_of_models return field_dict @@ -128,6 +185,21 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat model = AModelModel.from_dict(d.pop("model")) + def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + one_of_models: Union[FreeFormModel, ModelWithUnionProperty] + try: + one_of_models = FreeFormModel.from_dict(data) + + return one_of_models + except: # noqa: E722 + pass + one_of_models = ModelWithUnionProperty.from_dict(data) + + return one_of_models + + one_of_models = _parse_one_of_models(d.pop("one_of_models")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -170,12 +242,82 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat cast(Dict[str, Any], _not_required_nullable_model) ) + def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] + try: + nullable_one_of_models = FreeFormModel.from_dict(data) + + return nullable_one_of_models + except: # noqa: E722 + pass + nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + + return nullable_one_of_models + + nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models")) + + def _parse_not_required_one_of_models(data: Any) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] + try: + not_required_one_of_models = UNSET + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict( + cast(Dict[str, Any], _not_required_one_of_models) + ) + + return not_required_one_of_models + except: # noqa: E722 + pass + not_required_one_of_models = UNSET + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict( + cast(Dict[str, Any], _not_required_one_of_models) + ) + + return not_required_one_of_models + + not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) + + def _parse_not_required_nullable_one_of_models( + data: Any, + ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + try: + not_required_nullable_one_of_models = UNSET + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = FreeFormModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_one_of_models) + ) + + return not_required_nullable_one_of_models + except: # noqa: E722 + pass + not_required_nullable_one_of_models = UNSET + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( + cast(Dict[str, Any], _not_required_nullable_one_of_models) + ) + + return not_required_nullable_one_of_models + + not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models( + d.pop("not_required_nullable_one_of_models", UNSET) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, model=model, + one_of_models=one_of_models, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, @@ -185,6 +327,9 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat nullable_model=nullable_model, not_required_model=not_required_model, not_required_nullable_model=not_required_nullable_model, + nullable_one_of_models=nullable_one_of_models, + not_required_one_of_models=not_required_one_of_models, + not_required_nullable_one_of_models=not_required_nullable_one_of_models, ) return a_model diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 9462c38b9..e3410d097 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -10,6 +10,8 @@ from ..models.a_model_nullable_model import AModelNullableModel from ..models.an_enum import AnEnum from ..models.different_enum import DifferentEnum +from ..models.free_form_model import FreeFormModel +from ..models.model_with_union_property import ModelWithUnionProperty from ..types import UNSET, Unset @@ -22,15 +24,19 @@ class AModel: a_date: datetime.date required_not_nullable: str model: AModelModel + one_of_models: Union[FreeFormModel, ModelWithUnionProperty] a_nullable_date: Optional[datetime.date] required_nullable: Optional[str] nullable_model: Optional[AModelNullableModel] + nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET + not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] = UNSET + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -45,6 +51,12 @@ def to_dict(self) -> Dict[str, Any]: required_not_nullable = self.required_not_nullable model = self.model.to_dict() + if isinstance(self.one_of_models, FreeFormModel): + one_of_models = self.one_of_models.to_dict() + + else: + one_of_models = self.one_of_models.to_dict() + nested_list_of_enums: Union[Unset, List[Any]] = UNSET if not isinstance(self.nested_list_of_enums, Unset): nested_list_of_enums = [] @@ -74,6 +86,45 @@ def to_dict(self) -> Dict[str, Any]: self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None ) + nullable_one_of_models: Union[None, Dict[str, Any]] + if isinstance(self.nullable_one_of_models, Unset): + nullable_one_of_models = UNSET + if self.nullable_one_of_models is None: + nullable_one_of_models = None + elif isinstance(self.nullable_one_of_models, FreeFormModel): + nullable_one_of_models = self.nullable_one_of_models.to_dict() + + else: + nullable_one_of_models = self.nullable_one_of_models.to_dict() + + not_required_one_of_models: Union[Unset, Dict[str, Any]] + if isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = UNSET + elif isinstance(self.not_required_one_of_models, FreeFormModel): + not_required_one_of_models = UNSET + if not isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = self.not_required_one_of_models.to_dict() + + else: + not_required_one_of_models = UNSET + if not isinstance(self.not_required_one_of_models, Unset): + not_required_one_of_models = self.not_required_one_of_models.to_dict() + + not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any]] + if isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = UNSET + elif self.not_required_nullable_one_of_models is None: + not_required_nullable_one_of_models = None + elif isinstance(self.not_required_nullable_one_of_models, FreeFormModel): + not_required_nullable_one_of_models = UNSET + if not isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + + else: + not_required_nullable_one_of_models = UNSET + if not isinstance(self.not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + field_dict: Dict[str, Any] = {} field_dict.update( { @@ -82,9 +133,11 @@ def to_dict(self) -> Dict[str, Any]: "a_date": a_date, "required_not_nullable": required_not_nullable, "model": model, + "one_of_models": one_of_models, "a_nullable_date": a_nullable_date, "required_nullable": required_nullable, "nullable_model": nullable_model, + "nullable_one_of_models": nullable_one_of_models, } ) if nested_list_of_enums is not UNSET: @@ -99,6 +152,10 @@ def to_dict(self) -> Dict[str, Any]: field_dict["not_required_model"] = not_required_model if not_required_nullable_model is not UNSET: field_dict["not_required_nullable_model"] = not_required_nullable_model + if not_required_one_of_models is not UNSET: + field_dict["not_required_one_of_models"] = not_required_one_of_models + if not_required_nullable_one_of_models is not UNSET: + field_dict["not_required_nullable_one_of_models"] = not_required_nullable_one_of_models return field_dict @@ -128,6 +185,21 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat model = AModelModel.from_dict(d.pop("model")) + def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + one_of_models: Union[FreeFormModel, ModelWithUnionProperty] + try: + one_of_models = FreeFormModel.from_dict(data) + + return one_of_models + except: # noqa: E722 + pass + one_of_models = ModelWithUnionProperty.from_dict(data) + + return one_of_models + + one_of_models = _parse_one_of_models(d.pop("one_of_models")) + nested_list_of_enums = [] _nested_list_of_enums = d.pop("nested_list_of_enums", UNSET) for nested_list_of_enums_item_data in _nested_list_of_enums or []: @@ -170,12 +242,82 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat cast(Dict[str, Any], _not_required_nullable_model) ) + def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] + try: + nullable_one_of_models = FreeFormModel.from_dict(data) + + return nullable_one_of_models + except: # noqa: E722 + pass + nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + + return nullable_one_of_models + + nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models")) + + def _parse_not_required_one_of_models(data: Any) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] + try: + not_required_one_of_models = UNSET + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict( + cast(Dict[str, Any], _not_required_one_of_models) + ) + + return not_required_one_of_models + except: # noqa: E722 + pass + not_required_one_of_models = UNSET + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict( + cast(Dict[str, Any], _not_required_one_of_models) + ) + + return not_required_one_of_models + + not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) + + def _parse_not_required_nullable_one_of_models( + data: Any, + ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: + data = None if isinstance(data, Unset) else data + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + try: + not_required_nullable_one_of_models = UNSET + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = FreeFormModel.from_dict( + cast(Dict[str, Any], _not_required_nullable_one_of_models) + ) + + return not_required_nullable_one_of_models + except: # noqa: E722 + pass + not_required_nullable_one_of_models = UNSET + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( + cast(Dict[str, Any], _not_required_nullable_one_of_models) + ) + + return not_required_nullable_one_of_models + + not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models( + d.pop("not_required_nullable_one_of_models", UNSET) + ) + a_model = AModel( an_enum_value=an_enum_value, a_camel_date_time=a_camel_date_time, a_date=a_date, required_not_nullable=required_not_nullable, model=model, + one_of_models=one_of_models, nested_list_of_enums=nested_list_of_enums, a_nullable_date=a_nullable_date, attr_1_leading_digit=attr_1_leading_digit, @@ -185,6 +327,9 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat nullable_model=nullable_model, not_required_model=not_required_model, not_required_nullable_model=not_required_nullable_model, + nullable_one_of_models=nullable_one_of_models, + not_required_one_of_models=not_required_one_of_models, + not_required_nullable_one_of_models=not_required_nullable_one_of_models, ) return a_model diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 6d7d15c6c..404656e31 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -667,7 +667,18 @@ "schemas": { "AModel": { "title": "AModel", - "required": ["an_enum_value", "aCamelDateTime", "a_date", "a_nullable_date", "required_nullable", "required_not_nullable", "model", "nullable_model"], + "required": [ + "an_enum_value", + "aCamelDateTime", + "a_date", + "a_nullable_date", + "required_nullable", + "required_not_nullable", + "model", + "nullable_model", + "one_of_models", + "nullable_one_of_models" + ], "type": "object", "properties": { "an_enum_value": { @@ -767,6 +778,50 @@ } ], "nullable": true + }, + "one_of_models": { + "oneOf": [ + { + "ref": "#components/schemas/FreeFormModel" + }, + { + "ref": "#components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "nullable_one_of_models": { + "oneOf": [ + { + "ref": "#components/schemas/FreeFormModel" + }, + { + "ref": "#components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true + }, + "not_required_one_of_models": { + "oneOf": [ + { + "ref": "#components/schemas/FreeFormModel" + }, + { + "ref": "#components/schemas/ModelWithUnionProperty" + } + ], + "nullable": false + }, + "not_required_nullable_one_of_models": { + "oneOf": [ + { + "ref": "#components/schemas/FreeFormModel" + }, + { + "ref": "#components/schemas/ModelWithUnionProperty" + } + ], + "nullable": true } }, "description": "A Model for testing all the ways custom objects can be used ", From f9788d73abcc61cc7c5981e2e3945d539af96169 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Wed, 27 Jan 2021 19:03:01 -0500 Subject: [PATCH 13/18] Make progress toward fixing it --- .../custom_e2e/models/a_model.py | 67 ++++++++++--------- .../custom_e2e/models/a_model_model.py | 9 +-- .../models/a_model_not_required_model.py | 9 +-- .../a_model_not_required_nullable_model.py | 9 +-- .../models/a_model_nullable_model.py | 9 +-- .../models/model_with_any_json_properties.py | 4 +- ...el_with_primitive_additional_properties.py | 8 +-- .../models/model_with_union_property.py | 9 +-- .../my_test_api_client/models/a_model.py | 67 ++++++++++--------- .../models/a_model_model.py | 9 +-- .../models/a_model_not_required_model.py | 9 +-- .../a_model_not_required_nullable_model.py | 9 +-- .../models/a_model_nullable_model.py | 9 +-- .../models/model_with_any_json_properties.py | 4 +- ...el_with_primitive_additional_properties.py | 8 +-- .../models/model_with_union_property.py | 9 +-- .../property_templates/date_property.pyi | 2 +- .../property_templates/datetime_property.pyi | 2 +- .../property_templates/dict_property.pyi | 2 +- .../property_templates/enum_property.pyi | 2 +- .../property_templates/model_property.pyi | 4 +- .../property_templates/union_property.pyi | 11 ++- 22 files changed, 143 insertions(+), 128 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index e3410d097..1355a34d4 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -164,8 +164,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "AModel": d = src_dict.copy() an_enum_value = AnEnum(d.pop("an_enum_value")) - def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.date]: - data = None if isinstance(data, Unset) else data + def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datetime.date]: a_camel_date_time: Union[datetime.datetime, datetime.date] try: a_camel_date_time = isoparse(data) @@ -185,8 +184,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat model = AModelModel.from_dict(d.pop("model")) - def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, ModelWithUnionProperty]: one_of_models: Union[FreeFormModel, ModelWithUnionProperty] try: one_of_models = FreeFormModel.from_dict(data) @@ -214,7 +212,7 @@ def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProper a_nullable_date = None _a_nullable_date = d.pop("a_nullable_date") - if _a_nullable_date is not None: + if _a_nullable_date is not None and not isinstance(_a_nullable_date, Unset): a_nullable_date = isoparse(cast(str, _a_nullable_date)).date() attr_1_leading_digit = d.pop("1_leading_digit", UNSET) @@ -227,24 +225,25 @@ def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProper nullable_model = None _nullable_model = d.pop("nullable_model") - if _nullable_model is not None: - nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) + if _nullable_model is not None and not isinstance(_nullable_model, Unset): + nullable_model = AModelNullableModel.from_dict(_nullable_model) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) - if not isinstance(_not_required_model, Unset): - not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + if _not_required_model is not None and not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(_not_required_model) not_required_nullable_model = None _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_model) - ) + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(_not_required_nullable_model) - def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_nullable_one_of_models( + data: Union[None, Dict[str, Any]] + ) -> Union[None, FreeFormModel, ModelWithUnionProperty]: nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] + if data is None: + return data try: nullable_one_of_models = FreeFormModel.from_dict(data) @@ -257,52 +256,56 @@ def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, Model nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models")) - def _parse_not_required_one_of_models(data: Any) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_not_required_one_of_models( + data: Union[Unset, Dict[str, Any]] + ) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] + if isinstance(data, Unset): + return data try: not_required_one_of_models = UNSET _not_required_one_of_models = data - if not isinstance(_not_required_one_of_models, Unset): - not_required_one_of_models = FreeFormModel.from_dict( - cast(Dict[str, Any], _not_required_one_of_models) - ) + if _not_required_one_of_models is not None and not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict(_not_required_one_of_models) return not_required_one_of_models except: # noqa: E722 pass not_required_one_of_models = UNSET _not_required_one_of_models = data - if not isinstance(_not_required_one_of_models, Unset): - not_required_one_of_models = ModelWithUnionProperty.from_dict( - cast(Dict[str, Any], _not_required_one_of_models) - ) + if _not_required_one_of_models is not None and not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict(_not_required_one_of_models) return not_required_one_of_models not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) def _parse_not_required_nullable_one_of_models( - data: Any, + data: Union[Unset, None, Dict[str, Any]] ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + if data is None: + return data + if isinstance(data, Unset): + return data try: not_required_nullable_one_of_models = UNSET _not_required_nullable_one_of_models = data - if not isinstance(_not_required_nullable_one_of_models, Unset): - not_required_nullable_one_of_models = FreeFormModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_one_of_models) - ) + if _not_required_nullable_one_of_models is not None and not isinstance( + _not_required_nullable_one_of_models, Unset + ): + not_required_nullable_one_of_models = FreeFormModel.from_dict(_not_required_nullable_one_of_models) return not_required_nullable_one_of_models except: # noqa: E722 pass not_required_nullable_one_of_models = UNSET _not_required_nullable_one_of_models = data - if not isinstance(_not_required_nullable_one_of_models, Unset): + if _not_required_nullable_one_of_models is not None and not isinstance( + _not_required_nullable_one_of_models, Unset + ): not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( - cast(Dict[str, Any], _not_required_nullable_one_of_models) + _not_required_nullable_one_of_models ) return not_required_nullable_one_of_models diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py index 0700798c8..724c5f414 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py index a08f547aa..7c9cad150 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py index 52ee2ddc3..00a8de6b4 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py index 2f21cc5ac..09e6558ed 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py index 62481f913..21d57f432 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py @@ -3,7 +3,6 @@ import attr from ..models.model_with_any_json_properties_additional_property import ModelWithAnyJsonPropertiesAdditionalProperty -from ..types import Unset @attr.s(auto_attribs=True) @@ -40,9 +39,8 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithAnyJsonProperties": for prop_name, prop_dict in d.items(): def _parse_additional_property( - data: Any, + data: Union[Dict[str, Any], List[Any], str, float, int, bool] ) -> Union[ModelWithAnyJsonPropertiesAdditionalProperty, List[str], str, float, int, bool]: - data = None if isinstance(data, Unset) else data additional_property: Union[ ModelWithAnyJsonPropertiesAdditionalProperty, List[str], str, float, int, bool ] diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index 1ba447347..83feaf044 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Union, cast +from typing import Any, Dict, List, Union import attr @@ -33,10 +33,8 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if not isinstance(_a_date_holder, Unset): - a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( - cast(Dict[str, Any], _a_date_holder) - ) + if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(_a_date_holder) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( a_date_holder=a_date_holder, diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index 35bc2a853..956ea64b3 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -38,13 +38,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "ModelWithUnionProperty": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -52,7 +53,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index e3410d097..1355a34d4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -164,8 +164,7 @@ def from_dict(src_dict: Dict[str, Any]) -> "AModel": d = src_dict.copy() an_enum_value = AnEnum(d.pop("an_enum_value")) - def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.date]: - data = None if isinstance(data, Unset) else data + def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datetime.date]: a_camel_date_time: Union[datetime.datetime, datetime.date] try: a_camel_date_time = isoparse(data) @@ -185,8 +184,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat model = AModelModel.from_dict(d.pop("model")) - def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, ModelWithUnionProperty]: one_of_models: Union[FreeFormModel, ModelWithUnionProperty] try: one_of_models = FreeFormModel.from_dict(data) @@ -214,7 +212,7 @@ def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProper a_nullable_date = None _a_nullable_date = d.pop("a_nullable_date") - if _a_nullable_date is not None: + if _a_nullable_date is not None and not isinstance(_a_nullable_date, Unset): a_nullable_date = isoparse(cast(str, _a_nullable_date)).date() attr_1_leading_digit = d.pop("1_leading_digit", UNSET) @@ -227,24 +225,25 @@ def _parse_one_of_models(data: Any) -> Union[FreeFormModel, ModelWithUnionProper nullable_model = None _nullable_model = d.pop("nullable_model") - if _nullable_model is not None: - nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) + if _nullable_model is not None and not isinstance(_nullable_model, Unset): + nullable_model = AModelNullableModel.from_dict(_nullable_model) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) - if not isinstance(_not_required_model, Unset): - not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) + if _not_required_model is not None and not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(_not_required_model) not_required_nullable_model = None _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_model) - ) + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(_not_required_nullable_model) - def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_nullable_one_of_models( + data: Union[None, Dict[str, Any]] + ) -> Union[None, FreeFormModel, ModelWithUnionProperty]: nullable_one_of_models: Union[None, FreeFormModel, ModelWithUnionProperty] + if data is None: + return data try: nullable_one_of_models = FreeFormModel.from_dict(data) @@ -257,52 +256,56 @@ def _parse_nullable_one_of_models(data: Any) -> Union[None, FreeFormModel, Model nullable_one_of_models = _parse_nullable_one_of_models(d.pop("nullable_one_of_models")) - def _parse_not_required_one_of_models(data: Any) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data + def _parse_not_required_one_of_models( + data: Union[Unset, Dict[str, Any]] + ) -> Union[Unset, FreeFormModel, ModelWithUnionProperty]: not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] + if isinstance(data, Unset): + return data try: not_required_one_of_models = UNSET _not_required_one_of_models = data - if not isinstance(_not_required_one_of_models, Unset): - not_required_one_of_models = FreeFormModel.from_dict( - cast(Dict[str, Any], _not_required_one_of_models) - ) + if _not_required_one_of_models is not None and not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict(_not_required_one_of_models) return not_required_one_of_models except: # noqa: E722 pass not_required_one_of_models = UNSET _not_required_one_of_models = data - if not isinstance(_not_required_one_of_models, Unset): - not_required_one_of_models = ModelWithUnionProperty.from_dict( - cast(Dict[str, Any], _not_required_one_of_models) - ) + if _not_required_one_of_models is not None and not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict(_not_required_one_of_models) return not_required_one_of_models not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) def _parse_not_required_nullable_one_of_models( - data: Any, + data: Union[Unset, None, Dict[str, Any]] ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: - data = None if isinstance(data, Unset) else data not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + if data is None: + return data + if isinstance(data, Unset): + return data try: not_required_nullable_one_of_models = UNSET _not_required_nullable_one_of_models = data - if not isinstance(_not_required_nullable_one_of_models, Unset): - not_required_nullable_one_of_models = FreeFormModel.from_dict( - cast(Dict[str, Any], _not_required_nullable_one_of_models) - ) + if _not_required_nullable_one_of_models is not None and not isinstance( + _not_required_nullable_one_of_models, Unset + ): + not_required_nullable_one_of_models = FreeFormModel.from_dict(_not_required_nullable_one_of_models) return not_required_nullable_one_of_models except: # noqa: E722 pass not_required_nullable_one_of_models = UNSET _not_required_nullable_one_of_models = data - if not isinstance(_not_required_nullable_one_of_models, Unset): + if _not_required_nullable_one_of_models is not None and not isinstance( + _not_required_nullable_one_of_models, Unset + ): not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( - cast(Dict[str, Any], _not_required_nullable_one_of_models) + _not_required_nullable_one_of_models ) return not_required_nullable_one_of_models diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py index 0700798c8..724c5f414 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py index a08f547aa..7c9cad150 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py index 52ee2ddc3..00a8de6b4 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNotRequiredNullableModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py index 2f21cc5ac..09e6558ed 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -40,13 +40,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "AModelNullableModel": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -54,7 +55,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py index 62481f913..21d57f432 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py @@ -3,7 +3,6 @@ import attr from ..models.model_with_any_json_properties_additional_property import ModelWithAnyJsonPropertiesAdditionalProperty -from ..types import Unset @attr.s(auto_attribs=True) @@ -40,9 +39,8 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithAnyJsonProperties": for prop_name, prop_dict in d.items(): def _parse_additional_property( - data: Any, + data: Union[Dict[str, Any], List[Any], str, float, int, bool] ) -> Union[ModelWithAnyJsonPropertiesAdditionalProperty, List[str], str, float, int, bool]: - data = None if isinstance(data, Unset) else data additional_property: Union[ ModelWithAnyJsonPropertiesAdditionalProperty, List[str], str, float, int, bool ] diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index 1ba447347..83feaf044 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Union, cast +from typing import Any, Dict, List, Union import attr @@ -33,10 +33,8 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) - if not isinstance(_a_date_holder, Unset): - a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( - cast(Dict[str, Any], _a_date_holder) - ) + if _a_date_holder is not None and not isinstance(_a_date_holder, Unset): + a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(_a_date_holder) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( a_date_holder=a_date_holder, diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index 35bc2a853..956ea64b3 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -38,13 +38,14 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "ModelWithUnionProperty": d = src_dict.copy() - def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: - data = None if isinstance(data, Unset) else data + def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum]: a_property: Union[Unset, AnEnum, AnIntEnum] + if isinstance(data, Unset): + return data try: a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnEnum(_a_property) return a_property @@ -52,7 +53,7 @@ def _parse_a_property(data: Any) -> Union[Unset, AnEnum, AnIntEnum]: pass a_property = UNSET _a_property = data - if _a_property is not None: + if _a_property is not None and not isinstance(_a_property, Unset): a_property = AnIntEnum(_a_property) return a_property diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index bc2cae912..f73df9437 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None: +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): {{ property.python_name }} = isoparse(cast(str, _{{ property.python_name }})).date() {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index 91ce0cacc..88f370b32 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -9,7 +9,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None: +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): {{ property.python_name }} = isoparse(cast(str, _{{ property.python_name }})) {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/dict_property.pyi b/openapi_python_client/templates/property_templates/dict_property.pyi index 36a6b4292..ca16cb538 100644 --- a/openapi_python_client/templates/property_templates/dict_property.pyi +++ b/openapi_python_client/templates/property_templates/dict_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None: +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): {{ property.python_name }} = _{{ property.python_name }} {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 831f633d5..3bf16564e 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None: +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): {{ property.python_name }} = {{ property.reference.class_name }}(_{{ property.python_name }}) {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index 6aef71d0f..ebbba35bb 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -10,8 +10,8 @@ {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} _{{ property.python_name }} = {{source}} -if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}: - {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], _{{ property.python_name }})) +if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): + {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(_{{ property.python_name }}) {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index 509c7f34e..d493cb6ba 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -1,7 +1,14 @@ {% macro construct(property, source, initial_value=None) %} -def _parse_{{ property.python_name }}(data: Any) -> {{ property.get_type_string() }}: - data = None if isinstance(data, Unset) else data +def _parse_{{ property.python_name }}(data: {{ property.get_type_string(json=True) }}) -> {{ property.get_type_string() }}: {{ property.python_name }}: {{ property.get_type_string() }} + {% if "None" in property.get_type_string(json=True) %} + if data is None: + return data + {% endif %} + {% if "Unset" in property.get_type_string(json=True) %} + if isinstance(data, Unset): + return data + {% endif %} {% for inner_property in property.inner_properties_with_template() %} {% if not loop.last or property.has_properties_without_templates %} try: From 55e16f3031da0ba491cbc9c89ea93596296f4133 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 28 Jan 2021 08:07:49 -0500 Subject: [PATCH 14/18] feat: Change optional Open API query parameters to allow `None (#40) --- .../api/tests/defaults_tests_defaults_post.py | 100 +++++--- ...tional_value_tests_optional_query_param.py | 9 +- .../custom_e2e/models/a_model.py | 10 +- .../custom_e2e/models/a_model_model.py | 6 +- .../models/a_model_not_required_model.py | 6 +- .../a_model_not_required_nullable_model.py | 6 +- .../models/a_model_nullable_model.py | 6 +- ...el_with_primitive_additional_properties.py | 4 +- .../models/model_with_union_property.py | 6 +- .../golden-record-custom/custom_e2e/types.py | 5 +- .../api/tests/defaults_tests_defaults_post.py | 218 +++++++++++------- ...tional_value_tests_optional_query_param.py | 17 +- .../my_test_api_client/models/a_model.py | 10 +- .../models/a_model_model.py | 6 +- .../models/a_model_not_required_model.py | 6 +- .../a_model_not_required_nullable_model.py | 6 +- .../models/a_model_nullable_model.py | 6 +- ...el_with_primitive_additional_properties.py | 4 +- .../models/model_with_union_property.py | 6 +- .../golden-record/my_test_api_client/types.py | 5 +- end_to_end_tests/openapi.json | 41 +++- .../parser/properties/__init__.py | 62 +++-- .../parser/properties/enum_property.py | 14 +- .../parser/properties/model_property.py | 13 +- .../parser/properties/property.py | 48 +++- .../templates/endpoint_macros.pyi | 8 +- .../property_templates/date_property.pyi | 6 +- .../property_templates/datetime_property.pyi | 6 +- .../property_templates/enum_property.pyi | 10 +- .../property_templates/file_property.pyi | 6 +- .../property_templates/list_property.pyi | 8 +- .../property_templates/model_property.pyi | 6 +- .../property_templates/union_property.pyi | 10 +- openapi_python_client/templates/types.py | 5 +- pyproject.toml | 3 +- .../test_parser/test_properties/test_init.py | 141 ++++++----- .../test_properties/test_model_property.py | 4 +- .../test_date_property/optional_nullable.py | 2 +- 38 files changed, 506 insertions(+), 329 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index f87ad3e1b..d61560254 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -7,7 +7,7 @@ Client = httpx.Client import datetime -from typing import Dict, List, Union +from typing import Dict, List, Optional, Union from dateutil.parser import isoparse @@ -41,65 +41,101 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def httpx_request( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: - json_datetime_prop: Union[Unset, str] = UNSET - if not isinstance(datetime_prop, Unset): - json_datetime_prop = datetime_prop.isoformat() + json_not_required_not_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_not_nullable_datetime_prop, Unset): + json_not_required_not_nullable_datetime_prop = ( + not_required_not_nullable_datetime_prop.isoformat() if not_required_not_nullable_datetime_prop else None + ) - json_date_prop: Union[Unset, str] = UNSET + json_not_required_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_nullable_datetime_prop, Unset): + json_not_required_nullable_datetime_prop = ( + not_required_nullable_datetime_prop.isoformat() if not_required_nullable_datetime_prop else None + ) + + json_required_not_nullable_datetime_prop = required_not_nullable_datetime_prop.isoformat() + + json_required_nullable_datetime_prop = ( + required_nullable_datetime_prop.isoformat() if required_nullable_datetime_prop else None + ) + + json_date_prop: Union[Unset, None, str] = UNSET if not isinstance(date_prop, Unset): - json_date_prop = date_prop.isoformat() + json_date_prop = date_prop.isoformat() if date_prop else None - json_list_prop: Union[Unset, List[Any]] = UNSET + json_list_prop: Union[Unset, None, List[Any]] = UNSET if not isinstance(list_prop, Unset): - json_list_prop = [] - for list_prop_item_data in list_prop: - list_prop_item = list_prop_item_data.value + if list_prop is None: + json_list_prop = None + else: + json_list_prop = [] + for list_prop_item_data in list_prop: + list_prop_item = list_prop_item_data.value - json_list_prop.append(list_prop_item) + json_list_prop.append(list_prop_item) - json_union_prop: Union[Unset, float, str] + json_union_prop: Union[Unset, None, float, str] if isinstance(union_prop, Unset): json_union_prop = UNSET + elif union_prop is None: + json_union_prop = None else: json_union_prop = union_prop - json_union_prop_with_ref: Union[Unset, float, AnEnum] + json_union_prop_with_ref: Union[Unset, None, float, int] if isinstance(union_prop_with_ref, Unset): json_union_prop_with_ref = UNSET + elif union_prop_with_ref is None: + json_union_prop_with_ref = None elif isinstance(union_prop_with_ref, AnEnum): json_union_prop_with_ref = UNSET if not isinstance(union_prop_with_ref, Unset): - json_union_prop_with_ref = union_prop_with_ref + json_union_prop_with_ref = union_prop_with_ref.value else: json_union_prop_with_ref = union_prop_with_ref - json_enum_prop: Union[Unset, AnEnum] = UNSET + json_enum_prop: Union[Unset, None, int] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop + json_enum_prop = enum_prop.value if enum_prop else None - json_model_prop: Union[Unset, Dict[str, Any]] = UNSET + json_model_prop: Union[Unset, None, Dict[str, Any]] = UNSET if not isinstance(model_prop, Unset): - json_model_prop = model_prop.to_dict() + json_model_prop = model_prop.to_dict() if model_prop else None - params: Dict[str, Any] = {} + params: Dict[str, Any] = { + "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, + } if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: - params["datetime_prop"] = json_datetime_prop + if ( + not isinstance(json_not_required_not_nullable_datetime_prop, Unset) + and json_not_required_not_nullable_datetime_prop is not None + ): + params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop + if ( + not isinstance(json_not_required_nullable_datetime_prop, Unset) + and json_not_required_nullable_datetime_prop is not None + ): + params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop + if json_required_nullable_datetime_prop is not None: + params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop if not isinstance(float_prop, Unset) and float_prop is not None: diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py index 616dc4252..279ce8ca8 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py @@ -36,12 +36,15 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def httpx_request( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: - json_query_param: Union[Unset, List[Any]] = UNSET + json_query_param: Union[Unset, None, List[Any]] = UNSET if not isinstance(query_param, Unset): - json_query_param = query_param + if query_param is None: + json_query_param = None + else: + json_query_param = query_param params: Dict[str, Any] = {} if not isinstance(json_query_param, Unset) and json_query_param is not None: diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 15a7cc68c..9462c38b9 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -27,10 +27,10 @@ class AModel: nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET - not_required_nullable: Union[Unset, Optional[str]] = UNSET + not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -68,7 +68,7 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_model, Unset): not_required_model = self.not_required_model.to_dict() - not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET + not_required_nullable_model: Union[Unset, None, Dict[str, Any]] = UNSET if not isinstance(self.not_required_nullable_model, Unset): not_required_nullable_model = ( self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None @@ -158,7 +158,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat if _nullable_model is not None: nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) if not isinstance(_not_required_model, Unset): not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py index c1a00c152..0700798c8 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -15,18 +15,18 @@ class AModelModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py index adecb4225..a08f547aa 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -15,18 +15,18 @@ class AModelNotRequiredModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py index 9de2e3798..52ee2ddc3 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -15,18 +15,18 @@ class AModelNotRequiredNullableModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py index cbcf120f8..2f21cc5ac 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -15,18 +15,18 @@ class AModelNullableModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index 797c1ce31..1ba447347 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -12,7 +12,7 @@ class ModelWithPrimitiveAdditionalProperties: """ """ - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET additional_properties: Dict[str, str] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -31,7 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @staticmethod def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index cbecc7c90..35bc2a853 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -14,18 +14,18 @@ class ModelWithUnionProperty: a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update({}) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/types.py b/end_to_end_tests/golden-record-custom/custom_e2e/types.py index 2061b9f08..a354a2192 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/types.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index ff6ef2409..f87317ead 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -14,68 +14,104 @@ def _get_kwargs( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/defaults".format(client.base_url) headers: Dict[str, Any] = client.get_headers() - json_datetime_prop: Union[Unset, str] = UNSET - if not isinstance(datetime_prop, Unset): - json_datetime_prop = datetime_prop.isoformat() + json_not_required_not_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_not_nullable_datetime_prop, Unset): + json_not_required_not_nullable_datetime_prop = ( + not_required_not_nullable_datetime_prop.isoformat() if not_required_not_nullable_datetime_prop else None + ) + + json_not_required_nullable_datetime_prop: Union[Unset, None, str] = UNSET + if not isinstance(not_required_nullable_datetime_prop, Unset): + json_not_required_nullable_datetime_prop = ( + not_required_nullable_datetime_prop.isoformat() if not_required_nullable_datetime_prop else None + ) + + json_required_not_nullable_datetime_prop = required_not_nullable_datetime_prop.isoformat() - json_date_prop: Union[Unset, str] = UNSET + json_required_nullable_datetime_prop = ( + required_nullable_datetime_prop.isoformat() if required_nullable_datetime_prop else None + ) + + json_date_prop: Union[Unset, None, str] = UNSET if not isinstance(date_prop, Unset): - json_date_prop = date_prop.isoformat() + json_date_prop = date_prop.isoformat() if date_prop else None - json_list_prop: Union[Unset, List[Any]] = UNSET + json_list_prop: Union[Unset, None, List[Any]] = UNSET if not isinstance(list_prop, Unset): - json_list_prop = [] - for list_prop_item_data in list_prop: - list_prop_item = list_prop_item_data.value + if list_prop is None: + json_list_prop = None + else: + json_list_prop = [] + for list_prop_item_data in list_prop: + list_prop_item = list_prop_item_data.value - json_list_prop.append(list_prop_item) + json_list_prop.append(list_prop_item) - json_union_prop: Union[Unset, float, str] + json_union_prop: Union[Unset, None, float, str] if isinstance(union_prop, Unset): json_union_prop = UNSET + elif union_prop is None: + json_union_prop = None else: json_union_prop = union_prop - json_union_prop_with_ref: Union[Unset, float, AnEnum] + json_union_prop_with_ref: Union[Unset, None, float, int] if isinstance(union_prop_with_ref, Unset): json_union_prop_with_ref = UNSET + elif union_prop_with_ref is None: + json_union_prop_with_ref = None elif isinstance(union_prop_with_ref, AnEnum): json_union_prop_with_ref = UNSET if not isinstance(union_prop_with_ref, Unset): - json_union_prop_with_ref = union_prop_with_ref + json_union_prop_with_ref = union_prop_with_ref.value else: json_union_prop_with_ref = union_prop_with_ref - json_enum_prop: Union[Unset, AnEnum] = UNSET + json_enum_prop: Union[Unset, None, int] = UNSET if not isinstance(enum_prop, Unset): - json_enum_prop = enum_prop + json_enum_prop = enum_prop.value if enum_prop else None - json_model_prop: Union[Unset, Dict[str, Any]] = UNSET + json_model_prop: Union[Unset, None, Dict[str, Any]] = UNSET if not isinstance(model_prop, Unset): - json_model_prop = model_prop.to_dict() + json_model_prop = model_prop.to_dict() if model_prop else None - params: Dict[str, Any] = {} + params: Dict[str, Any] = { + "required_not_nullable_datetime_prop": json_required_not_nullable_datetime_prop, + } if not isinstance(string_prop, Unset) and string_prop is not None: params["string_prop"] = string_prop - if not isinstance(json_datetime_prop, Unset) and json_datetime_prop is not None: - params["datetime_prop"] = json_datetime_prop + if ( + not isinstance(json_not_required_not_nullable_datetime_prop, Unset) + and json_not_required_not_nullable_datetime_prop is not None + ): + params["not_required_not_nullable_datetime_prop"] = json_not_required_not_nullable_datetime_prop + if ( + not isinstance(json_not_required_nullable_datetime_prop, Unset) + and json_not_required_nullable_datetime_prop is not None + ): + params["not_required_nullable_datetime_prop"] = json_not_required_nullable_datetime_prop + if json_required_nullable_datetime_prop is not None: + params["required_nullable_datetime_prop"] = json_required_nullable_datetime_prop if not isinstance(json_date_prop, Unset) and json_date_prop is not None: params["date_prop"] = json_date_prop if not isinstance(float_prop, Unset) and float_prop is not None: @@ -128,22 +164,28 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def sync_detailed( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -165,24 +207,30 @@ def sync_detailed( def sync( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ return sync_detailed( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -198,22 +246,28 @@ def sync( async def asyncio_detailed( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, @@ -234,17 +288,20 @@ async def asyncio_detailed( async def asyncio( *, client: Client, - string_prop: Union[Unset, str] = "the default string", - datetime_prop: Union[Unset, datetime.datetime] = isoparse("1010-10-10T00:00:00"), - date_prop: Union[Unset, datetime.date] = isoparse("1010-10-10").date(), - float_prop: Union[Unset, float] = 3.14, - int_prop: Union[Unset, int] = 7, - boolean_prop: Union[Unset, bool] = False, - list_prop: Union[Unset, List[AnEnum]] = UNSET, - union_prop: Union[Unset, float, str] = "not a float", - union_prop_with_ref: Union[Unset, float, AnEnum] = 0.6, - enum_prop: Union[Unset, AnEnum] = UNSET, - model_prop: Union[ModelWithUnionProperty, Unset] = UNSET, + string_prop: Union[Unset, None, str] = "the default string", + not_required_not_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + not_required_nullable_datetime_prop: Union[Unset, None, datetime.datetime] = isoparse("1010-10-10T00:00:00"), + required_not_nullable_datetime_prop: datetime.datetime = isoparse("1010-10-10T00:00:00"), + required_nullable_datetime_prop: Optional[datetime.datetime] = isoparse("1010-10-10T00:00:00"), + date_prop: Union[Unset, None, datetime.date] = isoparse("1010-10-10").date(), + float_prop: Union[Unset, None, float] = 3.14, + int_prop: Union[Unset, None, int] = 7, + boolean_prop: Union[Unset, None, bool] = False, + list_prop: Union[Unset, None, List[AnEnum]] = UNSET, + union_prop: Union[Unset, None, float, str] = "not a float", + union_prop_with_ref: Union[Unset, None, float, AnEnum] = 0.6, + enum_prop: Union[Unset, None, AnEnum] = UNSET, + model_prop: Union[Unset, None, ModelWithUnionProperty] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ """ @@ -252,7 +309,10 @@ async def asyncio( await asyncio_detailed( client=client, string_prop=string_prop, - datetime_prop=datetime_prop, + not_required_not_nullable_datetime_prop=not_required_not_nullable_datetime_prop, + not_required_nullable_datetime_prop=not_required_nullable_datetime_prop, + required_not_nullable_datetime_prop=required_not_nullable_datetime_prop, + required_nullable_datetime_prop=required_nullable_datetime_prop, date_prop=date_prop, float_prop=float_prop, int_prop=int_prop, diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 576a770fe..23bd9e741 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -10,15 +10,18 @@ def _get_kwargs( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Dict[str, Any]: url = "{}/tests/optional_query_param/".format(client.base_url) headers: Dict[str, Any] = client.get_headers() - json_query_param: Union[Unset, List[Any]] = UNSET + json_query_param: Union[Unset, None, List[Any]] = UNSET if not isinstance(query_param, Unset): - json_query_param = query_param + if query_param is None: + json_query_param = None + else: + json_query_param = query_param params: Dict[str, Any] = {} if not isinstance(json_query_param, Unset) and json_query_param is not None: @@ -57,7 +60,7 @@ def _build_response(*, response: httpx.Response) -> Response[Union[None, HTTPVal def sync_detailed( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -74,7 +77,7 @@ def sync_detailed( def sync( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ Test optional query parameters """ @@ -87,7 +90,7 @@ def sync( async def asyncio_detailed( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Response[Union[None, HTTPValidationError]]: kwargs = _get_kwargs( client=client, @@ -103,7 +106,7 @@ async def asyncio_detailed( async def asyncio( *, client: Client, - query_param: Union[Unset, List[str]] = UNSET, + query_param: Union[Unset, None, List[str]] = UNSET, ) -> Optional[Union[None, HTTPValidationError]]: """ Test optional query parameters """ diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 15a7cc68c..9462c38b9 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -27,10 +27,10 @@ class AModel: nullable_model: Optional[AModelNullableModel] nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET - not_required_nullable: Union[Unset, Optional[str]] = UNSET + not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET - not_required_nullable_model: Union[Optional[AModelNotRequiredNullableModel], Unset] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET + not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -68,7 +68,7 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_model, Unset): not_required_model = self.not_required_model.to_dict() - not_required_nullable_model: Union[None, Unset, Dict[str, Any]] = UNSET + not_required_nullable_model: Union[Unset, None, Dict[str, Any]] = UNSET if not isinstance(self.not_required_nullable_model, Unset): not_required_nullable_model = ( self.not_required_nullable_model.to_dict() if self.not_required_nullable_model else None @@ -158,7 +158,7 @@ def _parse_a_camel_date_time(data: Any) -> Union[datetime.datetime, datetime.dat if _nullable_model is not None: nullable_model = AModelNullableModel.from_dict(cast(Dict[str, Any], _nullable_model)) - not_required_model: Union[AModelNotRequiredModel, Unset] = UNSET + not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET _not_required_model = d.pop("not_required_model", UNSET) if not isinstance(_not_required_model, Unset): not_required_model = AModelNotRequiredModel.from_dict(cast(Dict[str, Any], _not_required_model)) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py index c1a00c152..0700798c8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -15,18 +15,18 @@ class AModelModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py index adecb4225..a08f547aa 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -15,18 +15,18 @@ class AModelNotRequiredModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py index 9de2e3798..52ee2ddc3 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -15,18 +15,18 @@ class AModelNotRequiredNullableModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py index cbcf120f8..2f21cc5ac 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -15,18 +15,18 @@ class AModelNullableModel: additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index 797c1ce31..1ba447347 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -12,7 +12,7 @@ class ModelWithPrimitiveAdditionalProperties: """ """ - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET additional_properties: Dict[str, str] = attr.ib(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -31,7 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @staticmethod def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() - a_date_holder: Union[ModelWithPrimitiveAdditionalPropertiesADateHolder, Unset] = UNSET + a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET _a_date_holder = d.pop("a_date_holder", UNSET) if not isinstance(_a_date_holder, Unset): a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict( diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index cbecc7c90..35bc2a853 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -14,18 +14,18 @@ class ModelWithUnionProperty: a_property: Union[Unset, AnEnum, AnIntEnum] = UNSET def to_dict(self) -> Dict[str, Any]: - a_property: Union[Unset, AnEnum, AnIntEnum] + a_property: Union[Unset, int] if isinstance(self.a_property, Unset): a_property = UNSET elif isinstance(self.a_property, AnEnum): a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value else: a_property = UNSET if not isinstance(self.a_property, Unset): - a_property = self.a_property + a_property = self.a_property.value field_dict: Dict[str, Any] = {} field_dict.update({}) diff --git a/end_to_end_tests/golden-record/my_test_api_client/types.py b/end_to_end_tests/golden-record/my_test_api_client/types.py index 2061b9f08..a354a2192 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/types.py +++ b/end_to_end_tests/golden-record/my_test_api_client/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 8562f6796..6d7d15c6c 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -290,12 +290,49 @@ { "required": false, "schema": { - "title": "Datetime Prop", + "title": "Not Required, Not Nullable Datetime Prop", + "nullable": false, "type": "string", "format": "date-time", "default": "1010-10-10T00:00:00" }, - "name": "datetime_prop", + "name": "not_required_not_nullable_datetime_prop", + "in": "query" + }, + { + "required": false, + "schema": { + "title": "Not Required, Nullable Datetime Prop", + "nullable": true, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "not_required_nullable_datetime_prop", + "in": "query" + }, + { + "required": true, + "schema": { + "title": "Required, Not Nullable Datetime Prop", + "nullable": false, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "required_not_nullable_datetime_prop", + "in": "query" + }, + { + "required": true, + "schema": { + "title": "Required, Nullable Datetime Prop", + "nullable": true, + "type": "string", + "format": "date-time", + "default": "1010-10-10T00:00:00" + }, + "name": "required_nullable_datetime_prop", "in": "query" }, { diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index f6289ce7c..b84166f23 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -19,6 +19,7 @@ class NoneProperty(Property): """ A property that is always None (used for empty schemas) """ _type_string: ClassVar[str] = "None" + _json_type_string: ClassVar[str] = "None" template: ClassVar[Optional[str]] = "none_property.pyi" @@ -29,6 +30,7 @@ class StringProperty(Property): max_length: Optional[int] = None pattern: Optional[str] = None _type_string: ClassVar[str] = "str" + _json_type_string: ClassVar[str] = "str" @attr.s(auto_attribs=True, frozen=True) @@ -38,6 +40,7 @@ class DateTimeProperty(Property): """ _type_string: ClassVar[str] = "datetime.datetime" + _json_type_string: ClassVar[str] = "str" template: ClassVar[str] = "datetime_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -58,6 +61,7 @@ class DateProperty(Property): """ A property of type datetime.date """ _type_string: ClassVar[str] = "datetime.date" + _json_type_string: ClassVar[str] = "str" template: ClassVar[str] = "date_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -78,6 +82,8 @@ class FileProperty(Property): """ A property used for uploading files """ _type_string: ClassVar[str] = "File" + # Return type of File.to_tuple() + _json_type_string: ClassVar[str] = "Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]" template: ClassVar[str] = "file_property.pyi" def get_imports(self, *, prefix: str) -> Set[str]: @@ -98,6 +104,7 @@ class FloatProperty(Property): """ A property of type float """ _type_string: ClassVar[str] = "float" + _json_type_string: ClassVar[str] = "float" @attr.s(auto_attribs=True, frozen=True) @@ -105,6 +112,7 @@ class IntProperty(Property): """ A property of type int """ _type_string: ClassVar[str] = "int" + _json_type_string: ClassVar[str] = "int" @attr.s(auto_attribs=True, frozen=True) @@ -112,6 +120,7 @@ class BooleanProperty(Property): """ Property for bool """ _type_string: ClassVar[str] = "bool" + _json_type_string: ClassVar[str] = "bool" InnerProp = TypeVar("InnerProp", bound=Property) @@ -122,18 +131,11 @@ class ListProperty(Property, Generic[InnerProp]): """ A property representing a list (array) of other properties """ inner_property: InnerProp + _json_type_string: ClassVar[str] = "List[Any]" template: ClassVar[str] = "list_property.pyi" - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - type_string = f"List[{self.inner_property.get_type_string()}]" - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + def get_base_type_string(self) -> str: + return f"List[{self.inner_property.get_type_string()}]" def get_instance_type_string(self) -> str: """Get a string representation of runtime type that should be used for `isinstance` checks""" @@ -167,18 +169,38 @@ def __attrs_post_init__(self) -> None: self, "has_properties_without_templates", any(prop.template is None for prop in self.inner_properties) ) - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - inner_types = [p.get_type_string(no_optional=True) for p in self.inner_properties] - inner_prop_string = ", ".join(inner_types) - type_string = f"Union[{inner_prop_string}]" + def _get_inner_prop_string(self, json: bool = False) -> str: + inner_types = [p.get_type_string(no_optional=True, json=json) for p in self.inner_properties] + unique_inner_types = list(dict.fromkeys(inner_types)) + return ", ".join(unique_inner_types) + + def get_base_type_string(self, json: bool = False) -> str: + return f"Union[{self._get_inner_prop_string(json=json)}]" + + def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: + """ + Get a string representation of type that should be used when declaring this property. + + This implementation differs slightly from `Property.get_type_string` in order to collapse + nested union types. + """ + type_string = self.get_base_type_string(json=json) if no_optional: return type_string - if not self.required: - type_string = f"Union[Unset, {inner_prop_string}]" - if self.nullable: - type_string = f"Optional[{type_string}]" - return type_string + if self.required: + if self.nullable: + return f"Union[None, {self._get_inner_prop_string(json=json)}]" + else: + return type_string + else: + if self.nullable: + return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + else: + if query_parameter: + # For query parameters, None has the same meaning as Unset + return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + else: + return f"Union[Unset, {self._get_inner_prop_string(json=json)}]" def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/parser/properties/enum_property.py b/openapi_python_client/parser/properties/enum_property.py index 1217f23ee..6938dd716 100644 --- a/openapi_python_client/parser/properties/enum_property.py +++ b/openapi_python_client/parser/properties/enum_property.py @@ -18,21 +18,13 @@ class EnumProperty(Property): values: Dict[str, ValueType] reference: Reference value_type: Type[ValueType] + _json_type_string: ClassVar[str] = "int" default: Optional[Any] = attr.ib() template: ClassVar[str] = "enum_property.pyi" - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - - type_string = self.reference.class_name - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + def get_base_type_string(self) -> str: + return self.reference.class_name def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/parser/properties/model_property.py b/openapi_python_client/parser/properties/model_property.py index 4bcbe4695..c4c203a5d 100644 --- a/openapi_python_client/parser/properties/model_property.py +++ b/openapi_python_client/parser/properties/model_property.py @@ -25,6 +25,7 @@ class ModelProperty(Property): description: str relative_imports: Set[str] additional_properties: Union[bool, Property] + _json_type_string: ClassVar[str] = "Dict[str, Any]" template: ClassVar[str] = "model_property.pyi" json_is_dict: ClassVar[bool] = True @@ -72,16 +73,8 @@ def resolve_references( return schemas - def get_type_string(self, no_optional: bool = False) -> str: - """ Get a string representation of type that should be used when declaring this property """ - type_string = self.reference.class_name - if no_optional: - return type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[{type_string}, Unset]" - return type_string + def get_base_type_string(self) -> str: + return self.reference.class_name def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/parser/properties/property.py b/openapi_python_client/parser/properties/property.py index a94af72ba..c0ec0d56e 100644 --- a/openapi_python_client/parser/properties/property.py +++ b/openapi_python_client/parser/properties/property.py @@ -24,6 +24,7 @@ class Property: required: bool nullable: bool _type_string: ClassVar[str] = "" + _json_type_string: ClassVar[str] = "" # Type of the property after JSON serialization default: Optional[str] = attr.ib() python_name: str = attr.ib(init=False) @@ -33,21 +34,39 @@ class Property: def __attrs_post_init__(self) -> None: object.__setattr__(self, "python_name", utils.to_valid_python_identifier(utils.snake_case(self.name))) - def get_type_string(self, no_optional: bool = False) -> str: + def get_base_type_string(self) -> str: + return self._type_string + + def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: """ Get a string representation of type that should be used when declaring this property Args: no_optional: Do not include Optional or Unset even if the value is optional (needed for isinstance checks) + query_parameter: True if the property's type is being used for a query parameter + json: True if the type refers to the property after JSON serialization """ - type_string = self._type_string + if json: + type_string = self._json_type_string + else: + type_string = self.get_base_type_string() + if no_optional: - return self._type_string - if self.nullable: - type_string = f"Optional[{type_string}]" - if not self.required: - type_string = f"Union[Unset, {type_string}]" - return type_string + return type_string + if self.required: + if self.nullable: + return f"Optional[{type_string}]" + else: + return type_string + else: + if self.nullable: + return f"Union[Unset, None, {type_string}]" + else: + if query_parameter: + # For query parameters, None has the same meaning as Unset + return f"Union[Unset, None, {type_string}]" + else: + return f"Union[Unset, {type_string}]" def get_instance_type_string(self) -> str: """Get a string representation of runtime type that should be used for `isinstance` checks""" @@ -70,8 +89,13 @@ def get_imports(self, *, prefix: str) -> Set[str]: imports.add(f"from {prefix}types import UNSET, Unset") return imports - def to_string(self) -> str: - """ How this should be declared in a dataclass """ + def to_string(self, query_parameter: bool = False) -> str: + """ + How this should be declared in a dataclass + + Args: + query_parameter: True if the property's type is being used for a query parameter + """ default: Optional[str] if self.default is not None: default = self.default @@ -81,6 +105,6 @@ def to_string(self) -> str: default = None if default is not None: - return f"{self.python_name}: {self.get_type_string()} = {default}" + return f"{self.python_name}: {self.get_type_string(query_parameter=query_parameter)} = {default}" else: - return f"{self.python_name}: {self.get_type_string()}" + return f"{self.python_name}: {self.get_type_string(query_parameter=query_parameter)}" diff --git a/openapi_python_client/templates/endpoint_macros.pyi b/openapi_python_client/templates/endpoint_macros.pyi index 8d3d464c3..6586ecd70 100644 --- a/openapi_python_client/templates/endpoint_macros.pyi +++ b/openapi_python_client/templates/endpoint_macros.pyi @@ -17,12 +17,12 @@ if {{ parameter.python_name }} is not UNSET: {% set destination = "json_" + property.python_name %} {% if property.template %} {% from "property_templates/" + property.template import transform %} -{{ transform(property, property.python_name, destination) }} +{{ transform(property, property.python_name, destination, query_parameter=True) }} {% endif %} {% endfor %} params: Dict[str, Any] = { {% for property in endpoint.query_parameters %} - {% if property.required %} + {% if property.required and not property.nullable %} {% if property.template %} "{{ property.name }}": {{ "json_" + property.python_name }}, {% else %} @@ -32,7 +32,7 @@ params: Dict[str, Any] = { {% endfor %} } {% for property in endpoint.query_parameters %} - {% if not property.required %} + {% if not property.required or property.nullable %} {% set property_name = "json_" + property.python_name if property.template else property.python_name %} if {% if not property.required %}not isinstance({{ property_name }}, Unset) and {% endif %}{{ property_name }} is not None: {% if property.json_is_dict %} @@ -97,7 +97,7 @@ json_body: {{ endpoint.json_body.get_type_string() }}, {% endif %} {# query parameters #} {% for parameter in endpoint.query_parameters %} -{{ parameter.to_string() }}, +{{ parameter.to_string(query_parameter=True) }}, {% endfor %} {% for parameter in endpoint.header_parameters %} {{ parameter.to_string() }}, diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index a3a980c8f..bc2cae912 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -9,13 +9,13 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {{ destination }} = {{ source }}.isoformat() {% if property.nullable %}if {{ source }} else None {%endif%} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.isoformat() diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index b8e1b8ff0..91ce0cacc 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -14,7 +14,7 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None @@ -22,9 +22,9 @@ if _{{ property.python_name }} is not None: {{ destination }} = {{ source }}.isoformat() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, str]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.isoformat() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.isoformat() diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 4765a6fd5..831f633d5 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -9,7 +9,7 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.value if {{ source }} else None @@ -17,12 +17,12 @@ if _{{ property.python_name }} is not None: {{ destination }} = {{ source }}.value {% endif %} {% else %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} - {{ destination }} = {{ source }} if {{ source }} else None +{% if property.nullable or query_parameter %} + {{ destination }} = {{ source }}.value if {{ source }} else None {% else %} - {{ destination }} = {{ source }} + {{ destination }} = {{ source }}.value {% endif %} {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/file_property.pyi b/openapi_python_client/templates/property_templates/file_property.pyi index ffa3c20d9..50a331851 100644 --- a/openapi_python_client/templates/property_templates/file_property.pyi +++ b/openapi_python_client/templates/property_templates/file_property.pyi @@ -4,7 +4,7 @@ ) {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None @@ -12,9 +12,9 @@ {{ destination }} = {{ source }}.to_tuple() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.to_tuple() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.to_tuple() diff --git a/openapi_python_client/templates/property_templates/list_property.pyi b/openapi_python_client/templates/property_templates/list_property.pyi index d05a13960..5f58bcd30 100644 --- a/openapi_python_client/templates/property_templates/list_property.pyi +++ b/openapi_python_client/templates/property_templates/list_property.pyi @@ -32,7 +32,7 @@ for {{ inner_source }} in {{ source }}: {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% set inner_property = property.inner_property %} {% if property.required %} {% if property.nullable %} @@ -44,13 +44,13 @@ else: {{ _transform(property, source, destination) }} {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[Unset, List[Any]]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} if {{ source }} is None: {{ destination }} = None else: - {{ _transform(property, source, destination) | indent(4)}} + {{ _transform(property, source, destination) | indent(8)}} {% else %} {{ _transform(property, source, destination) | indent(4)}} {% endif %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index b41289409..6aef71d0f 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -15,7 +15,7 @@ if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{ {% endif %} {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None @@ -23,9 +23,9 @@ if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{ {{ destination }} = {{ source }}.to_dict() {% endif %} {% else %} -{{ destination }}{% if declare_type %}: Union[{% if property.nullable %}None, {% endif %}Unset, Dict[str, Any]]{% endif %} = UNSET +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} = UNSET if not isinstance({{ source }}, Unset): -{% if property.nullable %} +{% if property.nullable or query_parameter %} {{ destination }} = {{ source }}.to_dict() if {{ source }} else None {% else %} {{ destination }} = {{ source }}.to_dict() diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index 4c632c60a..509c7f34e 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -24,20 +24,20 @@ def _parse_{{ property.python_name }}(data: Any) -> {{ property.get_type_string( {{ property.python_name }} = _parse_{{ property.python_name }}({{ source }}) {% endmacro %} -{% macro transform(property, source, destination, declare_type=True) %} -{% if not property.required %} -{{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} +{% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} +{% if not property.required or property.nullable %} +{{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} if isinstance({{ source }}, Unset): {{ destination }} = UNSET {% endif %} -{% if property.nullable %} +{% if property.nullable or (query_parameter and not property.required) %} {% if property.required %} if {{ source }} is None: {% else %}{# There's an if UNSET statement before this #} elif {{ source }} is None: {% endif %} - {{ destination }}{% if declare_type %}: {{ property.get_type_string() }}{% endif %} = None + {{ destination }} = None {% endif %} {% for inner_property in property.inner_properties_with_template() %} {% if loop.first and property.required and not property.nullable %}{# No if UNSET or if None statement before this #} diff --git a/openapi_python_client/templates/types.py b/openapi_python_client/templates/types.py index 2061b9f08..a354a2192 100644 --- a/openapi_python_client/templates/types.py +++ b/openapi_python_client/templates/types.py @@ -11,6 +11,9 @@ def __bool__(self) -> bool: UNSET: Unset = Unset() +# Used as `FileProperty._json_type_string` +FileJsonType = Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]] + @attr.s(auto_attribs=True) class File: @@ -20,7 +23,7 @@ class File: file_name: Optional[str] = None mime_type: Optional[str] = None - def to_tuple(self) -> Tuple[Optional[str], Union[BinaryIO, TextIO], Optional[str]]: + def to_tuple(self) -> FileJsonType: """ Return a tuple representation that httpx will accept for multipart/form-data """ return self.file_name, self.payload, self.mime_type diff --git a/pyproject.toml b/pyproject.toml index 222b69561..4d74fea82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,8 +55,9 @@ isort .\ && flake8 openapi_python_client\ && safety check --bare\ && mypy openapi_python_client\ - && pytest --cov openapi_python_client tests --cov-report=term-missing\ + && task unit\ """ +unit = "pytest --cov openapi_python_client tests --cov-report=term-missing" regen = "python -m end_to_end_tests.regen_golden_record" regen_custom = "python -m end_to_end_tests.regen_golden_record custom" e2e = "pytest openapi_python_client end_to_end_tests/test_end_to_end.py" diff --git a/tests/test_parser/test_properties/test_init.py b/tests/test_parser/test_properties/test_init.py index 2f3c13676..604b1bd1d 100644 --- a/tests/test_parser/test_properties/test_init.py +++ b/tests/test_parser/test_properties/test_init.py @@ -16,45 +16,55 @@ class TestProperty: - def test_get_type_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,nullable,required,no_optional,expected", + [ + (False, False, False, False, "Union[Unset, TestType]"), + (False, False, False, True, "TestType"), + (False, False, True, False, "TestType"), + (False, False, True, True, "TestType"), + (False, True, False, False, "Union[Unset, None, TestType]"), + (False, True, False, True, "TestType"), + (False, True, True, False, "Optional[TestType]"), + (False, True, True, True, "TestType"), + (True, False, False, False, "Union[Unset, None, TestType]"), + (True, False, False, True, "TestType"), + (True, False, True, False, "TestType"), + (True, False, True, True, "TestType"), + (True, True, False, False, "Union[Unset, None, TestType]"), + (True, True, False, True, "TestType"), + (True, True, True, False, "Optional[TestType]"), + (True, True, True, True, "TestType"), + ], + ) + def test_get_type_string(self, mocker, query_parameter, nullable, required, no_optional, expected): from openapi_python_client.parser.properties import Property mocker.patch.object(Property, "_type_string", "TestType") - p = Property(name="test", required=True, default=None, nullable=False) - - base_type_string = f"TestType" - - assert p.get_type_string() == base_type_string + p = Property(name="test", required=required, default=None, nullable=nullable) + assert p.get_type_string(no_optional=no_optional, query_parameter=query_parameter) == expected - p = Property(name="test", required=True, default=None, nullable=True) - assert p.get_type_string() == f"Optional[{base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - p = Property(name="test", required=False, default=None, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" - assert p.get_type_string(no_optional=True) == base_type_string - - p = Property(name="test", required=False, default=None, nullable=False) - assert p.get_type_string() == f"Union[Unset, {base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - def test_to_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,default,required,expected", + [ + (False, None, False, "test: Union[Unset, TestType] = UNSET"), + (False, None, True, "test: TestType"), + (False, "Test", False, "test: Union[Unset, TestType] = Test"), + (False, "Test", True, "test: TestType = Test"), + (True, None, False, "test: Union[Unset, None, TestType] = UNSET"), + (True, None, True, "test: TestType"), + (True, "Test", False, "test: Union[Unset, None, TestType] = Test"), + (True, "Test", True, "test: TestType = Test"), + ], + ) + def test_to_string(self, mocker, query_parameter, default, required, expected): from openapi_python_client.parser.properties import Property name = "test" - get_type_string = mocker.patch.object(Property, "get_type_string") - p = Property(name=name, required=True, default=None, nullable=False) - - assert p.to_string() == f"{name}: {get_type_string()}" - - p = Property(name=name, required=False, default=None, nullable=False) - assert p.to_string() == f"{name}: {get_type_string()} = UNSET" - - p = Property(name=name, required=True, default=None, nullable=False) - assert p.to_string() == f"{name}: {get_type_string()}" + mocker.patch.object(Property, "_type_string", "TestType") + p = Property(name=name, required=required, default=default, nullable=False) - p = Property(name=name, required=True, default="TEST", nullable=False) - assert p.to_string() == f"{name}: {get_type_string()} = TEST" + assert p.to_string(query_parameter=query_parameter) == expected def test_get_imports(self): from openapi_python_client.parser.properties import Property @@ -87,7 +97,7 @@ def test_get_type_string(self): assert p.get_type_string() == f"Optional[{base_type_string}]" p = StringProperty(name="test", required=False, default=None, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" p = StringProperty(name="test", required=False, default=None, nullable=False) assert p.get_type_string() == f"Union[Unset, {base_type_string}]" @@ -202,7 +212,7 @@ def test_get_type_string(self, mocker): assert p.get_type_string(no_optional=True) == base_type_string p = ListProperty(name="test", required=False, default=None, inner_property=inner_property, nullable=True) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" assert p.get_type_string(no_optional=True) == base_type_string p = ListProperty(name="test", required=False, default=None, inner_property=inner_property, nullable=False) @@ -242,7 +252,28 @@ def test_get_type_imports(self, mocker): class TestUnionProperty: - def test_get_type_string(self, mocker): + @pytest.mark.parametrize( + "query_parameter,nullable,required,no_optional,expected", + [ + (False, False, False, False, "Union[Unset, inner_type_string_1, inner_type_string_2]"), + (False, False, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, False, True, False, "Union[inner_type_string_1, inner_type_string_2]"), + (False, False, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, True, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (False, True, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (False, True, True, False, "Union[None, inner_type_string_1, inner_type_string_2]"), + (False, True, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (True, False, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, True, False, "Union[inner_type_string_1, inner_type_string_2]"), + (True, False, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, True, False, False, "Union[Unset, None, inner_type_string_1, inner_type_string_2]"), + (True, True, False, True, "Union[inner_type_string_1, inner_type_string_2]"), + (True, True, True, False, "Union[None, inner_type_string_1, inner_type_string_2]"), + (True, True, True, True, "Union[inner_type_string_1, inner_type_string_2]"), + ], + ) + def test_get_type_string(self, mocker, query_parameter, nullable, required, no_optional, expected): from openapi_python_client.parser.properties import UnionProperty inner_property_1 = mocker.MagicMock() @@ -251,46 +282,13 @@ def test_get_type_string(self, mocker): inner_property_2.get_type_string.return_value = "inner_type_string_2" p = UnionProperty( name="test", - required=True, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=False, - ) - - base_type_string = f"Union[inner_type_string_1, inner_type_string_2]" - - assert p.get_type_string() == base_type_string - - p = UnionProperty( - name="test", - required=True, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=True, - ) - assert p.get_type_string() == f"Optional[{base_type_string}]" - assert p.get_type_string(no_optional=True) == base_type_string - - base_type_string_with_unset = f"Union[Unset, inner_type_string_1, inner_type_string_2]" - p = UnionProperty( - name="test", - required=False, + required=required, default=None, inner_properties=[inner_property_1, inner_property_2], - nullable=True, + nullable=nullable, ) - assert p.get_type_string() == f"Optional[{base_type_string_with_unset}]" - assert p.get_type_string(no_optional=True) == base_type_string - p = UnionProperty( - name="test", - required=False, - default=None, - inner_properties=[inner_property_1, inner_property_2], - nullable=False, - ) - assert p.get_type_string() == base_type_string_with_unset - assert p.get_type_string(no_optional=True) == base_type_string + assert p.get_type_string(query_parameter=query_parameter, no_optional=no_optional) == expected def test_get_imports(self, mocker): from openapi_python_client.parser.properties import UnionProperty @@ -389,7 +387,7 @@ def test_get_type_string(self, mocker): reference=fake_reference, value_type=str, ) - assert p.get_type_string() == f"Union[Unset, Optional[{base_type_string}]]" + assert p.get_type_string() == f"Union[Unset, None, {base_type_string}]" assert p.get_type_string(no_optional=True) == base_type_string p = properties.EnumProperty( @@ -990,7 +988,6 @@ def test__string_based_property_unsupported_format(self, mocker): def test_build_schemas(mocker): build_model_property = mocker.patch(f"{MODULE_NAME}.build_model_property") in_data = {"1": mocker.MagicMock(enum=None), "2": mocker.MagicMock(enum=None), "3": mocker.MagicMock(enum=None)} - model_1 = mocker.MagicMock() schemas_1 = mocker.MagicMock() model_2 = mocker.MagicMock() diff --git a/tests/test_parser/test_properties/test_model_property.py b/tests/test_parser/test_properties/test_model_property.py index 421f40d48..83d521ab1 100644 --- a/tests/test_parser/test_properties/test_model_property.py +++ b/tests/test_parser/test_properties/test_model_property.py @@ -4,9 +4,9 @@ @pytest.mark.parametrize( "no_optional,nullable,required,expected", [ - (False, False, False, "Union[MyClass, Unset]"), + (False, False, False, "Union[Unset, MyClass]"), (False, False, True, "MyClass"), - (False, True, False, "Union[Optional[MyClass], Unset]"), + (False, True, False, "Union[Unset, None, MyClass]"), (False, True, True, "Optional[MyClass]"), (True, False, False, "MyClass"), (True, False, True, "MyClass"), diff --git a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py index cf8780024..be32cfbd3 100644 --- a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py +++ b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py @@ -6,7 +6,7 @@ some_source = date(2020, 10, 12) -some_destination: Union[Unset, str] = UNSET +some_destination: Union[Unset, None, str] = UNSET if not isinstance(some_source, Unset): some_destination = some_source.isoformat() if some_source else None From 8e88fa49e113ac5e726d9698237ac873704ca27a Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 28 Jan 2021 08:43:11 -0500 Subject: [PATCH 15/18] Refactor --- .../parser/properties/__init__.py | 39 +++++++++++-------- .../property_templates/union_property.pyi | 4 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index b84166f23..96d146a4a 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -169,38 +169,43 @@ def __attrs_post_init__(self) -> None: self, "has_properties_without_templates", any(prop.template is None for prop in self.inner_properties) ) - def _get_inner_prop_string(self, json: bool = False) -> str: + 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] unique_inner_types = list(dict.fromkeys(inner_types)) - return ", ".join(unique_inner_types) + return unique_inner_types def get_base_type_string(self, json: bool = False) -> str: - return f"Union[{self._get_inner_prop_string(json=json)}]" + return f"Union[{', '.join(self._get_inner_type_strings(json=json))}]" - def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: - """ - Get a string representation of type that should be used when declaring this property. - - This implementation differs slightly from `Property.get_type_string` in order to collapse - nested union types. - """ - type_string = self.get_base_type_string(json=json) + def get_type_strings_in_union(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> List[str]: + type_strings = self._get_inner_type_strings(json=json) if no_optional: - return type_string + return type_strings if self.required: if self.nullable: - return f"Union[None, {self._get_inner_prop_string(json=json)}]" + return ["None"] + type_strings else: - return type_string + return type_strings else: if self.nullable: - return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + return ["Unset", "None"] + type_strings else: if query_parameter: # For query parameters, None has the same meaning as Unset - return f"Union[Unset, None, {self._get_inner_prop_string(json=json)}]" + return ["Unset", "None"] + type_strings else: - return f"Union[Unset, {self._get_inner_prop_string(json=json)}]" + return ["Unset"] + type_strings + + def get_type_string(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> str: + """ + Get a string representation of type that should be used when declaring this property. + + This implementation differs slightly from `Property.get_type_string` in order to collapse + nested union types. + """ + return ( + f"Union[{', '.join(self.get_type_strings_in_union(no_optional=no_optional, query_parameter=query_parameter, json=json))}]" + ) def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index d493cb6ba..0d5f09a07 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -1,11 +1,11 @@ {% macro construct(property, source, initial_value=None) %} def _parse_{{ property.python_name }}(data: {{ property.get_type_string(json=True) }}) -> {{ property.get_type_string() }}: {{ property.python_name }}: {{ property.get_type_string() }} - {% if "None" in property.get_type_string(json=True) %} + {% if "None" in property.get_type_strings_in_union(json=True) %} if data is None: return data {% endif %} - {% if "Unset" in property.get_type_string(json=True) %} + {% if "Unset" in property.get_type_strings_in_union(json=True) %} if isinstance(data, Unset): return data {% endif %} From 915d7c34e84eae602f354b8cdd64af3507fa4a57 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 28 Jan 2021 09:06:28 -0500 Subject: [PATCH 16/18] Check type --- .../api/tests/defaults_tests_defaults_post.py | 2 - .../custom_e2e/api/tests/get_user_list.py | 4 -- .../api/tests/int_enum_tests_int_enum_post.py | 2 - .../tests/json_body_tests_json_body_post.py | 2 - ...tional_value_tests_optional_query_param.py | 2 - .../api/tests/test_inline_objects.py | 2 - .../tests/upload_file_tests_upload_post.py | 2 - .../custom_e2e/models/a_model.py | 63 ++++++++++--------- .../custom_e2e/models/a_model_model.py | 4 ++ .../models/a_model_not_required_model.py | 4 ++ .../a_model_not_required_nullable_model.py | 4 ++ .../models/a_model_nullable_model.py | 4 ++ .../models/http_validation_error.py | 2 - ...odel_with_additional_properties_inlined.py | 2 - .../models/model_with_any_json_properties.py | 4 +- ...el_with_primitive_additional_properties.py | 2 - .../models/model_with_union_property.py | 4 ++ .../api/tests/defaults_tests_defaults_post.py | 2 - .../api/tests/get_user_list.py | 4 -- .../api/tests/int_enum_tests_int_enum_post.py | 2 - .../tests/json_body_tests_json_body_post.py | 2 - ...tional_value_tests_optional_query_param.py | 2 - .../api/tests/test_inline_objects.py | 2 - .../tests/upload_file_tests_upload_post.py | 2 - .../my_test_api_client/models/a_model.py | 63 ++++++++++--------- .../models/a_model_model.py | 4 ++ .../models/a_model_not_required_model.py | 4 ++ .../a_model_not_required_nullable_model.py | 4 ++ .../models/a_model_nullable_model.py | 4 ++ .../models/http_validation_error.py | 2 - ...odel_with_additional_properties_inlined.py | 2 - .../models/model_with_any_json_properties.py | 4 +- ...el_with_primitive_additional_properties.py | 2 - .../models/model_with_union_property.py | 4 ++ end_to_end_tests/openapi.json | 3 + .../property_templates/date_property.pyi | 2 + .../property_templates/datetime_property.pyi | 2 + .../property_templates/dict_property.pyi | 2 + .../property_templates/enum_property.pyi | 2 + .../property_templates/file_property.pyi | 2 + .../property_templates/list_property.pyi | 2 + .../property_templates/model_property.pyi | 6 +- .../property_templates/none_property.pyi | 2 + .../property_templates/union_property.pyi | 11 +++- 44 files changed, 138 insertions(+), 114 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py index 0168a4fed..d61560254 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/defaults_tests_defaults_post.py @@ -23,8 +23,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/get_user_list.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/get_user_list.py index c77035a76..72758fd75 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/get_user_list.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/get_user_list.py @@ -19,16 +19,12 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[List[AModel], response_200 = [] _response_200 = response.json() for response_200_item_data in _response_200: - if not isinstance(response_200_item_data, dict): - raise ValueError("Cannot construct model from value " + str(response_200_item_data)) response_200_item = AModel.from_dict(response_200_item_data) response_200.append(response_200_item) return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/int_enum_tests_int_enum_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/int_enum_tests_int_enum_post.py index ec87505f2..855a8d999 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/int_enum_tests_int_enum_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/int_enum_tests_int_enum_post.py @@ -18,8 +18,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/json_body_tests_json_body_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/json_body_tests_json_body_post.py index e9aaa3b81..30f80e33d 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/json_body_tests_json_body_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/json_body_tests_json_body_post.py @@ -16,8 +16,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py index c4e442f62..279ce8ca8 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/optional_value_tests_optional_query_param.py @@ -18,8 +18,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/test_inline_objects.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/test_inline_objects.py index 52163498b..d60561d8a 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/test_inline_objects.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/test_inline_objects.py @@ -12,8 +12,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[TestInlineObjectsResponse_200]: if response.status_code == 200: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_200 = TestInlineObjectsResponse_200.from_dict(response.json()) return response_200 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/upload_file_tests_upload_post.py b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/upload_file_tests_upload_post.py index 72d6720e2..2d084a9e0 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/api/tests/upload_file_tests_upload_post.py @@ -22,8 +22,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[ return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index e120497c0..5f11adb3a 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -36,7 +36,7 @@ class AModel: not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] = UNSET - not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] = UNSET + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -110,7 +110,7 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_one_of_models, Unset): not_required_one_of_models = self.not_required_one_of_models.to_dict() - not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any]] + not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any], str] if isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = UNSET elif self.not_required_nullable_one_of_models is None: @@ -120,11 +120,14 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() - else: + elif isinstance(self.not_required_nullable_one_of_models, ModelWithUnionProperty): not_required_nullable_one_of_models = UNSET if not isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + else: + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models + field_dict: Dict[str, Any] = {} field_dict.update( { @@ -167,11 +170,15 @@ def from_dict(src_dict: Dict[str, Any]) -> "AModel": def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datetime.date]: a_camel_date_time: Union[datetime.datetime, datetime.date] try: + if not isinstance(data, str): + raise TypeError() a_camel_date_time = isoparse(data) return a_camel_date_time except: # noqa: E722 pass + if not isinstance(data, str): + raise TypeError() a_camel_date_time = isoparse(data).date() return a_camel_date_time @@ -182,22 +189,20 @@ def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datet required_not_nullable = d.pop("required_not_nullable") - if not isinstance(d.pop("model"), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("model"))) model = AModelModel.from_dict(d.pop("model")) def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, ModelWithUnionProperty]: one_of_models: Union[FreeFormModel, ModelWithUnionProperty] try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() one_of_models = FreeFormModel.from_dict(data) return one_of_models except: # noqa: E722 pass if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() one_of_models = ModelWithUnionProperty.from_dict(data) return one_of_models @@ -231,24 +236,16 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo nullable_model = None if d.pop("nullable_model") is not None and not isinstance(d.pop("nullable_model"), Unset): - if not isinstance(d.pop("nullable_model"), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("nullable_model"))) nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET if d.pop("not_required_model", UNSET) is not None and not isinstance(d.pop("not_required_model", UNSET), Unset): - if not isinstance(d.pop("not_required_model", UNSET), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("not_required_model", UNSET))) not_required_model = AModelNotRequiredModel.from_dict(d.pop("not_required_model", UNSET)) not_required_nullable_model = None if d.pop("not_required_nullable_model", UNSET) is not None and not isinstance( d.pop("not_required_nullable_model", UNSET), Unset ): - if not isinstance(d.pop("not_required_nullable_model", UNSET), dict): - raise ValueError( - "Cannot construct model from value " + str(d.pop("not_required_nullable_model", UNSET)) - ) not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( d.pop("not_required_nullable_model", UNSET) ) @@ -261,14 +258,14 @@ def _parse_nullable_one_of_models( return data try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() nullable_one_of_models = FreeFormModel.from_dict(data) return nullable_one_of_models except: # noqa: E722 pass if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() nullable_one_of_models = ModelWithUnionProperty.from_dict(data) return nullable_one_of_models @@ -282,19 +279,19 @@ def _parse_not_required_one_of_models( if isinstance(data, Unset): return data try: + if not isinstance(data, dict): + raise TypeError() not_required_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_one_of_models = FreeFormModel.from_dict(data) return not_required_one_of_models except: # noqa: E722 pass + if not isinstance(data, dict): + raise TypeError() not_required_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_one_of_models = ModelWithUnionProperty.from_dict(data) return not_required_one_of_models @@ -302,30 +299,34 @@ def _parse_not_required_one_of_models( not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) def _parse_not_required_nullable_one_of_models( - data: Union[Unset, None, Dict[str, Any]] - ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: - not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + data: Union[Unset, None, Dict[str, Any], str] + ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str]: + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] if data is None: return data if isinstance(data, Unset): return data try: + if not isinstance(data, dict): + raise TypeError() not_required_nullable_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_nullable_one_of_models = FreeFormModel.from_dict(data) return not_required_nullable_one_of_models except: # noqa: E722 pass - not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): + try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) - not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + raise TypeError() + not_required_nullable_one_of_models = UNSET + if data is not None and not isinstance(data, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) - return not_required_nullable_one_of_models + return not_required_nullable_one_of_models + except: # noqa: E722 + pass + return cast(Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str], data) not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models( d.pop("not_required_nullable_one_of_models", UNSET) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py index 724c5f414..a51e66578 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py index 7c9cad150..505feab12 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py index 00a8de6b4..732e96133 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py index 09e6558ed..3f2d667a6 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/http_validation_error.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/http_validation_error.py index 695662ad8..1b25a6d98 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/http_validation_error.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/http_validation_error.py @@ -34,8 +34,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "HTTPValidationError": detail = [] _detail = d.pop("detail", UNSET) for detail_item_data in _detail or []: - if not isinstance(detail_item_data, dict): - raise ValueError("Cannot construct model from value " + str(detail_item_data)) detail_item = ValidationError.from_dict(detail_item_data) detail.append(detail_item) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_additional_properties_inlined.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_additional_properties_inlined.py index a68e8f222..30acb7957 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_additional_properties_inlined.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_additional_properties_inlined.py @@ -41,8 +41,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithAdditionalPropertiesInlined additional_properties = {} for prop_name, prop_dict in d.items(): - if not isinstance(prop_dict, dict): - raise ValueError("Cannot construct model from value " + str(prop_dict)) additional_property = ModelWithAdditionalPropertiesInlinedAdditionalProperty.from_dict(prop_dict) additional_properties[prop_name] = additional_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py index 5ce4fbb8c..7971f562e 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_any_json_properties.py @@ -46,13 +46,15 @@ def _parse_additional_property( ] try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() additional_property = ModelWithAnyJsonPropertiesAdditionalProperty.from_dict(data) return additional_property except: # noqa: E722 pass try: + if not isinstance(data, list): + raise TypeError() additional_property = cast(List[str], data) return additional_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index a97c64fb6..8f3001c9f 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -33,8 +33,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET if d.pop("a_date_holder", UNSET) is not None and not isinstance(d.pop("a_date_holder", UNSET), Unset): - if not isinstance(d.pop("a_date_holder", UNSET), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("a_date_holder", UNSET))) a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(d.pop("a_date_holder", UNSET)) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index 956ea64b3..425fe9c09 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -43,6 +43,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -51,6 +53,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py index 304856de9..f87317ead 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py @@ -146,8 +146,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py index e1020e492..e43c92d9b 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/get_user_list.py @@ -50,16 +50,12 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[List[AModel], response_200 = [] _response_200 = response.json() for response_200_item_data in _response_200: - if not isinstance(response_200_item_data, dict): - raise ValueError("Cannot construct model from value " + str(response_200_item_data)) response_200_item = AModel.from_dict(response_200_item_data) response_200.append(response_200_item) return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py index da7588b0a..cace678f1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py @@ -38,8 +38,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py index 244083ee9..408f2dab1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py @@ -34,8 +34,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py index 2b2e21453..23bd9e741 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/optional_value_tests_optional_query_param.py @@ -42,8 +42,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py index e80566576..0f134aa87 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/test_inline_objects.py @@ -30,8 +30,6 @@ def _get_kwargs( def _parse_response(*, response: httpx.Response) -> Optional[TestInlineObjectsResponse_200]: if response.status_code == 200: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_200 = TestInlineObjectsResponse_200.from_dict(response.json()) return response_200 diff --git a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py index 13b2d25ca..f8a54ec77 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_file_tests_upload_post.py @@ -36,8 +36,6 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[None, HTTPVal return response_200 if response.status_code == 422: - if not isinstance(response.json(), dict): - raise ValueError("Cannot construct model from value " + str(response.json())) response_422 = HTTPValidationError.from_dict(response.json()) return response_422 diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index e120497c0..5f11adb3a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -36,7 +36,7 @@ class AModel: not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET not_required_nullable_model: Union[Unset, None, AModelNotRequiredNullableModel] = UNSET not_required_one_of_models: Union[Unset, FreeFormModel, ModelWithUnionProperty] = UNSET - not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] = UNSET + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] = UNSET def to_dict(self) -> Dict[str, Any]: an_enum_value = self.an_enum_value.value @@ -110,7 +110,7 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_one_of_models, Unset): not_required_one_of_models = self.not_required_one_of_models.to_dict() - not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any]] + not_required_nullable_one_of_models: Union[Unset, None, Dict[str, Any], str] if isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = UNSET elif self.not_required_nullable_one_of_models is None: @@ -120,11 +120,14 @@ def to_dict(self) -> Dict[str, Any]: if not isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() - else: + elif isinstance(self.not_required_nullable_one_of_models, ModelWithUnionProperty): not_required_nullable_one_of_models = UNSET if not isinstance(self.not_required_nullable_one_of_models, Unset): not_required_nullable_one_of_models = self.not_required_nullable_one_of_models.to_dict() + else: + not_required_nullable_one_of_models = self.not_required_nullable_one_of_models + field_dict: Dict[str, Any] = {} field_dict.update( { @@ -167,11 +170,15 @@ def from_dict(src_dict: Dict[str, Any]) -> "AModel": def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datetime.date]: a_camel_date_time: Union[datetime.datetime, datetime.date] try: + if not isinstance(data, str): + raise TypeError() a_camel_date_time = isoparse(data) return a_camel_date_time except: # noqa: E722 pass + if not isinstance(data, str): + raise TypeError() a_camel_date_time = isoparse(data).date() return a_camel_date_time @@ -182,22 +189,20 @@ def _parse_a_camel_date_time(data: Union[str]) -> Union[datetime.datetime, datet required_not_nullable = d.pop("required_not_nullable") - if not isinstance(d.pop("model"), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("model"))) model = AModelModel.from_dict(d.pop("model")) def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, ModelWithUnionProperty]: one_of_models: Union[FreeFormModel, ModelWithUnionProperty] try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() one_of_models = FreeFormModel.from_dict(data) return one_of_models except: # noqa: E722 pass if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() one_of_models = ModelWithUnionProperty.from_dict(data) return one_of_models @@ -231,24 +236,16 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo nullable_model = None if d.pop("nullable_model") is not None and not isinstance(d.pop("nullable_model"), Unset): - if not isinstance(d.pop("nullable_model"), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("nullable_model"))) nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET if d.pop("not_required_model", UNSET) is not None and not isinstance(d.pop("not_required_model", UNSET), Unset): - if not isinstance(d.pop("not_required_model", UNSET), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("not_required_model", UNSET))) not_required_model = AModelNotRequiredModel.from_dict(d.pop("not_required_model", UNSET)) not_required_nullable_model = None if d.pop("not_required_nullable_model", UNSET) is not None and not isinstance( d.pop("not_required_nullable_model", UNSET), Unset ): - if not isinstance(d.pop("not_required_nullable_model", UNSET), dict): - raise ValueError( - "Cannot construct model from value " + str(d.pop("not_required_nullable_model", UNSET)) - ) not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( d.pop("not_required_nullable_model", UNSET) ) @@ -261,14 +258,14 @@ def _parse_nullable_one_of_models( return data try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() nullable_one_of_models = FreeFormModel.from_dict(data) return nullable_one_of_models except: # noqa: E722 pass if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() nullable_one_of_models = ModelWithUnionProperty.from_dict(data) return nullable_one_of_models @@ -282,19 +279,19 @@ def _parse_not_required_one_of_models( if isinstance(data, Unset): return data try: + if not isinstance(data, dict): + raise TypeError() not_required_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_one_of_models = FreeFormModel.from_dict(data) return not_required_one_of_models except: # noqa: E722 pass + if not isinstance(data, dict): + raise TypeError() not_required_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_one_of_models = ModelWithUnionProperty.from_dict(data) return not_required_one_of_models @@ -302,30 +299,34 @@ def _parse_not_required_one_of_models( not_required_one_of_models = _parse_not_required_one_of_models(d.pop("not_required_one_of_models", UNSET)) def _parse_not_required_nullable_one_of_models( - data: Union[Unset, None, Dict[str, Any]] - ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty]: - not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty] + data: Union[Unset, None, Dict[str, Any], str] + ) -> Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str]: + not_required_nullable_one_of_models: Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str] if data is None: return data if isinstance(data, Unset): return data try: + if not isinstance(data, dict): + raise TypeError() not_required_nullable_one_of_models = UNSET if data is not None and not isinstance(data, Unset): - if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) not_required_nullable_one_of_models = FreeFormModel.from_dict(data) return not_required_nullable_one_of_models except: # noqa: E722 pass - not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): + try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) - not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + raise TypeError() + not_required_nullable_one_of_models = UNSET + if data is not None and not isinstance(data, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) - return not_required_nullable_one_of_models + return not_required_nullable_one_of_models + except: # noqa: E722 + pass + return cast(Union[Unset, None, FreeFormModel, ModelWithUnionProperty, str], data) not_required_nullable_one_of_models = _parse_not_required_nullable_one_of_models( d.pop("not_required_nullable_one_of_models", UNSET) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py index 724c5f414..a51e66578 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py index 7c9cad150..505feab12 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py index 00a8de6b4..732e96133 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py index 09e6558ed..3f2d667a6 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -45,6 +45,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -53,6 +55,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py b/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py index 695662ad8..1b25a6d98 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/http_validation_error.py @@ -34,8 +34,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "HTTPValidationError": detail = [] _detail = d.pop("detail", UNSET) for detail_item_data in _detail or []: - if not isinstance(detail_item_data, dict): - raise ValueError("Cannot construct model from value " + str(detail_item_data)) detail_item = ValidationError.from_dict(detail_item_data) detail.append(detail_item) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py index a68e8f222..30acb7957 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_additional_properties_inlined.py @@ -41,8 +41,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithAdditionalPropertiesInlined additional_properties = {} for prop_name, prop_dict in d.items(): - if not isinstance(prop_dict, dict): - raise ValueError("Cannot construct model from value " + str(prop_dict)) additional_property = ModelWithAdditionalPropertiesInlinedAdditionalProperty.from_dict(prop_dict) additional_properties[prop_name] = additional_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py index 5ce4fbb8c..7971f562e 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_any_json_properties.py @@ -46,13 +46,15 @@ def _parse_additional_property( ] try: if not isinstance(data, dict): - raise ValueError("Cannot construct model from value " + str(data)) + raise TypeError() additional_property = ModelWithAnyJsonPropertiesAdditionalProperty.from_dict(data) return additional_property except: # noqa: E722 pass try: + if not isinstance(data, list): + raise TypeError() additional_property = cast(List[str], data) return additional_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index a97c64fb6..8f3001c9f 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -33,8 +33,6 @@ def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperti d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET if d.pop("a_date_holder", UNSET) is not None and not isinstance(d.pop("a_date_holder", UNSET), Unset): - if not isinstance(d.pop("a_date_holder", UNSET), dict): - raise ValueError("Cannot construct model from value " + str(d.pop("a_date_holder", UNSET))) a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(d.pop("a_date_holder", UNSET)) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index 956ea64b3..425fe9c09 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -43,6 +43,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): @@ -51,6 +53,8 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass + if not isinstance(data, int): + raise TypeError() a_property = UNSET _a_property = data if _a_property is not None and not isinstance(_a_property, Unset): diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 404656e31..971bbaa03 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -819,6 +819,9 @@ }, { "ref": "#components/schemas/ModelWithUnionProperty" + }, + { + "type": "string" } ], "nullable": true diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index f73df9437..ae1cf03dc 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -9,6 +9,8 @@ if _{{ property.python_name }} is not None and not isinstance(_{{ property.pytho {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, str){% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {{ destination }} = {{ source }}.isoformat() {% if property.nullable %}if {{ source }} else None {%endif%} diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index 88f370b32..0af84dee5 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -14,6 +14,8 @@ if _{{ property.python_name }} is not None and not isinstance(_{{ property.pytho {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, str){% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} diff --git a/openapi_python_client/templates/property_templates/dict_property.pyi b/openapi_python_client/templates/property_templates/dict_property.pyi index ca16cb538..1158b0cbc 100644 --- a/openapi_python_client/templates/property_templates/dict_property.pyi +++ b/openapi_python_client/templates/property_templates/dict_property.pyi @@ -9,6 +9,8 @@ if _{{ property.python_name }} is not None and not isinstance(_{{ property.pyth {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, dict){% endmacro %} + {% macro transform(property, source, destination, declare_type=True) %} {% if property.nullable %} {{ destination }} = {{ source }} if {{ source }} else None diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 3bf16564e..8838aaa44 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -9,6 +9,8 @@ if _{{ property.python_name }} is not None and not isinstance(_{{ property.pytho {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, int){% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} diff --git a/openapi_python_client/templates/property_templates/file_property.pyi b/openapi_python_client/templates/property_templates/file_property.pyi index 50a331851..3a5b5e746 100644 --- a/openapi_python_client/templates/property_templates/file_property.pyi +++ b/openapi_python_client/templates/property_templates/file_property.pyi @@ -4,6 +4,8 @@ ) {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, bytes){% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} diff --git a/openapi_python_client/templates/property_templates/list_property.pyi b/openapi_python_client/templates/property_templates/list_property.pyi index 5f58bcd30..6f2d03f68 100644 --- a/openapi_python_client/templates/property_templates/list_property.pyi +++ b/openapi_python_client/templates/property_templates/list_property.pyi @@ -17,6 +17,8 @@ for {{ inner_source }} in (_{{ property.python_name }} or []): {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, list){% endmacro %} + {% macro _transform(property, source, destination) %} {% set inner_property = property.inner_property %} {% if inner_property.template %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index cb4b198ff..56a3cb919 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -1,7 +1,5 @@ {% macro construct(property, source, initial_value=None) %} {% if property.required and not property.nullable %} -if not isinstance({{ source }}, dict): - raise ValueError("Cannot construct model from value " + str({{ source }})) {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% else %} {% if initial_value != None %} @@ -12,12 +10,12 @@ if not isinstance({{ source }}, dict): {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} if {{ source }} is not None and not isinstance({{ source }}, Unset): - if not isinstance({{ source }}, dict): - raise ValueError("Cannot construct model from value " + str({{ source }})) {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) {% endif %} {% endmacro %} +{% macro check_type_for_construct(source) %}isinstance({{ source }}, dict){% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %} {% if property.nullable %} diff --git a/openapi_python_client/templates/property_templates/none_property.pyi b/openapi_python_client/templates/property_templates/none_property.pyi index b3178780a..235530c8b 100644 --- a/openapi_python_client/templates/property_templates/none_property.pyi +++ b/openapi_python_client/templates/property_templates/none_property.pyi @@ -2,6 +2,8 @@ {{ property.python_name }} = {{ initial_value }} {% endmacro %} +{% macro check_type_for_construct(source) %}{{ source }} is None{% endmacro %} + {% macro transform(property, source, destination, declare_type=True) %} {{ destination }} = None {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/union_property.pyi b/openapi_python_client/templates/property_templates/union_property.pyi index 0d5f09a07..c414fb65d 100644 --- a/openapi_python_client/templates/property_templates/union_property.pyi +++ b/openapi_python_client/templates/property_templates/union_property.pyi @@ -12,13 +12,17 @@ def _parse_{{ property.python_name }}(data: {{ property.get_type_string(json=Tru {% for inner_property in property.inner_properties_with_template() %} {% if not loop.last or property.has_properties_without_templates %} try: - {% from "property_templates/" + inner_property.template import construct %} + {% from "property_templates/" + inner_property.template import construct, check_type_for_construct %} + if not {{ check_type_for_construct("data") }}: + raise TypeError() {{ construct(inner_property, "data", initial_value="UNSET") | indent(8) }} return {{ property.python_name }} except: # noqa: E722 pass {% else %}{# Don't do try/except for the last one #} - {% from "property_templates/" + inner_property.template import construct %} + {% from "property_templates/" + inner_property.template import construct, check_type_for_construct %} + if not {{ check_type_for_construct("data") }}: + raise TypeError() {{ construct(inner_property, "data", initial_value="UNSET") | indent(4) }} return {{ property.python_name }} {% endif %} @@ -31,6 +35,9 @@ def _parse_{{ property.python_name }}(data: {{ property.get_type_string(json=Tru {{ property.python_name }} = _parse_{{ property.python_name }}({{ source }}) {% endmacro %} +{# For now we assume there will be no unions of unions #} +{% macro check_type_for_construct(source) %}True{% endmacro %} + {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if not property.required or property.nullable %} {{ destination }}{% if declare_type %}: {{ property.get_type_string(query_parameter=query_parameter, json=True) }}{% endif %} From 9c002560f4df749aebb5e4f55a6ee747b41d1430 Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 28 Jan 2021 09:16:13 -0500 Subject: [PATCH 17/18] Revert changes to Unset --- .../custom_e2e/models/a_model.py | 43 +++++++++++-------- .../custom_e2e/models/a_model_model.py | 4 +- .../models/a_model_not_required_model.py | 4 +- .../a_model_not_required_nullable_model.py | 4 +- .../models/a_model_nullable_model.py | 4 +- ...el_with_primitive_additional_properties.py | 5 ++- .../models/model_with_union_property.py | 4 +- .../my_test_api_client/models/a_model.py | 43 +++++++++++-------- .../models/a_model_model.py | 4 +- .../models/a_model_not_required_model.py | 4 +- .../a_model_not_required_nullable_model.py | 4 +- .../models/a_model_nullable_model.py | 4 +- ...el_with_primitive_additional_properties.py | 5 ++- .../models/model_with_union_property.py | 4 +- .../parser/properties/__init__.py | 9 ++-- .../property_templates/date_property.pyi | 2 +- .../property_templates/datetime_property.pyi | 2 +- .../property_templates/dict_property.pyi | 2 +- .../property_templates/enum_property.pyi | 2 +- .../property_templates/model_property.pyi | 5 ++- .../test_date_property/optional_nullable.py | 2 +- .../test_date_property/required_nullable.py | 2 +- 22 files changed, 89 insertions(+), 73 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py index 5f11adb3a..83d7518a7 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model.py @@ -223,7 +223,7 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo a_nullable_date = None _a_nullable_date = d.pop("a_nullable_date") - if _a_nullable_date is not None and not isinstance(_a_nullable_date, Unset): + if _a_nullable_date is not None: a_nullable_date = isoparse(cast(str, _a_nullable_date)).date() attr_1_leading_digit = d.pop("1_leading_digit", UNSET) @@ -235,20 +235,19 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) nullable_model = None - if d.pop("nullable_model") is not None and not isinstance(d.pop("nullable_model"), Unset): - nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(_nullable_model) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET - if d.pop("not_required_model", UNSET) is not None and not isinstance(d.pop("not_required_model", UNSET), Unset): - not_required_model = AModelNotRequiredModel.from_dict(d.pop("not_required_model", UNSET)) + _not_required_model = d.pop("not_required_model", UNSET) + if not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(_not_required_model) not_required_nullable_model = None - if d.pop("not_required_nullable_model", UNSET) is not None and not isinstance( - d.pop("not_required_nullable_model", UNSET), Unset - ): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - d.pop("not_required_nullable_model", UNSET) - ) + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(_not_required_nullable_model) def _parse_nullable_one_of_models( data: Union[None, Dict[str, Any]] @@ -282,8 +281,9 @@ def _parse_not_required_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_one_of_models = FreeFormModel.from_dict(data) + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict(_not_required_one_of_models) return not_required_one_of_models except: # noqa: E722 @@ -291,8 +291,9 @@ def _parse_not_required_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_one_of_models = ModelWithUnionProperty.from_dict(data) + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict(_not_required_one_of_models) return not_required_one_of_models @@ -310,8 +311,9 @@ def _parse_not_required_nullable_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_nullable_one_of_models = FreeFormModel.from_dict(data) + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = FreeFormModel.from_dict(_not_required_nullable_one_of_models) return not_required_nullable_one_of_models except: # noqa: E722 @@ -320,8 +322,11 @@ def _parse_not_required_nullable_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( + _not_required_nullable_one_of_models + ) return not_required_nullable_one_of_models except: # noqa: E722 diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py index a51e66578..186a20d96 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py index 505feab12..c868d6778 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py index 732e96133..346eaf1c1 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py index 3f2d667a6..ce8951d04 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py index 8f3001c9f..32b23d7e5 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_primitive_additional_properties.py @@ -32,8 +32,9 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET - if d.pop("a_date_holder", UNSET) is not None and not isinstance(d.pop("a_date_holder", UNSET), Unset): - a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(d.pop("a_date_holder", UNSET)) + _a_date_holder = d.pop("a_date_holder", UNSET) + if not isinstance(_a_date_holder, Unset): + a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(_a_date_holder) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( a_date_holder=a_date_holder, diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index 425fe9c09..d530e0908 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -47,7 +47,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -57,7 +57,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 5f11adb3a..83d7518a7 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -223,7 +223,7 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo a_nullable_date = None _a_nullable_date = d.pop("a_nullable_date") - if _a_nullable_date is not None and not isinstance(_a_nullable_date, Unset): + if _a_nullable_date is not None: a_nullable_date = isoparse(cast(str, _a_nullable_date)).date() attr_1_leading_digit = d.pop("1_leading_digit", UNSET) @@ -235,20 +235,19 @@ def _parse_one_of_models(data: Union[Dict[str, Any]]) -> Union[FreeFormModel, Mo not_required_not_nullable = d.pop("not_required_not_nullable", UNSET) nullable_model = None - if d.pop("nullable_model") is not None and not isinstance(d.pop("nullable_model"), Unset): - nullable_model = AModelNullableModel.from_dict(d.pop("nullable_model")) + _nullable_model = d.pop("nullable_model") + if _nullable_model is not None: + nullable_model = AModelNullableModel.from_dict(_nullable_model) not_required_model: Union[Unset, AModelNotRequiredModel] = UNSET - if d.pop("not_required_model", UNSET) is not None and not isinstance(d.pop("not_required_model", UNSET), Unset): - not_required_model = AModelNotRequiredModel.from_dict(d.pop("not_required_model", UNSET)) + _not_required_model = d.pop("not_required_model", UNSET) + if not isinstance(_not_required_model, Unset): + not_required_model = AModelNotRequiredModel.from_dict(_not_required_model) not_required_nullable_model = None - if d.pop("not_required_nullable_model", UNSET) is not None and not isinstance( - d.pop("not_required_nullable_model", UNSET), Unset - ): - not_required_nullable_model = AModelNotRequiredNullableModel.from_dict( - d.pop("not_required_nullable_model", UNSET) - ) + _not_required_nullable_model = d.pop("not_required_nullable_model", UNSET) + if _not_required_nullable_model is not None and not isinstance(_not_required_nullable_model, Unset): + not_required_nullable_model = AModelNotRequiredNullableModel.from_dict(_not_required_nullable_model) def _parse_nullable_one_of_models( data: Union[None, Dict[str, Any]] @@ -282,8 +281,9 @@ def _parse_not_required_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_one_of_models = FreeFormModel.from_dict(data) + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = FreeFormModel.from_dict(_not_required_one_of_models) return not_required_one_of_models except: # noqa: E722 @@ -291,8 +291,9 @@ def _parse_not_required_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_one_of_models = ModelWithUnionProperty.from_dict(data) + _not_required_one_of_models = data + if not isinstance(_not_required_one_of_models, Unset): + not_required_one_of_models = ModelWithUnionProperty.from_dict(_not_required_one_of_models) return not_required_one_of_models @@ -310,8 +311,9 @@ def _parse_not_required_nullable_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_nullable_one_of_models = FreeFormModel.from_dict(data) + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = FreeFormModel.from_dict(_not_required_nullable_one_of_models) return not_required_nullable_one_of_models except: # noqa: E722 @@ -320,8 +322,11 @@ def _parse_not_required_nullable_one_of_models( if not isinstance(data, dict): raise TypeError() not_required_nullable_one_of_models = UNSET - if data is not None and not isinstance(data, Unset): - not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict(data) + _not_required_nullable_one_of_models = data + if not isinstance(_not_required_nullable_one_of_models, Unset): + not_required_nullable_one_of_models = ModelWithUnionProperty.from_dict( + _not_required_nullable_one_of_models + ) return not_required_nullable_one_of_models except: # noqa: E722 diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py index a51e66578..186a20d96 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py index 505feab12..c868d6778 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py index 732e96133..346eaf1c1 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py index 3f2d667a6..ce8951d04 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -49,7 +49,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -59,7 +59,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py index 8f3001c9f..32b23d7e5 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_primitive_additional_properties.py @@ -32,8 +32,9 @@ def to_dict(self) -> Dict[str, Any]: def from_dict(src_dict: Dict[str, Any]) -> "ModelWithPrimitiveAdditionalProperties": d = src_dict.copy() a_date_holder: Union[Unset, ModelWithPrimitiveAdditionalPropertiesADateHolder] = UNSET - if d.pop("a_date_holder", UNSET) is not None and not isinstance(d.pop("a_date_holder", UNSET), Unset): - a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(d.pop("a_date_holder", UNSET)) + _a_date_holder = d.pop("a_date_holder", UNSET) + if not isinstance(_a_date_holder, Unset): + a_date_holder = ModelWithPrimitiveAdditionalPropertiesADateHolder.from_dict(_a_date_holder) model_with_primitive_additional_properties = ModelWithPrimitiveAdditionalProperties( a_date_holder=a_date_holder, diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index 425fe9c09..d530e0908 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -47,7 +47,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnEnum(_a_property) return a_property @@ -57,7 +57,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum raise TypeError() a_property = UNSET _a_property = data - if _a_property is not None and not isinstance(_a_property, Unset): + if _a_property is not None: a_property = AnIntEnum(_a_property) return a_property diff --git a/openapi_python_client/parser/properties/__init__.py b/openapi_python_client/parser/properties/__init__.py index 96d146a4a..1794cf6ed 100644 --- a/openapi_python_client/parser/properties/__init__.py +++ b/openapi_python_client/parser/properties/__init__.py @@ -177,7 +177,9 @@ def _get_inner_type_strings(self, json: bool = False) -> List[str]: def get_base_type_string(self, json: bool = False) -> str: return f"Union[{', '.join(self._get_inner_type_strings(json=json))}]" - def get_type_strings_in_union(self, no_optional: bool = False, query_parameter: bool = False, json: bool = False) -> List[str]: + def get_type_strings_in_union( + self, no_optional: bool = False, query_parameter: bool = False, json: bool = False + ) -> List[str]: type_strings = self._get_inner_type_strings(json=json) if no_optional: return type_strings @@ -203,9 +205,10 @@ def get_type_string(self, no_optional: bool = False, query_parameter: bool = Fal This implementation differs slightly from `Property.get_type_string` in order to collapse nested union types. """ - return ( - f"Union[{', '.join(self.get_type_strings_in_union(no_optional=no_optional, query_parameter=query_parameter, json=json))}]" + type_strings_in_union = self.get_type_strings_in_union( + no_optional=no_optional, query_parameter=query_parameter, json=json ) + return f"Union[{', '.join(type_strings_in_union)}]" def get_imports(self, *, prefix: str) -> Set[str]: """ diff --git a/openapi_python_client/templates/property_templates/date_property.pyi b/openapi_python_client/templates/property_templates/date_property.pyi index ae1cf03dc..d883d8787 100644 --- a/openapi_python_client/templates/property_templates/date_property.pyi +++ b/openapi_python_client/templates/property_templates/date_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if _{{ property.python_name }} is not None: {{ property.python_name }} = isoparse(cast(str, _{{ property.python_name }})).date() {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/datetime_property.pyi b/openapi_python_client/templates/property_templates/datetime_property.pyi index 0af84dee5..53f432a59 100644 --- a/openapi_python_client/templates/property_templates/datetime_property.pyi +++ b/openapi_python_client/templates/property_templates/datetime_property.pyi @@ -9,7 +9,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if _{{ property.python_name }} is not None: {{ property.python_name }} = isoparse(cast(str, _{{ property.python_name }})) {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/dict_property.pyi b/openapi_python_client/templates/property_templates/dict_property.pyi index 1158b0cbc..c4a853d72 100644 --- a/openapi_python_client/templates/property_templates/dict_property.pyi +++ b/openapi_python_client/templates/property_templates/dict_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if _{{ property.python_name }} is not None: {{ property.python_name }} = _{{ property.python_name }} {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 8838aaa44..782d3ec44 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -4,7 +4,7 @@ {% else %} {{ property.python_name }} = {{ initial_value }} _{{ property.python_name }} = {{ source }} -if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset): +if _{{ property.python_name }} is not None: {{ property.python_name }} = {{ property.reference.class_name }}(_{{ property.python_name }}) {% endif %} {% endmacro %} diff --git a/openapi_python_client/templates/property_templates/model_property.pyi b/openapi_python_client/templates/property_templates/model_property.pyi index 56a3cb919..1cabf2996 100644 --- a/openapi_python_client/templates/property_templates/model_property.pyi +++ b/openapi_python_client/templates/property_templates/model_property.pyi @@ -9,8 +9,9 @@ {% else %} {{ property.python_name }}: {{ property.get_type_string() }} = UNSET {% endif %} -if {{ source }} is not None and not isinstance({{ source }}, Unset): - {{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }}) +_{{ property.python_name }} = {{source}} +if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}: + {{ property.python_name }} = {{ property.reference.class_name }}.from_dict(_{{ property.python_name }}) {% endif %} {% endmacro %} diff --git a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py index 95441cc62..be32cfbd3 100644 --- a/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py +++ b/tests/test_templates/test_property_templates/test_date_property/optional_nullable.py @@ -17,6 +17,6 @@ a_prop = None _a_prop = some_destination -if _a_prop is not None and not isinstance(_a_prop, Unset): +if _a_prop is not None: a_prop = isoparse(cast(str, _a_prop)).date() diff --git a/tests/test_templates/test_property_templates/test_date_property/required_nullable.py b/tests/test_templates/test_property_templates/test_date_property/required_nullable.py index 685dfbafc..b6ef423b8 100644 --- a/tests/test_templates/test_property_templates/test_date_property/required_nullable.py +++ b/tests/test_templates/test_property_templates/test_date_property/required_nullable.py @@ -13,6 +13,6 @@ a_prop = None _a_prop = some_destination -if _a_prop is not None and not isinstance(_a_prop, Unset): +if _a_prop is not None: a_prop = isoparse(cast(str, _a_prop)).date() From 64c31ce92b0b05125c7643fab940a834fa2a043c Mon Sep 17 00:00:00 2001 From: Forest Tong Date: Thu, 28 Jan 2021 09:30:29 -0500 Subject: [PATCH 18/18] Regenerate tests --- .../golden-record-custom/custom_e2e/models/a_model_model.py | 4 ++-- .../custom_e2e/models/a_model_not_required_model.py | 4 ++-- .../custom_e2e/models/a_model_not_required_nullable_model.py | 4 ++-- .../custom_e2e/models/a_model_nullable_model.py | 4 ++-- .../custom_e2e/models/model_with_union_property.py | 4 ++-- .../golden-record/my_test_api_client/models/a_model_model.py | 4 ++-- .../my_test_api_client/models/a_model_not_required_model.py | 4 ++-- .../models/a_model_not_required_nullable_model.py | 4 ++-- .../my_test_api_client/models/a_model_nullable_model.py | 4 ++-- .../my_test_api_client/models/model_with_union_property.py | 4 ++-- .../templates/property_templates/enum_property.pyi | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py index 186a20d96..cef48694b 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py index c868d6778..3f56b7f52 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py index 346eaf1c1..55ef6810a 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_not_required_nullable_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py index ce8951d04..05c4f8897 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/a_model_nullable_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py index d530e0908..99fcdfe96 100644 --- a/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record-custom/custom_e2e/models/model_with_union_property.py @@ -43,7 +43,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -53,7 +53,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py index 186a20d96..cef48694b 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py index c868d6778..3f56b7f52 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py index 346eaf1c1..55ef6810a 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_not_required_nullable_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py index ce8951d04..05c4f8897 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model_nullable_model.py @@ -45,7 +45,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -55,7 +55,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py index d530e0908..99fcdfe96 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/model_with_union_property.py @@ -43,7 +43,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum if isinstance(data, Unset): return data try: - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data @@ -53,7 +53,7 @@ def _parse_a_property(data: Union[Unset, int]) -> Union[Unset, AnEnum, AnIntEnum return a_property except: # noqa: E722 pass - if not isinstance(data, int): + if not (isinstance(data, int) or isinstance(data, str)): raise TypeError() a_property = UNSET _a_property = data diff --git a/openapi_python_client/templates/property_templates/enum_property.pyi b/openapi_python_client/templates/property_templates/enum_property.pyi index 782d3ec44..6d87c2918 100644 --- a/openapi_python_client/templates/property_templates/enum_property.pyi +++ b/openapi_python_client/templates/property_templates/enum_property.pyi @@ -9,7 +9,7 @@ if _{{ property.python_name }} is not None: {% endif %} {% endmacro %} -{% macro check_type_for_construct(source) %}isinstance({{ source }}, int){% endmacro %} +{% macro check_type_for_construct(source) %}(isinstance({{ source }}, int) or isinstance({{ source }}, str)){% endmacro %} {% macro transform(property, source, destination, declare_type=True, query_parameter=False) %} {% if property.required %}