openapi-python-generator 0.5.1.dev1710539733__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/PKG-INFO +5 -6
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/pyproject.toml +6 -6
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/setup.py +5 -5
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/__main__.py +12 -4
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/common.py +4 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/generate_data.py +6 -3
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/api_config_generator.py +8 -4
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/generator.py +5 -3
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/jinja_config.py +2 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/model_generator.py +41 -32
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/service_generator.py +1 -8
- openapi_python_generator-1.0.0/src/openapi_python_generator/language_converters/python/templates/apiconfig_pydantic_2.jinja2 +42 -0
- openapi_python_generator-1.0.0/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 +26 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/models.py +1 -3
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/LICENSE +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/README.md +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/__init__.py +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/__init__.py +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/__init__.py +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/common.py +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/aiohttp.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/apiconfig.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/enum.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/httpx.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/models.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/requests.jinja2 +0 -0
- {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/templates/service.jinja2 +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openapi-python-generator
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Openapi Python Generator
|
|
5
5
|
Home-page: https://github.com/MarcoMuellner/openapi-python-generator
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: OpenAPI,Generator,Python,async
|
|
8
8
|
Author: Marco Müllner
|
|
9
9
|
Author-email: muellnermarco@gmail.com
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.8,<4.0
|
|
11
11
|
Classifier: Development Status :: 3 - Alpha
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.8
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -21,9 +20,9 @@ Requires-Dist: black (>=21.10b0)
|
|
|
21
20
|
Requires-Dist: click (>=8.1.3,<9.0.0)
|
|
22
21
|
Requires-Dist: httpx[all] (>=0.23.0,<0.24.0)
|
|
23
22
|
Requires-Dist: isort (>=5.10.1)
|
|
24
|
-
Requires-Dist: openapi-
|
|
25
|
-
Requires-Dist: orjson (>=3.
|
|
26
|
-
Requires-Dist: pydantic (>=
|
|
23
|
+
Requires-Dist: openapi-pydantic (>=0.5.0,<0.6.0)
|
|
24
|
+
Requires-Dist: orjson (>=3.9.15,<4.0.0)
|
|
25
|
+
Requires-Dist: pydantic (>=2.10.2,<3.0.0)
|
|
27
26
|
Project-URL: Changelog, https://github.com/MarcoMuellner/openapi-python-generator/releases
|
|
28
27
|
Project-URL: Documentation, https://openapi-python-generator.readthedocs.io
|
|
29
28
|
Project-URL: Repository, https://github.com/MarcoMuellner/openapi-python-generator
|
{openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/pyproject.toml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "openapi-python-generator"
|
|
3
|
-
version = "
|
|
3
|
+
version = "1.0.0"
|
|
4
4
|
description = "Openapi Python Generator"
|
|
5
5
|
authors = ["Marco Müllner <muellnermarco@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -17,15 +17,15 @@ keywords = ["OpenAPI", "Generator", "Python", "async"]
|
|
|
17
17
|
Changelog = "https://github.com/MarcoMuellner/openapi-python-generator/releases"
|
|
18
18
|
|
|
19
19
|
[tool.poetry.dependencies]
|
|
20
|
-
python = "^3.
|
|
20
|
+
python = "^3.8"
|
|
21
21
|
httpx = {extras = ["all"], version = "^0.23.0"}
|
|
22
|
-
pydantic = "^
|
|
23
|
-
orjson = "^3.
|
|
24
|
-
openapi-schema-pydantic = "^1.2.3"
|
|
22
|
+
pydantic = "^2.10.2"
|
|
23
|
+
orjson = "^3.9.15"
|
|
25
24
|
Jinja2 = "^3.1.2"
|
|
26
25
|
click = "^8.1.3"
|
|
27
26
|
black = ">=21.10b0"
|
|
28
27
|
isort = ">=5.10.1"
|
|
28
|
+
openapi-pydantic = "^0.5.0"
|
|
29
29
|
|
|
30
30
|
[tool.poetry.dev-dependencies]
|
|
31
31
|
Pygments = ">=2.10.0"
|
|
@@ -48,7 +48,7 @@ typeguard = ">=2.13.3"
|
|
|
48
48
|
xdoctest = {extras = ["colors"], version = ">=0.15.10"}
|
|
49
49
|
myst-parser = {version = ">=0.16.1"}
|
|
50
50
|
pytest-cov = "^3.0.0"
|
|
51
|
-
fastapi = "^0.
|
|
51
|
+
fastapi = "^0.115.5"
|
|
52
52
|
uvicorn = "^0.18.1"
|
|
53
53
|
respx = "^0.20.1"
|
|
54
54
|
aiohttp = "^3.8.3"
|
|
@@ -19,9 +19,9 @@ install_requires = \
|
|
|
19
19
|
'click>=8.1.3,<9.0.0',
|
|
20
20
|
'httpx[all]>=0.23.0,<0.24.0',
|
|
21
21
|
'isort>=5.10.1',
|
|
22
|
-
'openapi-
|
|
23
|
-
'orjson>=3.
|
|
24
|
-
'pydantic>=
|
|
22
|
+
'openapi-pydantic>=0.5.0,<0.6.0',
|
|
23
|
+
'orjson>=3.9.15,<4.0.0',
|
|
24
|
+
'pydantic>=2.10.2,<3.0.0']
|
|
25
25
|
|
|
26
26
|
entry_points = \
|
|
27
27
|
{'console_scripts': ['openapi-python-generator = '
|
|
@@ -29,7 +29,7 @@ entry_points = \
|
|
|
29
29
|
|
|
30
30
|
setup_kwargs = {
|
|
31
31
|
'name': 'openapi-python-generator',
|
|
32
|
-
'version': '0.
|
|
32
|
+
'version': '1.0.0',
|
|
33
33
|
'description': 'Openapi Python Generator',
|
|
34
34
|
'long_description': "# Openapi Python Generator\n\n[][pypi_]\n[][status]\n[][python version]\n[][license]\n\n[][documentation]\n[][tests]\n[][codecov]\n\n[][pre-commit]\n[][black]\n\n[pypi_]: https://pypi.org/project/openapi-python-generator/\n[status]: https://pypi.org/project/openapi-python-generator/\n[python version]: https://pypi.org/project/openapi-python-generator\n[documentation]: https://marcomuellner.github.io/openapi-python-generator/\n[tests]: https://github.com/MarcoMuellner/openapi-python-generator/actions?workflow=Tests\n[codecov]: https://app.codecov.io/gh/MarcoMuellner/openapi-python-generator\n[pre-commit]: https://github.com/pre-commit/pre-commit\n[black]: https://github.com/psf/black\n\n\n\n---\n__Documentation:__ [here][documentation]\n\n---\n\n## Features\n\n- __Ease of use__. Provide input, output and the library, and the generator will do the rest.\n- __Type safety and type hinting.__ __OpenAPI python generator__ makes heavy use of pydantic models to provide type-safe data structures.\n- __Support for multiple rest frameworks.__ __OpenAPI python generator__ currently supports the following:\n - [httpx](https://pypi.org/project/httpx/)\n - [requests](https://pypi.org/project/requests/)\n - [aiohttp](https://pypi.org/project/aiohttp/)\n- __Async and sync code generation support__, depending on the framework. It will automatically create both for frameworks that support both.\n- __Easily extendable using Jinja2 templates__. The code is designed to be easily extendable and should support even more languages and frameworks in the future.\n- __Fully tested__. Every generated code is automatically tested against the OpenAPI spec and we have 100% coverage.\n- __Usage as CLI or as library__.\n\n## Requirements\n\n- Python 3.7+\n\n## Installation\n\nYou can install _Openapi Python Generator_ via [pip] from [PyPI]:\n\n```console\n$ pip install openapi-python-generator\n```\n\n## Usage\n\nPlease see the [Quick start page] for details.\n\n## Roadmap\n\n- Support for all commonly used http libraries in the python ecosystem (~~requests~~, urllib, ...)\n- Support for multiple languages\n- Support for multiple authentication schemes\n- Support custom themes\n\n## Contributing\n\nContributions are very welcome.\nTo learn more, see the [Contributor Guide].\n\n## License\n\nDistributed under the terms of the [MIT license][license],\n_Openapi Python Generator_ is free and open source software.\n\n## Issues\n\nIf you encounter any problems,\nplease [file an issue] along with a detailed description.\n\n## Credits\n\nSpecial thanks to the peeps from [openapi-schema-pydantic](https://github.com/kuimono/openapi-schema-pydantic),\nwhich already did a lot of the legwork by providing a pydantic schema for the OpenAPI 3.0.0+ specification.\n\nThis project was generated from [@cjolowicz]'s [Hypermodern Python Cookiecutter] template.\n\n[@cjolowicz]: https://github.com/cjolowicz\n[pypi]: https://pypi.org/\n[hypermodern python cookiecutter]: https://github.com/cjolowicz/cookiecutter-hypermodern-python\n[file an issue]: https://github.com/MarcoMuellner/openapi-python-generator/issues\n[pip]: https://pip.pypa.io/\n\n<!-- github-only -->\n\n[license]: https://github.com/MarcoMuellner/openapi-python-generator/blob/main/LICENSE\n[contributor guide]: https://github.com/MarcoMuellner/openapi-python-generator/blob/main/CONTRIBUTING.md\n[Quick start page]: https://marcomuellner.github.io/openapi-python-generator/quick_start/\n",
|
|
35
35
|
'author': 'Marco Müllner',
|
|
@@ -42,7 +42,7 @@ setup_kwargs = {
|
|
|
42
42
|
'package_data': package_data,
|
|
43
43
|
'install_requires': install_requires,
|
|
44
44
|
'entry_points': entry_points,
|
|
45
|
-
'python_requires': '>=3.
|
|
45
|
+
'python_requires': '>=3.8,<4.0',
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
|
+
from enum import Enum
|
|
2
3
|
|
|
3
4
|
import click
|
|
4
5
|
|
|
5
6
|
from openapi_python_generator import __version__
|
|
6
|
-
from openapi_python_generator.common import HTTPLibrary
|
|
7
|
+
from openapi_python_generator.common import HTTPLibrary, PydanticVersion
|
|
7
8
|
from openapi_python_generator.generate_data import generate_data
|
|
8
9
|
|
|
9
|
-
|
|
10
10
|
@click.command()
|
|
11
11
|
@click.argument("source")
|
|
12
12
|
@click.argument("output")
|
|
@@ -38,6 +38,13 @@ from openapi_python_generator.generate_data import generate_data
|
|
|
38
38
|
default=None,
|
|
39
39
|
help="Custom template path to use. Allows overriding of the built in templates",
|
|
40
40
|
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--pydantic-version",
|
|
43
|
+
type=click.Choice(["v1", "v2"]),
|
|
44
|
+
default="v2",
|
|
45
|
+
show_default=True,
|
|
46
|
+
help="Pydantic version to use for generated models.",
|
|
47
|
+
)
|
|
41
48
|
@click.version_option(version=__version__)
|
|
42
49
|
def main(
|
|
43
50
|
source: str,
|
|
@@ -46,6 +53,7 @@ def main(
|
|
|
46
53
|
env_token_name: Optional[str] = None,
|
|
47
54
|
use_orjson: bool = False,
|
|
48
55
|
custom_template_path: Optional[str] = None,
|
|
56
|
+
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
49
57
|
) -> None:
|
|
50
58
|
"""
|
|
51
59
|
Generate Python code from an OpenAPI 3.0 specification.
|
|
@@ -54,9 +62,9 @@ def main(
|
|
|
54
62
|
an OUTPUT path, where the resulting client is created.
|
|
55
63
|
"""
|
|
56
64
|
generate_data(
|
|
57
|
-
source, output, library, env_token_name, use_orjson, custom_template_path
|
|
65
|
+
source, output, library, env_token_name, use_orjson, custom_template_path,pydantic_version
|
|
58
66
|
)
|
|
59
67
|
|
|
60
68
|
|
|
61
69
|
if __name__ == "__main__": # pragma: no cover
|
|
62
|
-
main()
|
|
70
|
+
main()
|
|
@@ -14,6 +14,10 @@ class HTTPLibrary(str, Enum):
|
|
|
14
14
|
requests = "requests"
|
|
15
15
|
aiohttp = "aiohttp"
|
|
16
16
|
|
|
17
|
+
class PydanticVersion(str, Enum):
|
|
18
|
+
V1 = "v1"
|
|
19
|
+
V2 = "v2"
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
library_config_dict: Dict[Optional[HTTPLibrary], LibraryConfig] = {
|
|
19
23
|
HTTPLibrary.httpx: LibraryConfig(
|
|
@@ -10,10 +10,10 @@ import orjson
|
|
|
10
10
|
from black import NothingChanged
|
|
11
11
|
from httpx import ConnectError
|
|
12
12
|
from httpx import ConnectTimeout
|
|
13
|
-
from
|
|
13
|
+
from openapi_pydantic.v3.v3_0 import OpenAPI
|
|
14
14
|
from pydantic import ValidationError
|
|
15
15
|
|
|
16
|
-
from .common import HTTPLibrary
|
|
16
|
+
from .common import HTTPLibrary, PydanticVersion
|
|
17
17
|
from .common import library_config_dict
|
|
18
18
|
from .language_converters.python.generator import generator
|
|
19
19
|
from .language_converters.python.jinja_config import SERVICE_TEMPLATE
|
|
@@ -56,7 +56,8 @@ def get_open_api(source: Union[str, Path]) -> OpenAPI:
|
|
|
56
56
|
return OpenAPI(**orjson.loads(httpx.get(source).text))
|
|
57
57
|
|
|
58
58
|
with open(source, "r") as f:
|
|
59
|
-
|
|
59
|
+
file_content = f.read()
|
|
60
|
+
return OpenAPI(**orjson.loads(file_content))
|
|
60
61
|
except FileNotFoundError:
|
|
61
62
|
click.echo(
|
|
62
63
|
f"File {source} not found. Please make sure to pass the path to the OpenAPI 3.0 specification."
|
|
@@ -139,6 +140,7 @@ def generate_data(
|
|
|
139
140
|
env_token_name: Optional[str] = None,
|
|
140
141
|
use_orjson: bool = False,
|
|
141
142
|
custom_template_path: Optional[str] = None,
|
|
143
|
+
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
142
144
|
) -> None:
|
|
143
145
|
"""
|
|
144
146
|
Generate Python code from an OpenAPI 3.0 specification.
|
|
@@ -152,6 +154,7 @@ def generate_data(
|
|
|
152
154
|
env_token_name,
|
|
153
155
|
use_orjson,
|
|
154
156
|
custom_template_path,
|
|
157
|
+
pydantic_version,
|
|
155
158
|
)
|
|
156
159
|
|
|
157
160
|
write_data(result, output)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from openapi_pydantic.v3.v3_0 import OpenAPI
|
|
4
4
|
|
|
5
|
+
from openapi_python_generator.common import PydanticVersion
|
|
5
6
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
6
|
-
API_CONFIG_TEMPLATE,
|
|
7
|
+
API_CONFIG_TEMPLATE, API_CONFIG_TEMPLATE_PYDANTIC_V2,
|
|
7
8
|
)
|
|
8
9
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
9
10
|
create_jinja_env,
|
|
@@ -12,15 +13,18 @@ from openapi_python_generator.models import APIConfig
|
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def generate_api_config(
|
|
15
|
-
|
|
16
|
+
data: OpenAPI, env_token_name: Optional[str] = None,
|
|
17
|
+
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
16
18
|
) -> APIConfig:
|
|
17
19
|
"""
|
|
18
20
|
Generate the API model.
|
|
19
21
|
"""
|
|
22
|
+
|
|
23
|
+
template_name = API_CONFIG_TEMPLATE_PYDANTIC_V2 if pydantic_version == PydanticVersion.V2 else API_CONFIG_TEMPLATE
|
|
20
24
|
jinja_env = create_jinja_env()
|
|
21
25
|
return APIConfig(
|
|
22
26
|
file_name="api_config",
|
|
23
|
-
content=jinja_env.get_template(
|
|
27
|
+
content=jinja_env.get_template(template_name).render(
|
|
24
28
|
env_token_name=env_token_name, **data.dict()
|
|
25
29
|
),
|
|
26
30
|
base_url=data.servers[0].url if len(data.servers) > 0 else "NO SERVER",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from openapi_pydantic.v3.v3_0 import OpenAPI
|
|
4
4
|
|
|
5
|
+
from openapi_python_generator.common import PydanticVersion
|
|
5
6
|
from openapi_python_generator.language_converters.python import common
|
|
6
7
|
from openapi_python_generator.language_converters.python.api_config_generator import (
|
|
7
8
|
generate_api_config,
|
|
@@ -22,6 +23,7 @@ def generator(
|
|
|
22
23
|
env_token_name: Optional[str] = None,
|
|
23
24
|
use_orjson: bool = False,
|
|
24
25
|
custom_template_path: Optional[str] = None,
|
|
26
|
+
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
25
27
|
) -> ConversionResult:
|
|
26
28
|
"""
|
|
27
29
|
Generate Python code from an OpenAPI 3.0 specification.
|
|
@@ -31,7 +33,7 @@ def generator(
|
|
|
31
33
|
common.set_custom_template_path(custom_template_path)
|
|
32
34
|
|
|
33
35
|
if data.components is not None:
|
|
34
|
-
models = generate_models(data.components)
|
|
36
|
+
models = generate_models(data.components, pydantic_version)
|
|
35
37
|
else:
|
|
36
38
|
models = []
|
|
37
39
|
|
|
@@ -40,7 +42,7 @@ def generator(
|
|
|
40
42
|
else:
|
|
41
43
|
services = []
|
|
42
44
|
|
|
43
|
-
api_config = generate_api_config(data, env_token_name)
|
|
45
|
+
api_config = generate_api_config(data, env_token_name, pydantic_version)
|
|
44
46
|
|
|
45
47
|
return ConversionResult(
|
|
46
48
|
models=models,
|
|
@@ -9,9 +9,11 @@ from . import common
|
|
|
9
9
|
|
|
10
10
|
ENUM_TEMPLATE = "enum.jinja2"
|
|
11
11
|
MODELS_TEMPLATE = "models.jinja2"
|
|
12
|
+
MODELS_TEMPLATE_PYDANTIC_V2 = "models_pydantic_2.jinja2"
|
|
12
13
|
SERVICE_TEMPLATE = "service.jinja2"
|
|
13
14
|
HTTPX_TEMPLATE = "httpx.jinja2"
|
|
14
15
|
API_CONFIG_TEMPLATE = "apiconfig.jinja2"
|
|
16
|
+
API_CONFIG_TEMPLATE_PYDANTIC_V2 = "apiconfig_pydantic_2.jinja2"
|
|
15
17
|
TEMPLATE_PATH = Path(__file__).parent / "templates"
|
|
16
18
|
|
|
17
19
|
|
|
@@ -4,13 +4,12 @@ from typing import List
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
|
-
from
|
|
8
|
-
from openapi_schema_pydantic import Reference
|
|
9
|
-
from openapi_schema_pydantic import Schema
|
|
7
|
+
from openapi_pydantic.v3.v3_0 import Schema, Reference, Components
|
|
10
8
|
|
|
9
|
+
from openapi_python_generator.common import PydanticVersion
|
|
11
10
|
from openapi_python_generator.language_converters.python import common
|
|
12
11
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
13
|
-
ENUM_TEMPLATE,
|
|
12
|
+
ENUM_TEMPLATE, MODELS_TEMPLATE_PYDANTIC_V2,
|
|
14
13
|
)
|
|
15
14
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
16
15
|
MODELS_TEMPLATE,
|
|
@@ -24,9 +23,9 @@ from openapi_python_generator.models import TypeConversion
|
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
def type_converter( # noqa: C901
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
schema: Schema,
|
|
27
|
+
required: bool = False,
|
|
28
|
+
model_name: Optional[str] = None,
|
|
30
29
|
) -> TypeConversion:
|
|
31
30
|
"""
|
|
32
31
|
Converts an OpenAPI type to a Python type.
|
|
@@ -42,7 +41,7 @@ def type_converter( # noqa: C901
|
|
|
42
41
|
pre_type = "Optional["
|
|
43
42
|
post_type = "]"
|
|
44
43
|
|
|
45
|
-
original_type = schema.type if schema.type is not None else "object"
|
|
44
|
+
original_type = schema.type.value if schema.type is not None else "object"
|
|
46
45
|
import_types: Optional[List[str]] = None
|
|
47
46
|
|
|
48
47
|
if schema.allOf is not None:
|
|
@@ -71,13 +70,13 @@ def type_converter( # noqa: C901
|
|
|
71
70
|
)
|
|
72
71
|
|
|
73
72
|
original_type = (
|
|
74
|
-
|
|
73
|
+
"tuple<" + ",".join([i.original_type for i in conversions]) + ">"
|
|
75
74
|
)
|
|
76
75
|
if len(conversions) == 1:
|
|
77
76
|
converted_type = conversions[0].converted_type
|
|
78
77
|
else:
|
|
79
78
|
converted_type = (
|
|
80
|
-
|
|
79
|
+
"Tuple[" + ",".join([i.converted_type for i in conversions]) + "]"
|
|
81
80
|
)
|
|
82
81
|
|
|
83
82
|
converted_type = pre_type + converted_type + post_type
|
|
@@ -103,14 +102,14 @@ def type_converter( # noqa: C901
|
|
|
103
102
|
)
|
|
104
103
|
)
|
|
105
104
|
original_type = (
|
|
106
|
-
|
|
105
|
+
"union<" + ",".join([i.original_type for i in conversions]) + ">"
|
|
107
106
|
)
|
|
108
107
|
|
|
109
108
|
if len(conversions) == 1:
|
|
110
109
|
converted_type = conversions[0].converted_type
|
|
111
110
|
else:
|
|
112
111
|
converted_type = (
|
|
113
|
-
|
|
112
|
+
"Union[" + ",".join([i.converted_type for i in conversions]) + "]"
|
|
114
113
|
)
|
|
115
114
|
|
|
116
115
|
converted_type = pre_type + converted_type + post_type
|
|
@@ -122,13 +121,13 @@ def type_converter( # noqa: C901
|
|
|
122
121
|
# We only want to auto convert to datetime if orjson is used throghout the code, otherwise we can not
|
|
123
122
|
# serialize it to JSON.
|
|
124
123
|
elif schema.type == "string" and (
|
|
125
|
-
|
|
124
|
+
schema.schema_format is None or not common.get_use_orjson()
|
|
126
125
|
):
|
|
127
126
|
converted_type = pre_type + "str" + post_type
|
|
128
127
|
elif (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
schema.type == "string"
|
|
129
|
+
and schema.schema_format.startswith("uuid")
|
|
130
|
+
and common.get_use_orjson()
|
|
132
131
|
):
|
|
133
132
|
if len(schema.schema_format) > 4 and schema.schema_format[4].isnumeric():
|
|
134
133
|
uuid_type = schema.schema_format.upper()
|
|
@@ -156,7 +155,8 @@ def type_converter( # noqa: C901
|
|
|
156
155
|
original_type = "array<" + converted_reference.type.original_type + ">"
|
|
157
156
|
retVal += converted_reference.type.converted_type
|
|
158
157
|
elif isinstance(schema.items, Schema):
|
|
159
|
-
original_type = "array<" +
|
|
158
|
+
original_type = "array<" + (
|
|
159
|
+
str(schema.items.type.value) if schema.items.type is not None else "unknown") + ">"
|
|
160
160
|
retVal += type_converter(schema.items, True).converted_type
|
|
161
161
|
else:
|
|
162
162
|
original_type = "array<unknown>"
|
|
@@ -180,7 +180,7 @@ def type_converter( # noqa: C901
|
|
|
180
180
|
|
|
181
181
|
|
|
182
182
|
def _generate_property_from_schema(
|
|
183
|
-
|
|
183
|
+
model_name: str, name: str, schema: Schema, parent_schema: Optional[Schema] = None
|
|
184
184
|
) -> Property:
|
|
185
185
|
"""
|
|
186
186
|
Generates a property from a schema. It takes the type of the schema and converts it to a python type, and then
|
|
@@ -192,24 +192,30 @@ def _generate_property_from_schema(
|
|
|
192
192
|
:return: Property
|
|
193
193
|
"""
|
|
194
194
|
required = (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
parent_schema is not None
|
|
196
|
+
and parent_schema.required is not None
|
|
197
|
+
and name in parent_schema.required
|
|
198
198
|
)
|
|
199
|
+
|
|
200
|
+
import_type = None
|
|
201
|
+
if required:
|
|
202
|
+
import_type = [] if name == model_name else [name]
|
|
203
|
+
|
|
199
204
|
return Property(
|
|
200
205
|
name=name,
|
|
201
206
|
type=type_converter(schema, required, model_name),
|
|
202
207
|
required=required,
|
|
203
208
|
default=None if required else "None",
|
|
209
|
+
import_type=import_type,
|
|
204
210
|
)
|
|
205
211
|
|
|
206
212
|
|
|
207
213
|
def _generate_property_from_reference(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
model_name: str,
|
|
215
|
+
name: str,
|
|
216
|
+
reference: Reference,
|
|
217
|
+
parent_schema: Optional[Schema] = None,
|
|
218
|
+
force_required: bool = False,
|
|
213
219
|
) -> Property:
|
|
214
220
|
"""
|
|
215
221
|
Generates a property from a reference. It takes the name of the reference as the type, and then
|
|
@@ -221,10 +227,10 @@ def _generate_property_from_reference(
|
|
|
221
227
|
:return: Property and model to be imported by the file
|
|
222
228
|
"""
|
|
223
229
|
required = (
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
230
|
+
parent_schema is not None
|
|
231
|
+
and parent_schema.required is not None
|
|
232
|
+
and name in parent_schema.required
|
|
233
|
+
) or force_required
|
|
228
234
|
import_model = common.normalize_symbol(reference.ref.split("/")[-1])
|
|
229
235
|
|
|
230
236
|
if import_model == model_name:
|
|
@@ -252,13 +258,14 @@ def _generate_property_from_reference(
|
|
|
252
258
|
)
|
|
253
259
|
|
|
254
260
|
|
|
255
|
-
def generate_models(components: Components) -> List[Model]:
|
|
261
|
+
def generate_models(components: Components, pydantic_version: PydanticVersion = PydanticVersion.V2) -> List[Model]:
|
|
256
262
|
"""
|
|
257
263
|
Receives components from an OpenAPI 3.0 specification and generates the models from it.
|
|
258
264
|
It does so, by iterating over the components.schemas dictionary. For each schema, it checks if
|
|
259
265
|
it is a normal schema (i.e. simple type like string, integer, etc.), a reference to another schema, or
|
|
260
266
|
an array of types/references. It then computes pydantic models from it using jinja2
|
|
261
267
|
:param components: The components from an OpenAPI 3.0 specification.
|
|
268
|
+
:param pydantic_version: The version of pydantic to use.
|
|
262
269
|
:return: A list of models.
|
|
263
270
|
"""
|
|
264
271
|
models: List[Model] = []
|
|
@@ -309,7 +316,9 @@ def generate_models(components: Components) -> List[Model]:
|
|
|
309
316
|
)
|
|
310
317
|
properties.append(conv_property)
|
|
311
318
|
|
|
312
|
-
|
|
319
|
+
template_name = MODELS_TEMPLATE_PYDANTIC_V2 if pydantic_version == PydanticVersion.V2 else MODELS_TEMPLATE
|
|
320
|
+
|
|
321
|
+
generated_content = jinja_env.get_template(template_name).render(
|
|
313
322
|
schema_name=name, schema=schema_or_reference, properties=properties
|
|
314
323
|
)
|
|
315
324
|
|
|
@@ -7,14 +7,7 @@ from typing import Tuple
|
|
|
7
7
|
from typing import Union
|
|
8
8
|
|
|
9
9
|
import click
|
|
10
|
-
from
|
|
11
|
-
from openapi_schema_pydantic import Operation
|
|
12
|
-
from openapi_schema_pydantic import Parameter
|
|
13
|
-
from openapi_schema_pydantic import PathItem
|
|
14
|
-
from openapi_schema_pydantic import Reference
|
|
15
|
-
from openapi_schema_pydantic import RequestBody
|
|
16
|
-
from openapi_schema_pydantic import Response
|
|
17
|
-
from openapi_schema_pydantic import Schema
|
|
10
|
+
from openapi_pydantic.v3.v3_0 import Reference, Schema, Operation, Parameter, RequestBody, Response, MediaType, PathItem
|
|
18
11
|
|
|
19
12
|
from openapi_python_generator.language_converters.python import common
|
|
20
13
|
from openapi_python_generator.language_converters.python.common import normalize_symbol
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{% if env_token_name is not none %}import os{% endif %}
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from typing import Optional, Union
|
|
5
|
+
|
|
6
|
+
class APIConfig(BaseModel):
|
|
7
|
+
model_config = {
|
|
8
|
+
"validate_assignment": True
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
base_path: str = {% if servers|length > 0 %} '{{ servers[0].url }}' {% else %} 'NO SERVER' {% endif %}
|
|
12
|
+
|
|
13
|
+
verify: Union[bool, str] = True
|
|
14
|
+
{% if env_token_name is none %}
|
|
15
|
+
access_token : Optional[str] = None
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
def get_access_token(self) -> Optional[str]:
|
|
19
|
+
{% if env_token_name is not none %}
|
|
20
|
+
try:
|
|
21
|
+
return os.environ['{{ env_token_name }}']
|
|
22
|
+
except KeyError:
|
|
23
|
+
return None
|
|
24
|
+
{% else %}
|
|
25
|
+
return self.access_token
|
|
26
|
+
{% endif %}
|
|
27
|
+
|
|
28
|
+
def set_access_token(self, value : str):
|
|
29
|
+
{% if env_token_name is not none %}
|
|
30
|
+
raise Exception("This client was generated with an environment variable for the access token. Please set the environment variable '{{ env_token_name }}' to the access token.")
|
|
31
|
+
{% else %}
|
|
32
|
+
self.access_token = value
|
|
33
|
+
{% endif %}
|
|
34
|
+
|
|
35
|
+
class HTTPException(Exception):
|
|
36
|
+
def __init__(self, status_code: int, message: str):
|
|
37
|
+
self.status_code = status_code
|
|
38
|
+
self.message = message
|
|
39
|
+
super().__init__(f"{status_code} {message}")
|
|
40
|
+
|
|
41
|
+
def __str__(self):
|
|
42
|
+
return f"{self.status_code} {self.message}"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import *
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
{% for property in properties %}
|
|
4
|
+
{% if property.type.import_types is not none %}
|
|
5
|
+
{% for import_type in property.type.import_types %}
|
|
6
|
+
{{ import_type }}
|
|
7
|
+
{% endfor %}
|
|
8
|
+
{% endif %}
|
|
9
|
+
{% endfor %}
|
|
10
|
+
|
|
11
|
+
class {{ schema_name }}(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
{{ schema.title }} model
|
|
14
|
+
{% if schema.description != None %}
|
|
15
|
+
{{ schema.description }}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
model_config = {
|
|
20
|
+
"populate_by_name": True,
|
|
21
|
+
"validate_assignment": True
|
|
22
|
+
}
|
|
23
|
+
{% for property in properties %}
|
|
24
|
+
|
|
25
|
+
{{ property.name | replace("@","") | replace("-","_") }} : {{ property.type.converted_type | safe }} = Field(validation_alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %})
|
|
26
|
+
{% endfor %}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from openapi_schema_pydantic import PathItem
|
|
6
|
-
from openapi_schema_pydantic import Schema
|
|
4
|
+
from openapi_pydantic.v3.v3_0 import Operation, PathItem, Schema
|
|
7
5
|
from pydantic import BaseModel
|
|
8
6
|
|
|
9
7
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|