openapi-python-generator 1.1.2.dev1734089718__py3-none-any.whl → 1.2.1.dev1757310194__py3-none-any.whl
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/__init__.py +2 -1
- openapi_python_generator/__main__.py +21 -6
- openapi_python_generator/common.py +15 -0
- openapi_python_generator/generate_data.py +112 -65
- openapi_python_generator/language_converters/python/api_config_generator.py +12 -6
- openapi_python_generator/language_converters/python/generator.py +8 -4
- openapi_python_generator/language_converters/python/model_generator.py +191 -54
- openapi_python_generator/language_converters/python/service_generator.py +159 -62
- openapi_python_generator/language_converters/python/templates/aiohttp.jinja2 +10 -9
- openapi_python_generator/language_converters/python/templates/httpx.jinja2 +8 -5
- openapi_python_generator/language_converters/python/templates/models.jinja2 +5 -3
- openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 +5 -3
- openapi_python_generator/language_converters/python/templates/requests.jinja2 +8 -5
- openapi_python_generator/language_converters/python/templates/service.jinja2 +2 -1
- openapi_python_generator/models.py +16 -2
- openapi_python_generator/parsers/__init__.py +13 -0
- openapi_python_generator/parsers/openapi_30.py +65 -0
- openapi_python_generator/parsers/openapi_31.py +65 -0
- openapi_python_generator/py.typed +0 -0
- openapi_python_generator/version_detector.py +70 -0
- {openapi_python_generator-1.1.2.dev1734089718.dist-info → openapi_python_generator-1.2.1.dev1757310194.dist-info}/METADATA +3 -3
- openapi_python_generator-1.2.1.dev1757310194.dist-info/RECORD +32 -0
- openapi_python_generator-1.1.2.dev1734089718.dist-info/RECORD +0 -27
- {openapi_python_generator-1.1.2.dev1734089718.dist-info → openapi_python_generator-1.2.1.dev1757310194.dist-info}/LICENSE +0 -0
- {openapi_python_generator-1.1.2.dev1734089718.dist-info → openapi_python_generator-1.2.1.dev1757310194.dist-info}/WHEEL +0 -0
- {openapi_python_generator-1.1.2.dev1734089718.dist-info → openapi_python_generator-1.2.1.dev1757310194.dist-info}/entry_points.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
|
-
from enum import Enum
|
|
3
2
|
|
|
4
3
|
import click
|
|
5
4
|
|
|
6
5
|
from openapi_python_generator import __version__
|
|
7
|
-
from openapi_python_generator.common import HTTPLibrary, PydanticVersion
|
|
6
|
+
from openapi_python_generator.common import Formatter, HTTPLibrary, PydanticVersion
|
|
8
7
|
from openapi_python_generator.generate_data import generate_data
|
|
9
8
|
|
|
9
|
+
|
|
10
10
|
@click.command()
|
|
11
11
|
@click.argument("source")
|
|
12
12
|
@click.argument("output")
|
|
@@ -45,6 +45,13 @@ from openapi_python_generator.generate_data import generate_data
|
|
|
45
45
|
show_default=True,
|
|
46
46
|
help="Pydantic version to use for generated models.",
|
|
47
47
|
)
|
|
48
|
+
@click.option(
|
|
49
|
+
"--formatter",
|
|
50
|
+
type=click.Choice(["black", "none"]),
|
|
51
|
+
default="black",
|
|
52
|
+
show_default=True,
|
|
53
|
+
help="Option to choose which auto formatter is applied.",
|
|
54
|
+
)
|
|
48
55
|
@click.version_option(version=__version__)
|
|
49
56
|
def main(
|
|
50
57
|
source: str,
|
|
@@ -54,17 +61,25 @@ def main(
|
|
|
54
61
|
use_orjson: bool = False,
|
|
55
62
|
custom_template_path: Optional[str] = None,
|
|
56
63
|
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
64
|
+
formatter: Formatter = Formatter.BLACK,
|
|
57
65
|
) -> None:
|
|
58
66
|
"""
|
|
59
|
-
Generate Python code from an OpenAPI 3.0 specification.
|
|
67
|
+
Generate Python code from an OpenAPI 3.0+ specification.
|
|
60
68
|
|
|
61
|
-
Provide a SOURCE (file or URL) containing the OpenAPI 3 specification and
|
|
69
|
+
Provide a SOURCE (file or URL) containing the OpenAPI 3.0+ specification and
|
|
62
70
|
an OUTPUT path, where the resulting client is created.
|
|
63
71
|
"""
|
|
64
72
|
generate_data(
|
|
65
|
-
source,
|
|
73
|
+
source,
|
|
74
|
+
output,
|
|
75
|
+
library,
|
|
76
|
+
env_token_name,
|
|
77
|
+
use_orjson,
|
|
78
|
+
custom_template_path,
|
|
79
|
+
pydantic_version,
|
|
80
|
+
formatter,
|
|
66
81
|
)
|
|
67
82
|
|
|
68
83
|
|
|
69
84
|
if __name__ == "__main__": # pragma: no cover
|
|
70
|
-
main()
|
|
85
|
+
main()
|
|
@@ -14,11 +14,26 @@ class HTTPLibrary(str, Enum):
|
|
|
14
14
|
requests = "requests"
|
|
15
15
|
aiohttp = "aiohttp"
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
class PydanticVersion(str, Enum):
|
|
18
19
|
V1 = "v1"
|
|
19
20
|
V2 = "v2"
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
class Formatter(str, Enum):
|
|
24
|
+
"""
|
|
25
|
+
Enum for the available code formatters.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
BLACK = "black"
|
|
29
|
+
NONE = "none"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FormatOptions:
|
|
33
|
+
skip_validation: bool = False
|
|
34
|
+
line_length: int = 120
|
|
35
|
+
|
|
36
|
+
|
|
22
37
|
library_config_dict: Dict[Optional[HTTPLibrary], LibraryConfig] = {
|
|
23
38
|
HTTPLibrary.httpx: LibraryConfig(
|
|
24
39
|
name="httpx",
|
|
@@ -1,59 +1,74 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
+
from typing import List
|
|
2
3
|
from typing import Optional
|
|
3
4
|
from typing import Union
|
|
4
5
|
|
|
5
6
|
import black
|
|
7
|
+
from black.report import NothingChanged # type: ignore
|
|
6
8
|
import click
|
|
7
9
|
import httpx
|
|
8
10
|
import isort
|
|
9
11
|
import orjson
|
|
10
|
-
import yaml
|
|
11
|
-
from black import NothingChanged
|
|
12
|
+
import yaml # type: ignore
|
|
12
13
|
from httpx import ConnectError
|
|
13
14
|
from httpx import ConnectTimeout
|
|
14
|
-
from openapi_pydantic.v3.v3_0 import OpenAPI
|
|
15
15
|
from pydantic import ValidationError
|
|
16
16
|
|
|
17
|
-
from .common import HTTPLibrary, PydanticVersion
|
|
18
|
-
from .common import library_config_dict
|
|
19
|
-
from .language_converters.python.generator import generator
|
|
17
|
+
from .common import FormatOptions, Formatter, HTTPLibrary, PydanticVersion
|
|
20
18
|
from .language_converters.python.jinja_config import SERVICE_TEMPLATE
|
|
21
19
|
from .language_converters.python.jinja_config import create_jinja_env
|
|
22
20
|
from .models import ConversionResult
|
|
21
|
+
from .version_detector import detect_openapi_version
|
|
22
|
+
from .parsers import (
|
|
23
|
+
parse_openapi_3_0,
|
|
24
|
+
parse_openapi_3_1,
|
|
25
|
+
generate_code_3_0,
|
|
26
|
+
generate_code_3_1,
|
|
27
|
+
)
|
|
23
28
|
|
|
24
29
|
|
|
25
|
-
def write_code(path: Path, content) -> None:
|
|
30
|
+
def write_code(path: Path, content: str, formatter: Formatter) -> None:
|
|
26
31
|
"""
|
|
27
32
|
Write the content to the file at the given path.
|
|
28
|
-
:param autoformat: The autoformat applied to the code written.
|
|
29
33
|
:param path: The path to the file.
|
|
30
34
|
:param content: The content to write.
|
|
35
|
+
:param formatter: The formatter applied to the code written.
|
|
31
36
|
"""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
if formatter == Formatter.BLACK:
|
|
38
|
+
formatted_contend = format_using_black(content)
|
|
39
|
+
elif formatter == Formatter.NONE:
|
|
40
|
+
formatted_contend = content
|
|
41
|
+
else:
|
|
42
|
+
raise NotImplementedError(
|
|
43
|
+
f"Missing implementation for formatter {formatter!r}."
|
|
44
|
+
)
|
|
45
|
+
with open(path, "w") as f:
|
|
46
|
+
f.write(formatted_contend)
|
|
47
|
+
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
def format_using_black(content: str) -> str:
|
|
50
|
+
try:
|
|
51
|
+
formatted_contend = black.format_file_contents(
|
|
52
|
+
content,
|
|
53
|
+
fast=FormatOptions.skip_validation,
|
|
54
|
+
mode=black.FileMode(line_length=FormatOptions.line_length),
|
|
55
|
+
)
|
|
56
|
+
except NothingChanged:
|
|
57
|
+
return content
|
|
58
|
+
return isort.code(formatted_contend, line_length=FormatOptions.line_length)
|
|
45
59
|
|
|
46
60
|
|
|
47
|
-
def get_open_api(source: Union[str, Path])
|
|
61
|
+
def get_open_api(source: Union[str, Path]):
|
|
48
62
|
"""
|
|
49
63
|
Tries to fetch the openapi specification file from the web or load from a local file.
|
|
50
64
|
Supports both JSON and YAML formats. Returns the according OpenAPI object.
|
|
65
|
+
Automatically supports OpenAPI 3.0 and 3.1 specifications with intelligent version detection.
|
|
51
66
|
|
|
52
67
|
Args:
|
|
53
68
|
source: URL or file path to the OpenAPI specification
|
|
54
69
|
|
|
55
70
|
Returns:
|
|
56
|
-
|
|
71
|
+
tuple: (OpenAPI object, version) where version is "3.0" or "3.1"
|
|
57
72
|
|
|
58
73
|
Raises:
|
|
59
74
|
FileNotFoundError: If the specified file cannot be found
|
|
@@ -64,31 +79,46 @@ def get_open_api(source: Union[str, Path]) -> OpenAPI:
|
|
|
64
79
|
try:
|
|
65
80
|
# Handle remote files
|
|
66
81
|
if not isinstance(source, Path) and (
|
|
67
|
-
|
|
82
|
+
source.startswith("http://") or source.startswith("https://")
|
|
68
83
|
):
|
|
69
84
|
content = httpx.get(source).text
|
|
70
85
|
# Try JSON first, then YAML for remote files
|
|
71
86
|
try:
|
|
72
|
-
|
|
87
|
+
data = orjson.loads(content)
|
|
73
88
|
except orjson.JSONDecodeError:
|
|
74
|
-
|
|
89
|
+
data = yaml.safe_load(content)
|
|
90
|
+
else:
|
|
91
|
+
# Handle local files
|
|
92
|
+
with open(source, "r") as f:
|
|
93
|
+
file_content = f.read()
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
with open(source, "r") as f:
|
|
78
|
-
file_content = f.read()
|
|
79
|
-
|
|
80
|
-
# Try JSON first
|
|
81
|
-
try:
|
|
82
|
-
return OpenAPI(**orjson.loads(file_content))
|
|
83
|
-
except orjson.JSONDecodeError:
|
|
84
|
-
# If JSON fails, try YAML
|
|
95
|
+
# Try JSON first
|
|
85
96
|
try:
|
|
86
|
-
|
|
87
|
-
except
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
data = orjson.loads(file_content)
|
|
98
|
+
except orjson.JSONDecodeError:
|
|
99
|
+
# If JSON fails, try YAML
|
|
100
|
+
try:
|
|
101
|
+
data = yaml.safe_load(file_content)
|
|
102
|
+
except yaml.YAMLError as e:
|
|
103
|
+
click.echo(
|
|
104
|
+
f"File {source} is neither a valid JSON nor YAML file: {str(e)}"
|
|
105
|
+
)
|
|
106
|
+
raise
|
|
107
|
+
|
|
108
|
+
# Detect version and parse with appropriate parser
|
|
109
|
+
version = detect_openapi_version(data)
|
|
110
|
+
|
|
111
|
+
if version == "3.0":
|
|
112
|
+
openapi_obj = parse_openapi_3_0(data) # type: ignore[assignment]
|
|
113
|
+
elif version == "3.1":
|
|
114
|
+
openapi_obj = parse_openapi_3_1(data) # type: ignore[assignment]
|
|
115
|
+
else:
|
|
116
|
+
# Unsupported version detected (version detection already limited to 3.0 / 3.1)
|
|
117
|
+
raise ValueError(
|
|
118
|
+
f"Unsupported OpenAPI version: {version}. Only 3.0.x and 3.1.x are supported."
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
return openapi_obj, version
|
|
92
122
|
|
|
93
123
|
except FileNotFoundError:
|
|
94
124
|
click.echo(
|
|
@@ -99,20 +129,20 @@ def get_open_api(source: Union[str, Path]) -> OpenAPI:
|
|
|
99
129
|
click.echo(f"Could not connect to {source}.")
|
|
100
130
|
raise ConnectError(f"Could not connect to {source}.") from None
|
|
101
131
|
except ValidationError:
|
|
102
|
-
click.echo(
|
|
103
|
-
f"File {source} is not a valid OpenAPI 3.0 specification."
|
|
104
|
-
)
|
|
132
|
+
click.echo(f"File {source} is not a valid OpenAPI 3.0+ specification.")
|
|
105
133
|
raise
|
|
106
134
|
|
|
107
135
|
|
|
108
|
-
def write_data(
|
|
136
|
+
def write_data(
|
|
137
|
+
data: ConversionResult, output: Union[str, Path], formatter: Formatter
|
|
138
|
+
) -> None:
|
|
109
139
|
"""
|
|
110
|
-
This function will firstly create the
|
|
140
|
+
This function will firstly create the folder structure of output, if it doesn't exist. Then it will create the
|
|
111
141
|
models from data.models into the models sub module of the output folder. After this, the services will be created
|
|
112
142
|
into the services sub module of the output folder.
|
|
113
|
-
:param autoformat: The autoformat applied to the code written.
|
|
114
143
|
:param data: The data to write.
|
|
115
144
|
:param output: The path to the output folder.
|
|
145
|
+
:param formatter: The formatter applied to the code written.
|
|
116
146
|
"""
|
|
117
147
|
|
|
118
148
|
# Create the folder structure of the output folder.
|
|
@@ -126,17 +156,18 @@ def write_data(data: ConversionResult, output: Union[str, Path]) -> None:
|
|
|
126
156
|
services_path = Path(output) / "services"
|
|
127
157
|
services_path.mkdir(parents=True, exist_ok=True)
|
|
128
158
|
|
|
129
|
-
files = []
|
|
159
|
+
files: List[str] = []
|
|
130
160
|
|
|
131
161
|
# Write the models.
|
|
132
162
|
for model in data.models:
|
|
133
163
|
files.append(model.file_name)
|
|
134
|
-
write_code(models_path / f"{model.file_name}.py", model.content)
|
|
164
|
+
write_code(models_path / f"{model.file_name}.py", model.content, formatter)
|
|
135
165
|
|
|
136
166
|
# Create models.__init__.py file containing imports to all models.
|
|
137
167
|
write_code(
|
|
138
168
|
models_path / "__init__.py",
|
|
139
169
|
"\n".join([f"from .{file} import *" for file in files]),
|
|
170
|
+
formatter,
|
|
140
171
|
)
|
|
141
172
|
|
|
142
173
|
files = []
|
|
@@ -149,44 +180,60 @@ def write_data(data: ConversionResult, output: Union[str, Path]) -> None:
|
|
|
149
180
|
files.append(service.file_name)
|
|
150
181
|
write_code(
|
|
151
182
|
services_path / f"{service.file_name}.py",
|
|
152
|
-
jinja_env.get_template(SERVICE_TEMPLATE).render(**service.
|
|
183
|
+
jinja_env.get_template(SERVICE_TEMPLATE).render(**service.model_dump()),
|
|
184
|
+
formatter,
|
|
153
185
|
)
|
|
154
186
|
|
|
155
187
|
# Create services.__init__.py file containing imports to all services.
|
|
156
|
-
write_code(services_path / "__init__.py", "")
|
|
188
|
+
write_code(services_path / "__init__.py", "", formatter)
|
|
157
189
|
|
|
158
190
|
# Write the api_config.py file.
|
|
159
|
-
write_code(Path(output) / "api_config.py", data.api_config.content)
|
|
191
|
+
write_code(Path(output) / "api_config.py", data.api_config.content, formatter)
|
|
160
192
|
|
|
161
193
|
# Write the __init__.py file.
|
|
162
194
|
write_code(
|
|
163
195
|
Path(output) / "__init__.py",
|
|
164
196
|
"from .models import *\nfrom .services import *\nfrom .api_config import *",
|
|
197
|
+
formatter,
|
|
165
198
|
)
|
|
166
199
|
|
|
167
200
|
|
|
168
201
|
def generate_data(
|
|
169
202
|
source: Union[str, Path],
|
|
170
203
|
output: Union[str, Path],
|
|
171
|
-
library:
|
|
204
|
+
library: HTTPLibrary = HTTPLibrary.httpx,
|
|
172
205
|
env_token_name: Optional[str] = None,
|
|
173
206
|
use_orjson: bool = False,
|
|
174
207
|
custom_template_path: Optional[str] = None,
|
|
175
208
|
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
209
|
+
formatter: Formatter = Formatter.BLACK,
|
|
176
210
|
) -> None:
|
|
177
211
|
"""
|
|
178
|
-
Generate Python code from an OpenAPI 3.0 specification.
|
|
212
|
+
Generate Python code from an OpenAPI 3.0+ specification.
|
|
179
213
|
"""
|
|
180
|
-
|
|
181
|
-
click.echo(f"Generating data from {source}")
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
214
|
+
openapi_obj, version = get_open_api(source)
|
|
215
|
+
click.echo(f"Generating data from {source} (OpenAPI {version})")
|
|
216
|
+
|
|
217
|
+
# Use version-specific generator
|
|
218
|
+
if version == "3.0":
|
|
219
|
+
result = generate_code_3_0(
|
|
220
|
+
openapi_obj, # type: ignore
|
|
221
|
+
library,
|
|
222
|
+
env_token_name,
|
|
223
|
+
use_orjson,
|
|
224
|
+
custom_template_path,
|
|
225
|
+
pydantic_version,
|
|
226
|
+
)
|
|
227
|
+
elif version == "3.1":
|
|
228
|
+
result = generate_code_3_1(
|
|
229
|
+
openapi_obj, # type: ignore
|
|
230
|
+
library,
|
|
231
|
+
env_token_name,
|
|
232
|
+
use_orjson,
|
|
233
|
+
custom_template_path,
|
|
234
|
+
pydantic_version,
|
|
235
|
+
)
|
|
236
|
+
else:
|
|
237
|
+
raise ValueError(f"Unsupported OpenAPI version: {version}")
|
|
191
238
|
|
|
192
|
-
write_data(result, output)
|
|
239
|
+
write_data(result, output, formatter)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from openapi_pydantic.v3
|
|
3
|
+
from openapi_pydantic.v3 import OpenAPI
|
|
4
4
|
|
|
5
5
|
from openapi_python_generator.common import PydanticVersion
|
|
6
6
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
7
|
-
API_CONFIG_TEMPLATE,
|
|
7
|
+
API_CONFIG_TEMPLATE,
|
|
8
|
+
API_CONFIG_TEMPLATE_PYDANTIC_V2,
|
|
8
9
|
)
|
|
9
10
|
from openapi_python_generator.language_converters.python.jinja_config import (
|
|
10
11
|
create_jinja_env,
|
|
@@ -13,19 +14,24 @@ from openapi_python_generator.models import APIConfig
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def generate_api_config(
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
data: OpenAPI,
|
|
18
|
+
env_token_name: Optional[str] = None,
|
|
19
|
+
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
18
20
|
) -> APIConfig:
|
|
19
21
|
"""
|
|
20
22
|
Generate the API model.
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
|
-
template_name =
|
|
25
|
+
template_name = (
|
|
26
|
+
API_CONFIG_TEMPLATE_PYDANTIC_V2
|
|
27
|
+
if pydantic_version == PydanticVersion.V2
|
|
28
|
+
else API_CONFIG_TEMPLATE
|
|
29
|
+
)
|
|
24
30
|
jinja_env = create_jinja_env()
|
|
25
31
|
return APIConfig(
|
|
26
32
|
file_name="api_config",
|
|
27
33
|
content=jinja_env.get_template(template_name).render(
|
|
28
|
-
env_token_name=env_token_name, **data.
|
|
34
|
+
env_token_name=env_token_name, **data.model_dump()
|
|
29
35
|
),
|
|
30
36
|
base_url=data.servers[0].url if len(data.servers) > 0 else "NO SERVER",
|
|
31
37
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Optional, Union
|
|
2
2
|
|
|
3
|
-
from openapi_pydantic.v3.v3_0 import OpenAPI
|
|
3
|
+
from openapi_pydantic.v3.v3_0 import OpenAPI as OpenAPI30
|
|
4
|
+
from openapi_pydantic.v3.v3_1 import OpenAPI as OpenAPI31
|
|
4
5
|
|
|
5
6
|
from openapi_python_generator.common import PydanticVersion
|
|
6
7
|
from openapi_python_generator.language_converters.python import common
|
|
@@ -16,9 +17,12 @@ from openapi_python_generator.language_converters.python.service_generator impor
|
|
|
16
17
|
from openapi_python_generator.models import ConversionResult
|
|
17
18
|
from openapi_python_generator.models import LibraryConfig
|
|
18
19
|
|
|
20
|
+
# Type alias for both OpenAPI versions
|
|
21
|
+
OpenAPISpec = Union[OpenAPI30, OpenAPI31]
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
def generator(
|
|
21
|
-
data:
|
|
25
|
+
data: OpenAPISpec,
|
|
22
26
|
library_config: LibraryConfig,
|
|
23
27
|
env_token_name: Optional[str] = None,
|
|
24
28
|
use_orjson: bool = False,
|
|
@@ -26,7 +30,7 @@ def generator(
|
|
|
26
30
|
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
27
31
|
) -> ConversionResult:
|
|
28
32
|
"""
|
|
29
|
-
Generate Python code from an OpenAPI 3.0 specification.
|
|
33
|
+
Generate Python code from an OpenAPI 3.0+ specification.
|
|
30
34
|
"""
|
|
31
35
|
|
|
32
36
|
common.set_use_orjson(use_orjson)
|