From f3e3a724fbef5c0f19af93a6f29c66a57366dbcf Mon Sep 17 00:00:00 2001 From: Christoph Ludwig Date: Mon, 14 Jun 2021 12:05:36 +0200 Subject: [PATCH] Fix `python-fastapi` free-form objects mapping and forward ref type hints (#9723) * map free-form objects to Dict[str, Any] * support Forward Type References Forward type references will be supported by default from Python 3.10 on only. Until then (and starting with Python 3.7), we can opt in by a __future__ import, cf. https://docs.python.org/3.9/whatsnew/3.7.html?highlight=forward#pep-563-postponed-evaluation-of-annotations * re-created pet-store sample * bump required Python version to 3.7 for generated FastAPI projects * make pydantic modell classes process forward type references --- .../src/main/resources/python-fastapi/Dockerfile.mustache | 6 +++--- .../src/main/resources/python-fastapi/README.mustache | 2 +- .../src/main/resources/python-fastapi/model.mustache | 5 ++++- .../main/resources/python-fastapi/model_field_type.mustache | 2 +- .../src/main/resources/python-fastapi/setup_cfg.mustache | 4 ++-- samples/server/petstore/python-fastapi/Dockerfile | 6 +++--- samples/server/petstore/python-fastapi/README.md | 2 +- samples/server/petstore/python-fastapi/setup.cfg | 4 ++-- .../src/openapi_server/models/api_response.py | 5 ++++- .../python-fastapi/src/openapi_server/models/category.py | 5 ++++- .../python-fastapi/src/openapi_server/models/order.py | 5 ++++- .../python-fastapi/src/openapi_server/models/pet.py | 5 ++++- .../python-fastapi/src/openapi_server/models/tag.py | 5 ++++- .../python-fastapi/src/openapi_server/models/user.py | 5 ++++- 14 files changed, 41 insertions(+), 20 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache index 395fed380e6..b66458eb417 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/Dockerfile.mustache @@ -1,4 +1,4 @@ -FROM python:3.6 AS builder +FROM python:3.7 AS builder WORKDIR /usr/src/app @@ -11,7 +11,7 @@ COPY . . RUN pip install --no-cache-dir . -FROM python:3.6 AS test_runner +FROM python:3.7 AS test_runner WORKDIR /tmp COPY --from=builder /venv /venv COPY --from=builder /usr/src/app/tests tests @@ -24,7 +24,7 @@ RUN pip install pytest RUN pytest tests -FROM python:3.6 AS service +FROM python:3.7 AS service WORKDIR /root/app/site-packages COPY --from=test_runner /venv /venv ENV PATH=/venv/bin:$PATH diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/README.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/README.mustache index ae8428952fd..c426a965f0f 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/README.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/README.mustache @@ -10,7 +10,7 @@ This Python package is automatically generated by the [OpenAPI Generator](https: ## Requirements. -Python >= 3.6 +Python >= 3.7 ## Installation & Usage diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache index 4c5545e0795..65d40b93482 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/model.mustache @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 {{#models}} @@ -71,3 +72,5 @@ class {{classname}}(BaseModel): {{/vars}} {{/model}} {{/models}} + +{{classname}}.update_forward_refs() diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache index c7e36fc47fc..a27dc7e87fe 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/model_field_type.mustache @@ -1 +1 @@ -{{#isEmail}}EmailStr{{/isEmail}}{{#isUri}}AnyUrl{{/isUri}}{{^isEmail}}{{^isUri}}{{dataType}}{{/isUri}}{{/isEmail}} \ No newline at end of file +{{#isEmail}}EmailStr{{/isEmail}}{{#isUri}}AnyUrl{{/isUri}}{{#isFreeFormObject}}Dict[str, Any]{{/isFreeFormObject}}{{^isEmail}}{{^isUri}}{{^isFreeFormObject}}{{dataType}}{{/isFreeFormObject}}{{/isUri}}{{/isEmail}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache b/modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache index ff5cfe968e0..2934cb8fc53 100644 --- a/modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache +++ b/modules/openapi-generator/src/main/resources/python-fastapi/setup_cfg.mustache @@ -4,11 +4,11 @@ version = {{appVersion}} description = {{appDescription}} long_description = file: README.md keywords = OpenAPI {{appName}} -python_requires = >= 3.6.* +python_requires = >= 3.7.* classifiers = Operating System :: OS Independent Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 [options] install_requires = diff --git a/samples/server/petstore/python-fastapi/Dockerfile b/samples/server/petstore/python-fastapi/Dockerfile index 395fed380e6..b66458eb417 100644 --- a/samples/server/petstore/python-fastapi/Dockerfile +++ b/samples/server/petstore/python-fastapi/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6 AS builder +FROM python:3.7 AS builder WORKDIR /usr/src/app @@ -11,7 +11,7 @@ COPY . . RUN pip install --no-cache-dir . -FROM python:3.6 AS test_runner +FROM python:3.7 AS test_runner WORKDIR /tmp COPY --from=builder /venv /venv COPY --from=builder /usr/src/app/tests tests @@ -24,7 +24,7 @@ RUN pip install pytest RUN pytest tests -FROM python:3.6 AS service +FROM python:3.7 AS service WORKDIR /root/app/site-packages COPY --from=test_runner /venv /venv ENV PATH=/venv/bin:$PATH diff --git a/samples/server/petstore/python-fastapi/README.md b/samples/server/petstore/python-fastapi/README.md index 6cafe22445e..34a725321ea 100644 --- a/samples/server/petstore/python-fastapi/README.md +++ b/samples/server/petstore/python-fastapi/README.md @@ -7,7 +7,7 @@ This Python package is automatically generated by the [OpenAPI Generator](https: ## Requirements. -Python >= 3.6 +Python >= 3.7 ## Installation & Usage diff --git a/samples/server/petstore/python-fastapi/setup.cfg b/samples/server/petstore/python-fastapi/setup.cfg index bc0f0d452d9..cafb7b8cf7d 100644 --- a/samples/server/petstore/python-fastapi/setup.cfg +++ b/samples/server/petstore/python-fastapi/setup.cfg @@ -4,11 +4,11 @@ version = 1.0.0 description = This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. long_description = file: README.md keywords = OpenAPI OpenAPI Petstore -python_requires = >= 3.6.* +python_requires = >= 3.7.* classifiers = Operating System :: OS Independent Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 [options] install_requires = diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py index d5d1d9280c4..fce5f94edc0 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/api_response.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 @@ -23,3 +24,5 @@ class ApiResponse(BaseModel): code: Optional[int] = None type: Optional[str] = None message: Optional[str] = None + +ApiResponse.update_forward_refs() diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py index c690b247acc..de57bf2d2ee 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/category.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 @@ -26,3 +27,5 @@ class Category(BaseModel): def name_pattern(cls, value): assert value is not None and re.match(r"^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$", value) return value + +Category.update_forward_refs() diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py index 8cf86bb6a55..384fec2a3a1 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/order.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 @@ -29,3 +30,5 @@ class Order(BaseModel): ship_date: Optional[datetime] = None status: Optional[str] = None complete: Optional[bool] = None + +Order.update_forward_refs() diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py index 9a688f83b1d..c44c38079ac 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/pet.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 from openapi_server.models.category import Category @@ -31,3 +32,5 @@ class Pet(BaseModel): photo_urls: List[str] tags: Optional[List[Tag]] = None status: Optional[str] = None + +Pet.update_forward_refs() diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py index 47ad31d81d2..3e0b45cd787 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/tag.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 @@ -21,3 +22,5 @@ class Tag(BaseModel): id: Optional[int] = None name: Optional[str] = None + +Tag.update_forward_refs() diff --git a/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py b/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py index e6abfd9a5dd..1c75b77dbfc 100644 --- a/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py +++ b/samples/server/petstore/python-fastapi/src/openapi_server/models/user.py @@ -1,9 +1,10 @@ # coding: utf-8 +from __future__ import annotations from datetime import date, datetime # noqa: F401 import re # noqa: F401 -from typing import Dict, List, Optional # noqa: F401 +from typing import Any, Dict, List, Optional # noqa: F401 from pydantic import AnyUrl, BaseModel, EmailStr, validator # noqa: F401 @@ -33,3 +34,5 @@ class User(BaseModel): password: Optional[str] = None phone: Optional[str] = None user_status: Optional[int] = None + +User.update_forward_refs()