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.
Files changed (27) hide show
  1. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/PKG-INFO +5 -6
  2. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/pyproject.toml +6 -6
  3. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/setup.py +5 -5
  4. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/__main__.py +12 -4
  5. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/common.py +4 -0
  6. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/generate_data.py +6 -3
  7. {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
  8. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/generator.py +5 -3
  9. {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
  10. {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
  11. {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
  12. openapi_python_generator-1.0.0/src/openapi_python_generator/language_converters/python/templates/apiconfig_pydantic_2.jinja2 +42 -0
  13. openapi_python_generator-1.0.0/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 +26 -0
  14. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/models.py +1 -3
  15. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/LICENSE +0 -0
  16. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/README.md +0 -0
  17. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/__init__.py +0 -0
  18. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/__init__.py +0 -0
  19. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/__init__.py +0 -0
  20. {openapi_python_generator-0.5.1.dev1710539733 → openapi_python_generator-1.0.0}/src/openapi_python_generator/language_converters/python/common.py +0 -0
  21. {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
  22. {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
  23. {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
  24. {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
  25. {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
  26. {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
  27. {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.5.1.dev1710539733
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.7,<4.0
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-schema-pydantic (>=1.2.3,<2.0.0)
25
- Requires-Dist: orjson (>=3.7.2,<4.0.0)
26
- Requires-Dist: pydantic (>=1.9.1,<2.0.0)
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openapi-python-generator"
3
- version = "0.5.1.dev.1710539733"
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.7"
20
+ python = "^3.8"
21
21
  httpx = {extras = ["all"], version = "^0.23.0"}
22
- pydantic = "^1.9.1"
23
- orjson = "^3.7.2"
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.78.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-schema-pydantic>=1.2.3,<2.0.0',
23
- 'orjson>=3.7.2,<4.0.0',
24
- 'pydantic>=1.9.1,<2.0.0']
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.5.1.dev1710539733',
32
+ 'version': '1.0.0',
33
33
  'description': 'Openapi Python Generator',
34
34
  'long_description': "# Openapi Python Generator\n\n[![PyPI](https://img.shields.io/pypi/v/openapi-python-generator.svg)][pypi_]\n[![Status](https://img.shields.io/pypi/status/openapi-python-generator.svg)][status]\n[![Python Version](https://img.shields.io/pypi/pyversions/openapi-python-generator)][python version]\n[![License](https://img.shields.io/pypi/l/openapi-python-generator)][license]\n\n[![](https://img.shields.io/static/v1?label=documentation&message=enabled&color=<COLOR>)][documentation]\n[![Tests](https://github.com/MarcoMuellner/openapi-python-generator/workflows/Tests/badge.svg)][tests]\n[![Codecov](https://codecov.io/gh/MarcoMuellner/openapi-python-generator/branch/main/graph/badge.svg)][codecov]\n\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)][pre-commit]\n[![Black](https://img.shields.io/badge/code%20style-black-000000.svg)][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![](logo.png)\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.7,<4.0',
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 openapi_schema_pydantic import OpenAPI
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
- return OpenAPI(**orjson.loads(f.read()))
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 openapi_schema_pydantic import OpenAPI
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
- data: OpenAPI, env_token_name: Optional[str] = None
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(API_CONFIG_TEMPLATE).render(
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 openapi_schema_pydantic import OpenAPI
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 openapi_schema_pydantic import Components
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
- schema: Schema,
28
- required: bool = False,
29
- model_name: Optional[str] = None,
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
- "tuple<" + ",".join([i.original_type for i in conversions]) + ">"
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
- "Tuple[" + ",".join([i.converted_type for i in conversions]) + "]"
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
- "union<" + ",".join([i.original_type for i in conversions]) + ">"
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
- "Union[" + ",".join([i.converted_type for i in conversions]) + "]"
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
- schema.schema_format is None or not common.get_use_orjson()
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
- schema.type == "string"
130
- and schema.schema_format.startswith("uuid")
131
- and common.get_use_orjson()
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<" + str(schema.items.type) + ">"
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
- model_name: str, name: str, schema: Schema, parent_schema: Optional[Schema] = None
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
- parent_schema is not None
196
- and parent_schema.required is not None
197
- and name in parent_schema.required
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
- model_name: str,
209
- name: str,
210
- reference: Reference,
211
- parent_schema: Optional[Schema] = None,
212
- force_required: bool = False,
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
- parent_schema is not None
225
- and parent_schema.required is not None
226
- and name in parent_schema.required
227
- ) or force_required
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
- generated_content = jinja_env.get_template(MODELS_TEMPLATE).render(
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 openapi_schema_pydantic import MediaType
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 openapi_schema_pydantic import Operation
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