openapi-python-client 0.28.4__tar.gz → 0.29.1__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_client-0.28.4 → openapi_python_client-0.29.1}/.gitignore +2 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/PKG-INFO +6 -9
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/__init__.py +26 -17
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/cli.py +1 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/config.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/bodies.py +14 -23
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/openapi.py +58 -48
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/__init__.py +34 -33
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/any.py +11 -10
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/boolean.py +13 -13
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/const.py +11 -10
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/date.py +15 -14
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/datetime.py +15 -14
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/enum_property.py +23 -20
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/file.py +11 -10
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/float.py +13 -13
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/int.py +11 -11
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/list_property.py +22 -22
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/literal_enum_property.py +20 -20
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/merge_properties.py +9 -6
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/model_property.py +34 -33
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/none.py +11 -11
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/protocol.py +42 -32
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/schemas.py +30 -23
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/string.py +10 -11
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/union.py +24 -22
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/uuid.py +11 -11
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/responses.py +30 -23
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/__init__.py +2 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/data_type.py +2 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +3 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/components.py +10 -9
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +4 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +4 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/example.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +4 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/header.py +20 -6
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/info.py +5 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/license.py +4 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/link.py +5 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +3 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +6 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +6 -5
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +6 -5
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +2 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +3 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +3 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/response.py +5 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +2 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +7 -6
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +3 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +8 -7
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/server.py +4 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +5 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +3 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +5 -3
- openapi_python_client-0.29.1/openapi_python_client/schema/parameter_location.py +10 -0
- openapi_python_client-0.29.1/openapi_python_client/schema/ref.py +52 -0
- openapi_python_client-0.29.1/openapi_python_client/schema/untrusted_string.py +56 -0
- openapi_python_client-0.29.1/openapi_python_client/strings.py +245 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/README.md.jinja +3 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/client.py.jinja +5 -5
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/endpoint_macros.py.jinja +18 -18
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/endpoint_module.py.jinja +20 -14
- openapi_python_client-0.29.1/openapi_python_client/templates/helpers.jinja +6 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/literal_enum.py.jinja +3 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/model.py.jinja +18 -18
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/package_init.py.jinja +2 -2
- openapi_python_client-0.29.1/openapi_python_client/templates/property_templates/const_property.py.jinja +9 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/date_property.py.jinja +2 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +2 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/enum_property.py.jinja +1 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/file_property.py.jinja +1 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/list_property.py.jinja +3 -3
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja +2 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/model_property.py.jinja +1 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/property_macros.py.jinja +1 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/union_property.py.jinja +9 -9
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/uuid_property.py.jinja +1 -1
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/pyproject_pdm.toml.jinja +4 -5
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/pyproject_poetry.toml.jinja +4 -5
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/pyproject_uv.toml.jinja +5 -6
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/setup.py.jinja +4 -4
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/str_enum.py.jinja +2 -2
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/pyproject.toml +24 -25
- openapi_python_client-0.28.4/openapi_python_client/schema/parameter_location.py +0 -25
- openapi_python_client-0.28.4/openapi_python_client/templates/helpers.jinja +0 -10
- openapi_python_client-0.28.4/openapi_python_client/templates/property_templates/const_property.py.jinja +0 -9
- openapi_python_client-0.28.4/openapi_python_client/utils.py +0 -122
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/LICENSE +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/README.md +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/__main__.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/__init__.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/errors.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/properties/property.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/py.typed +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/3.0.3.md +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/3.1.0.md +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/.gitignore.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/api_init.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/errors.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/int_enum.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/models_init.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/pyproject.toml.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/pyproject_ruff.toml.jinja +0 -0
- {openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/templates/types.py.jinja +0 -0
|
@@ -1,34 +1,31 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: openapi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.29.1
|
|
4
4
|
Summary: Generate modern Python clients from OpenAPI
|
|
5
5
|
Project-URL: repository, https://github.com/openapi-generators/openapi-python-client
|
|
6
6
|
Author-email: Dylan Anthony <contact@dylananthony.com>
|
|
7
|
-
License: MIT
|
|
7
|
+
License-Expression: MIT
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Keywords: Client,Generator,OpenAPI
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
17
|
Classifier: Topic :: Software Development :: Code Generators
|
|
20
18
|
Classifier: Typing :: Typed
|
|
21
|
-
Requires-Python: <4.0,>=3.
|
|
19
|
+
Requires-Python: <4.0,>=3.11
|
|
22
20
|
Requires-Dist: attrs>=22.2.0
|
|
23
21
|
Requires-Dist: colorama>=0.4.3; sys_platform == 'win32'
|
|
24
|
-
Requires-Dist: httpx<0.29.0,>=0.23.
|
|
22
|
+
Requires-Dist: httpx<0.29.0,>=0.23.1
|
|
25
23
|
Requires-Dist: jinja2<4.0.0,>=3.0.0
|
|
26
24
|
Requires-Dist: pydantic<3.0.0,>=2.10
|
|
27
|
-
Requires-Dist: python-dateutil<3.0.0,>=2.8.1
|
|
28
25
|
Requires-Dist: ruamel-yaml<0.20.0,>=0.18.6
|
|
29
26
|
Requires-Dist: ruff>=0.2
|
|
30
27
|
Requires-Dist: shellingham<2.0.0,>=1.3.2
|
|
31
|
-
Requires-Dist: typer<0.
|
|
28
|
+
Requires-Dist: typer<0.28,>0.16
|
|
32
29
|
Description-Content-Type: text/markdown
|
|
33
30
|
|
|
34
31
|

|
{openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/__init__.py
RENAMED
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import mimetypes
|
|
5
5
|
import shutil
|
|
6
6
|
import subprocess
|
|
7
|
-
from collections.abc import Sequence
|
|
7
|
+
from collections.abc import Callable, Sequence
|
|
8
8
|
from importlib.metadata import version
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from subprocess import CalledProcessError
|
|
@@ -16,7 +16,7 @@ from jinja2 import BaseLoader, ChoiceLoader, Environment, FileSystemLoader, Pack
|
|
|
16
16
|
from ruamel.yaml import YAML
|
|
17
17
|
from ruamel.yaml.error import YAMLError
|
|
18
18
|
|
|
19
|
-
from openapi_python_client import
|
|
19
|
+
from openapi_python_client import strings
|
|
20
20
|
|
|
21
21
|
from .config import Config, MetaType
|
|
22
22
|
from .parser import GeneratorData, import_string_from_class
|
|
@@ -25,11 +25,16 @@ from .parser.properties import LiteralEnumProperty
|
|
|
25
25
|
|
|
26
26
|
__version__ = version(__package__)
|
|
27
27
|
|
|
28
|
+
from .schema.untrusted_string import UntrustedString
|
|
28
29
|
|
|
29
|
-
TEMPLATE_FILTERS = {
|
|
30
|
-
"snakecase":
|
|
31
|
-
"kebabcase":
|
|
32
|
-
"pascalcase":
|
|
30
|
+
TEMPLATE_FILTERS: dict[str, Callable[..., object]] = {
|
|
31
|
+
"snakecase": strings.snake_case,
|
|
32
|
+
"kebabcase": strings.kebab_case,
|
|
33
|
+
"pascalcase": strings.pascal_case,
|
|
34
|
+
"safe_for_docstring": strings.safe_for_docstring,
|
|
35
|
+
"in_double_quote_literal": strings.in_double_quote_literal,
|
|
36
|
+
"in_f_string_literal": strings.in_f_string_literal,
|
|
37
|
+
"as_unembedded_code": strings.PythonCode.as_unembedded_code,
|
|
33
38
|
"any": any,
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -66,14 +71,14 @@ class Project:
|
|
|
66
71
|
keep_trailing_newline=True,
|
|
67
72
|
)
|
|
68
73
|
|
|
69
|
-
self.project_name: str = config.project_name_override or f"{
|
|
74
|
+
self.project_name: str = config.project_name_override or f"{strings.kebab_case(openapi.title).lower()}-client"
|
|
70
75
|
self.package_name: str = config.package_name_override or self.project_name.replace("-", "_")
|
|
71
76
|
self.project_dir: Path # Where the generated code will be placed
|
|
72
77
|
self.package_dir: Path # Where the generated Python module will be placed (same as project_dir if no meta)
|
|
73
78
|
|
|
74
79
|
if config.output_path is not None:
|
|
75
80
|
self.project_dir = config.output_path
|
|
76
|
-
elif config.meta_type == MetaType.NONE:
|
|
81
|
+
elif config.meta_type == MetaType.NONE: # pragma: no cover
|
|
77
82
|
self.project_dir = Path.cwd() / self.package_name
|
|
78
83
|
else:
|
|
79
84
|
self.project_dir = Path.cwd() / self.project_name
|
|
@@ -83,17 +88,20 @@ class Project:
|
|
|
83
88
|
else:
|
|
84
89
|
self.package_dir = self.project_dir / self.package_name
|
|
85
90
|
|
|
86
|
-
self.package_description
|
|
87
|
-
f"A client library for accessing {self.openapi.title}"
|
|
91
|
+
self.package_description = UntrustedString(
|
|
92
|
+
f"A client library for accessing {self.openapi.title.get_untrusted_value()}"
|
|
93
|
+
)
|
|
94
|
+
self.version: UntrustedString = (
|
|
95
|
+
UntrustedString(config.package_version_override) if config.package_version_override else openapi.version
|
|
88
96
|
)
|
|
89
|
-
self.version: str = config.package_version_override or openapi.version
|
|
90
97
|
|
|
91
98
|
self.env.filters.update(TEMPLATE_FILTERS)
|
|
92
99
|
self.env.globals.update(
|
|
93
100
|
config=config,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
strings=strings,
|
|
102
|
+
PythonCode=strings.PythonCode,
|
|
103
|
+
python_identifier=lambda x: strings.PythonIdentifier(x, config.field_prefix),
|
|
104
|
+
class_name=lambda x: strings.ClassName(x, config.field_prefix),
|
|
97
105
|
package_name=self.package_name,
|
|
98
106
|
package_dir=self.package_dir,
|
|
99
107
|
package_description=self.package_description,
|
|
@@ -110,7 +118,7 @@ class Project:
|
|
|
110
118
|
|
|
111
119
|
print(f"Generating {self.project_dir}")
|
|
112
120
|
try:
|
|
113
|
-
self.project_dir.mkdir()
|
|
121
|
+
self.project_dir.mkdir(parents=True)
|
|
114
122
|
except FileExistsError:
|
|
115
123
|
if not self.config.overwrite:
|
|
116
124
|
return [GeneratorError(detail="Directory already exists. Delete it or use the --overwrite option.")]
|
|
@@ -267,7 +275,8 @@ class Project:
|
|
|
267
275
|
|
|
268
276
|
endpoint_collections_by_tag = self.openapi.endpoint_collections_by_tag
|
|
269
277
|
endpoint_template = self.env.get_template(
|
|
270
|
-
"endpoint_module.py.jinja",
|
|
278
|
+
"endpoint_module.py.jinja",
|
|
279
|
+
globals={"isbool": lambda obj: obj.get_base_type_string() == strings.PythonCode("bool")},
|
|
271
280
|
)
|
|
272
281
|
for tag, collection in endpoint_collections_by_tag.items():
|
|
273
282
|
tag_dir = api_dir / tag
|
|
@@ -281,7 +290,7 @@ class Project:
|
|
|
281
290
|
)
|
|
282
291
|
|
|
283
292
|
for endpoint in collection.endpoints:
|
|
284
|
-
module_path = tag_dir / f"{
|
|
293
|
+
module_path = tag_dir / f"{strings.PythonIdentifier(endpoint.name, self.config.field_prefix)}.py"
|
|
285
294
|
module_path.write_text(
|
|
286
295
|
endpoint_template.render(
|
|
287
296
|
endpoint=endpoint,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import codecs
|
|
2
2
|
from collections.abc import Sequence
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from pprint import pformat
|
|
5
4
|
|
|
6
5
|
import typer
|
|
7
6
|
|
|
@@ -75,7 +74,7 @@ def _print_parser_error(err: GeneratorError, color: str) -> None:
|
|
|
75
74
|
typer.echo(err=True)
|
|
76
75
|
|
|
77
76
|
if isinstance(err, ParseError) and err.data is not None:
|
|
78
|
-
formatted_data =
|
|
77
|
+
formatted_data = err.data.model_dump_json(indent=2, exclude_unset=True, by_alias=True)
|
|
79
78
|
typer.secho(formatted_data, fg=color, err=True)
|
|
80
79
|
|
|
81
80
|
typer.echo(err=True)
|
{openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/config.py
RENAMED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import mimetypes
|
|
3
|
-
from enum import
|
|
3
|
+
from enum import StrEnum
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
from attr import define
|
|
7
7
|
from pydantic import BaseModel
|
|
8
8
|
from ruamel.yaml import YAML
|
|
9
9
|
|
|
10
|
+
from openapi_python_client.schema.untrusted_string import UntrustedString
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class ClassOverride(BaseModel):
|
|
12
14
|
"""An override of a single generated class.
|
|
@@ -14,11 +16,11 @@ class ClassOverride(BaseModel):
|
|
|
14
16
|
See https://github.com/openapi-generators/openapi-python-client#class_overrides
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
|
-
class_name:
|
|
19
|
+
class_name: UntrustedString | None = None
|
|
18
20
|
module_name: str | None = None
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
class MetaType(
|
|
23
|
+
class MetaType(StrEnum):
|
|
22
24
|
"""The types of metadata supported for project generation."""
|
|
23
25
|
|
|
24
26
|
NONE = "none"
|
{openapi_python_client-0.28.4 → openapi_python_client-0.29.1}/openapi_python_client/parser/bodies.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
from enum import StrEnum
|
|
2
2
|
|
|
3
3
|
import attr
|
|
4
4
|
|
|
@@ -12,30 +12,21 @@ from openapi_python_client.parser.properties.schemas import get_reference_simple
|
|
|
12
12
|
|
|
13
13
|
from .. import schema as oai
|
|
14
14
|
from ..config import Config
|
|
15
|
-
from ..
|
|
15
|
+
from ..schema.untrusted_string import UntrustedString
|
|
16
|
+
from ..strings import get_content_type
|
|
16
17
|
from .errors import ErrorLevel, ParseError
|
|
17
18
|
|
|
18
|
-
if sys.version_info >= (3, 11):
|
|
19
|
-
from enum import StrEnum
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
else:
|
|
27
|
-
from enum import Enum
|
|
28
|
-
|
|
29
|
-
class BodyType(str, Enum):
|
|
30
|
-
JSON = "json"
|
|
31
|
-
DATA = "data"
|
|
32
|
-
FILES = "files"
|
|
33
|
-
CONTENT = "content"
|
|
20
|
+
class BodyType(StrEnum):
|
|
21
|
+
JSON = "json"
|
|
22
|
+
DATA = "data"
|
|
23
|
+
FILES = "files"
|
|
24
|
+
CONTENT = "content"
|
|
34
25
|
|
|
35
26
|
|
|
36
27
|
@attr.define
|
|
37
28
|
class Body:
|
|
38
|
-
content_type:
|
|
29
|
+
content_type: UntrustedString
|
|
39
30
|
prop: Property
|
|
40
31
|
body_type: BodyType
|
|
41
32
|
|
|
@@ -44,7 +35,7 @@ def body_from_data(
|
|
|
44
35
|
*,
|
|
45
36
|
data: oai.Operation,
|
|
46
37
|
schemas: Schemas,
|
|
47
|
-
request_bodies: dict[
|
|
38
|
+
request_bodies: dict[UntrustedString, oai.RequestBody | oai.Reference],
|
|
48
39
|
config: Config,
|
|
49
40
|
endpoint_name: str,
|
|
50
41
|
) -> tuple[list[Body | ParseError], Schemas]:
|
|
@@ -60,7 +51,7 @@ def body_from_data(
|
|
|
60
51
|
prefix_type_names = len(body_content) > 1
|
|
61
52
|
|
|
62
53
|
for content_type, media_type in body_content.items():
|
|
63
|
-
simplified_content_type = get_content_type(content_type, config)
|
|
54
|
+
simplified_content_type = get_content_type(content_type.get_untrusted_value(), config)
|
|
64
55
|
if simplified_content_type is None:
|
|
65
56
|
bodies.append(
|
|
66
57
|
ParseError(
|
|
@@ -98,7 +89,7 @@ def body_from_data(
|
|
|
98
89
|
)
|
|
99
90
|
continue
|
|
100
91
|
prop, schemas = property_from_data(
|
|
101
|
-
name="body",
|
|
92
|
+
name=UntrustedString("body"),
|
|
102
93
|
required=body.required,
|
|
103
94
|
data=media_type_schema,
|
|
104
95
|
schemas=schemas,
|
|
@@ -131,7 +122,7 @@ def body_from_data(
|
|
|
131
122
|
|
|
132
123
|
|
|
133
124
|
def _resolve_reference(
|
|
134
|
-
body: oai.RequestBody | oai.Reference | None, request_bodies: dict[
|
|
125
|
+
body: oai.RequestBody | oai.Reference | None, request_bodies: dict[UntrustedString, oai.RequestBody | oai.Reference]
|
|
135
126
|
) -> oai.RequestBody | ParseError | None:
|
|
136
127
|
if body is None:
|
|
137
128
|
return None
|
|
@@ -142,5 +133,5 @@ def _resolve_reference(
|
|
|
142
133
|
if isinstance(body, oai.Reference):
|
|
143
134
|
return ParseError(detail="Circular $ref in request body", data=body)
|
|
144
135
|
if body is None and references_seen:
|
|
145
|
-
return ParseError(detail=f"Could not resolve $ref {references_seen[-1]} in request body")
|
|
136
|
+
return ParseError(detail=f"Could not resolve $ref {references_seen[-1].get_untrusted_value()} in request body")
|
|
146
137
|
return body
|
|
@@ -7,9 +7,10 @@ from typing import Any, Protocol
|
|
|
7
7
|
from pydantic import ValidationError
|
|
8
8
|
|
|
9
9
|
from .. import schema as oai
|
|
10
|
-
from .. import
|
|
10
|
+
from .. import strings
|
|
11
11
|
from ..config import Config
|
|
12
|
-
from ..
|
|
12
|
+
from ..schema.untrusted_string import UntrustedString
|
|
13
|
+
from ..strings import PythonIdentifier
|
|
13
14
|
from .bodies import Body, body_from_data
|
|
14
15
|
from .errors import GeneratorError, ParseError, PropertyError
|
|
15
16
|
from .properties import (
|
|
@@ -46,15 +47,15 @@ class EndpointCollection:
|
|
|
46
47
|
@staticmethod
|
|
47
48
|
def from_data(
|
|
48
49
|
*,
|
|
49
|
-
data: dict[
|
|
50
|
+
data: dict[UntrustedString, oai.PathItem],
|
|
50
51
|
schemas: Schemas,
|
|
51
52
|
parameters: Parameters,
|
|
52
|
-
request_bodies: dict[
|
|
53
|
-
responses: dict[
|
|
53
|
+
request_bodies: dict[UntrustedString, oai.RequestBody | oai.Reference],
|
|
54
|
+
responses: dict[UntrustedString, oai.Response | oai.Reference],
|
|
54
55
|
config: Config,
|
|
55
|
-
) -> tuple[dict[
|
|
56
|
+
) -> tuple[dict[strings.PythonIdentifier, "EndpointCollection"], Schemas, Parameters]:
|
|
56
57
|
"""Parse the openapi paths data to get EndpointCollections by tag"""
|
|
57
|
-
endpoints_by_tag: dict[
|
|
58
|
+
endpoints_by_tag: dict[strings.PythonIdentifier, EndpointCollection] = {}
|
|
58
59
|
|
|
59
60
|
methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"]
|
|
60
61
|
|
|
@@ -64,7 +65,10 @@ class EndpointCollection:
|
|
|
64
65
|
if operation is None:
|
|
65
66
|
continue
|
|
66
67
|
|
|
67
|
-
tags = [
|
|
68
|
+
tags = [
|
|
69
|
+
strings.PythonIdentifier(value=tag, prefix="tag")
|
|
70
|
+
for tag in operation.tags or [UntrustedString("default")]
|
|
71
|
+
]
|
|
68
72
|
if not config.generate_all_tags:
|
|
69
73
|
tags = tags[:1]
|
|
70
74
|
|
|
@@ -93,12 +97,14 @@ class EndpointCollection:
|
|
|
93
97
|
if not isinstance(endpoint, ParseError):
|
|
94
98
|
endpoint = Endpoint.sort_parameters(endpoint=endpoint)
|
|
95
99
|
if isinstance(endpoint, ParseError):
|
|
96
|
-
endpoint.header = f"WARNING parsing {method.upper()} {path} within {'/'.join(tags)}. Endpoint will not be generated."
|
|
100
|
+
endpoint.header = f"WARNING parsing {method.upper()} {path.get_untrusted_value()} within {'/'.join(tags)}. Endpoint will not be generated."
|
|
97
101
|
for collection in collections:
|
|
98
102
|
collection.parse_errors.append(endpoint)
|
|
99
103
|
continue
|
|
100
104
|
for error in endpoint.errors:
|
|
101
|
-
error.header =
|
|
105
|
+
error.header = (
|
|
106
|
+
f"WARNING parsing {method.upper()} {path.get_untrusted_value()} within {'/'.join(tags)}."
|
|
107
|
+
)
|
|
102
108
|
for collection in collections:
|
|
103
109
|
collection.parse_errors.append(error)
|
|
104
110
|
for collection in collections:
|
|
@@ -107,14 +113,14 @@ class EndpointCollection:
|
|
|
107
113
|
return endpoints_by_tag, schemas, parameters
|
|
108
114
|
|
|
109
115
|
|
|
110
|
-
def generate_operation_id(*, path:
|
|
116
|
+
def generate_operation_id(*, path: UntrustedString, method: str, prefix: str) -> PythonIdentifier:
|
|
111
117
|
"""Generate an operationId from a path"""
|
|
112
|
-
|
|
113
|
-
if
|
|
114
|
-
|
|
115
|
-
if
|
|
116
|
-
|
|
117
|
-
return f"{method}_{
|
|
118
|
+
unsafe_id = path.get_untrusted_value().replace("{", "").replace("}", "").replace("/", "_")
|
|
119
|
+
if unsafe_id.startswith("_"):
|
|
120
|
+
unsafe_id = unsafe_id[1:]
|
|
121
|
+
if unsafe_id.endswith("_"): # pragma: no cover
|
|
122
|
+
unsafe_id = unsafe_id[:-1]
|
|
123
|
+
return PythonIdentifier(f"{method}_{unsafe_id}", prefix=prefix)
|
|
118
124
|
|
|
119
125
|
|
|
120
126
|
models_relative_prefix: str = "..."
|
|
@@ -134,13 +140,13 @@ class Endpoint:
|
|
|
134
140
|
Describes a single endpoint on the server
|
|
135
141
|
"""
|
|
136
142
|
|
|
137
|
-
path:
|
|
143
|
+
path: UntrustedString
|
|
138
144
|
method: str
|
|
139
|
-
description:
|
|
140
|
-
name:
|
|
145
|
+
description: UntrustedString
|
|
146
|
+
name: PythonIdentifier
|
|
141
147
|
requires_security: bool
|
|
142
148
|
tags: list[PythonIdentifier]
|
|
143
|
-
summary:
|
|
149
|
+
summary: UntrustedString
|
|
144
150
|
relative_imports: set[str] = field(default_factory=set)
|
|
145
151
|
query_parameters: list[Property] = field(default_factory=list)
|
|
146
152
|
path_parameters: list[Property] = field(default_factory=list)
|
|
@@ -156,7 +162,7 @@ class Endpoint:
|
|
|
156
162
|
endpoint: "Endpoint",
|
|
157
163
|
data: oai.Responses,
|
|
158
164
|
schemas: Schemas,
|
|
159
|
-
responses: dict[
|
|
165
|
+
responses: dict[UntrustedString, oai.Response | oai.Reference],
|
|
160
166
|
config: Config,
|
|
161
167
|
) -> tuple["Endpoint", Schemas]:
|
|
162
168
|
endpoint = deepcopy(endpoint)
|
|
@@ -234,7 +240,7 @@ class Endpoint:
|
|
|
234
240
|
|
|
235
241
|
endpoint = deepcopy(endpoint)
|
|
236
242
|
|
|
237
|
-
unique_parameters: set[tuple[
|
|
243
|
+
unique_parameters: set[tuple[UntrustedString, oai.ParameterLocation]] = set()
|
|
238
244
|
parameters_by_location: dict[str, list[Property]] = {
|
|
239
245
|
oai.ParameterLocation.QUERY: endpoint.query_parameters,
|
|
240
246
|
oai.ParameterLocation.PATH: endpoint.path_parameters,
|
|
@@ -260,7 +266,7 @@ class Endpoint:
|
|
|
260
266
|
detail=(
|
|
261
267
|
"Parameters MUST NOT contain duplicates. "
|
|
262
268
|
"A unique parameter is defined by a combination of a name and location. "
|
|
263
|
-
f"Duplicated parameters named `{param.name}` detected in `{param.param_in}`."
|
|
269
|
+
f"Duplicated parameters named `{param.name.get_untrusted_value()}` detected in `{param.param_in}`."
|
|
264
270
|
),
|
|
265
271
|
),
|
|
266
272
|
schemas,
|
|
@@ -312,7 +318,7 @@ class Endpoint:
|
|
|
312
318
|
self,
|
|
313
319
|
*,
|
|
314
320
|
config: Config,
|
|
315
|
-
previously_modified_params: set[tuple[oai.ParameterLocation,
|
|
321
|
+
previously_modified_params: set[tuple[oai.ParameterLocation, UntrustedString]] | None = None,
|
|
316
322
|
) -> "Endpoint | ParseError":
|
|
317
323
|
"""Check for conflicting parameters
|
|
318
324
|
|
|
@@ -330,7 +336,7 @@ class Endpoint:
|
|
|
330
336
|
location, prop = parameter
|
|
331
337
|
|
|
332
338
|
if prop.python_name in reserved_names:
|
|
333
|
-
prop.set_python_name(new_name=f"{prop.python_name}_{location}", config=config)
|
|
339
|
+
prop.set_python_name(new_name=UntrustedString(f"{prop.python_name}_{location}"), config=config)
|
|
334
340
|
modified_params.add((location, prop.name))
|
|
335
341
|
continue
|
|
336
342
|
|
|
@@ -349,9 +355,9 @@ class Endpoint:
|
|
|
349
355
|
|
|
350
356
|
if location != conflicting_location:
|
|
351
357
|
conflicting_prop.set_python_name(
|
|
352
|
-
new_name=f"{conflicting_prop.python_name}_{conflicting_location}", config=config
|
|
358
|
+
new_name=UntrustedString(f"{conflicting_prop.python_name}_{conflicting_location}"), config=config
|
|
353
359
|
)
|
|
354
|
-
prop.set_python_name(new_name=f"{prop.python_name}_{location}", config=config)
|
|
360
|
+
prop.set_python_name(new_name=UntrustedString(f"{prop.python_name}_{location}"), config=config)
|
|
355
361
|
elif conflicting_prop.name != prop.name: # Use the name to differentiate
|
|
356
362
|
conflicting_prop.set_python_name(new_name=conflicting_prop.name, config=config, skip_snake_case=True)
|
|
357
363
|
prop.set_python_name(new_name=prop.name, config=config, skip_snake_case=True)
|
|
@@ -378,7 +384,7 @@ class Endpoint:
|
|
|
378
384
|
the path parameters and they could not be sorted.
|
|
379
385
|
"""
|
|
380
386
|
endpoint = deepcopy(endpoint)
|
|
381
|
-
parameters_from_path = re.findall(_PATH_PARAM_REGEX, endpoint.path)
|
|
387
|
+
parameters_from_path = re.findall(_PATH_PARAM_REGEX, endpoint.path.get_untrusted_value())
|
|
382
388
|
try:
|
|
383
389
|
endpoint.path_parameters.sort(
|
|
384
390
|
key=lambda param: parameters_from_path.index(param.name),
|
|
@@ -388,37 +394,41 @@ class Endpoint:
|
|
|
388
394
|
|
|
389
395
|
if parameters_from_path != [param.name for param in endpoint.path_parameters]:
|
|
390
396
|
return ParseError(
|
|
391
|
-
detail=f"Incorrect path templating for {endpoint.path} (Path parameters do not match with path)",
|
|
397
|
+
detail=f"Incorrect path templating for {endpoint.path.get_untrusted_value()} (Path parameters do not match with path)",
|
|
392
398
|
)
|
|
393
399
|
for parameter in endpoint.path_parameters:
|
|
394
|
-
endpoint.path =
|
|
400
|
+
endpoint.path = UntrustedString(
|
|
401
|
+
endpoint.path.get_untrusted_value().replace(
|
|
402
|
+
f"{{{parameter.name.get_untrusted_value()}}}", f"{{{parameter.python_name}}}"
|
|
403
|
+
)
|
|
404
|
+
)
|
|
395
405
|
return endpoint
|
|
396
406
|
|
|
397
407
|
@staticmethod
|
|
398
408
|
def from_data(
|
|
399
409
|
*,
|
|
400
410
|
data: oai.Operation,
|
|
401
|
-
path:
|
|
411
|
+
path: UntrustedString,
|
|
402
412
|
method: str,
|
|
403
413
|
tags: list[PythonIdentifier],
|
|
404
414
|
schemas: Schemas,
|
|
405
415
|
parameters: Parameters,
|
|
406
|
-
request_bodies: dict[
|
|
407
|
-
responses: dict[
|
|
416
|
+
request_bodies: dict[UntrustedString, oai.RequestBody | oai.Reference],
|
|
417
|
+
responses: dict[UntrustedString, oai.Response | oai.Reference],
|
|
408
418
|
config: Config,
|
|
409
419
|
) -> tuple["Endpoint | ParseError", Schemas, Parameters]:
|
|
410
420
|
"""Construct an endpoint from the OpenAPI data"""
|
|
411
421
|
|
|
412
422
|
if data.operationId is None:
|
|
413
|
-
name = generate_operation_id(path=path, method=method)
|
|
423
|
+
name = generate_operation_id(path=path, method=method, prefix=config.field_prefix)
|
|
414
424
|
else:
|
|
415
|
-
name = data.operationId
|
|
425
|
+
name = PythonIdentifier(data.operationId, prefix=config.field_prefix)
|
|
416
426
|
|
|
417
427
|
endpoint = Endpoint(
|
|
418
428
|
path=path,
|
|
419
429
|
method=method,
|
|
420
|
-
summary=
|
|
421
|
-
description=
|
|
430
|
+
summary=data.summary if data.summary else UntrustedString(""),
|
|
431
|
+
description=data.description if data.description else UntrustedString(""),
|
|
422
432
|
name=name,
|
|
423
433
|
requires_security=bool(data.security),
|
|
424
434
|
tags=tags,
|
|
@@ -440,7 +450,7 @@ class Endpoint:
|
|
|
440
450
|
responses=responses,
|
|
441
451
|
config=config,
|
|
442
452
|
)
|
|
443
|
-
if isinstance(result, ParseError):
|
|
453
|
+
if isinstance(result, ParseError): # pragma: no cover
|
|
444
454
|
return result, schemas, parameters
|
|
445
455
|
bodies, schemas = body_from_data(
|
|
446
456
|
data=data, schemas=schemas, config=config, endpoint_name=result.name, request_bodies=request_bodies
|
|
@@ -467,14 +477,14 @@ class Endpoint:
|
|
|
467
477
|
|
|
468
478
|
return result, schemas, parameters
|
|
469
479
|
|
|
470
|
-
def response_type(self) ->
|
|
480
|
+
def response_type(self) -> strings.PythonCode:
|
|
471
481
|
"""Get the Python type of any response from this endpoint"""
|
|
472
|
-
types = sorted({response.prop.get_type_string() for response in self.responses})
|
|
482
|
+
types = sorted({response.prop.get_type_string().as_unembedded_code() for response in self.responses})
|
|
473
483
|
if len(types) == 0:
|
|
474
|
-
return "Any"
|
|
484
|
+
return strings.PythonCode("Any")
|
|
475
485
|
if len(types) == 1:
|
|
476
|
-
return types[0]
|
|
477
|
-
return " | ".join(types)
|
|
486
|
+
return strings.PythonCode(types[0])
|
|
487
|
+
return strings.PythonCode(" | ".join(types))
|
|
478
488
|
|
|
479
489
|
def iter_all_parameters(self) -> Iterator[tuple[oai.ParameterLocation, Property]]:
|
|
480
490
|
"""Iterate through all the parameters of this endpoint"""
|
|
@@ -498,12 +508,12 @@ class Endpoint:
|
|
|
498
508
|
class GeneratorData:
|
|
499
509
|
"""All the data needed to generate a client"""
|
|
500
510
|
|
|
501
|
-
title:
|
|
502
|
-
description:
|
|
503
|
-
version:
|
|
511
|
+
title: UntrustedString
|
|
512
|
+
description: UntrustedString | None
|
|
513
|
+
version: UntrustedString
|
|
504
514
|
models: list[ModelProperty]
|
|
505
515
|
errors: list[ParseError]
|
|
506
|
-
endpoint_collections_by_tag: dict[
|
|
516
|
+
endpoint_collections_by_tag: dict[strings.PythonIdentifier, EndpointCollection]
|
|
507
517
|
enums: list[EnumProperty | LiteralEnumProperty]
|
|
508
518
|
|
|
509
519
|
@staticmethod
|