openapi-python-client 0.25.3__tar.gz → 0.26.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.25.3 → openapi_python_client-0.26.1}/PKG-INFO +3 -3
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/openapi.py +12 -19
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/__init__.py +19 -5
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/union.py +30 -4
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/responses.py +97 -7
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/endpoint_macros.py.jinja +15 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/endpoint_module.py.jinja +19 -15
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/pyproject.toml +3 -3
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/.gitignore +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/LICENSE +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/README.md +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/__init__.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/__main__.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/cli.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/config.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/__init__.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/bodies.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/errors.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/any.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/boolean.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/const.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/date.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/datetime.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/enum_property.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/file.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/float.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/int.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/list_property.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/literal_enum_property.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/merge_properties.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/model_property.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/none.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/property.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/protocol.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/schemas.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/string.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/properties/uuid.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/py.typed +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/3.0.3.md +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/3.1.0.md +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/__init__.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/data_type.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/parameter_location.py +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/.gitignore.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/README.md.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/api_init.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/client.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/errors.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/helpers.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/int_enum.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/literal_enum.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/model.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/models_init.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/package_init.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/const_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/date_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/enum_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/file_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/list_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/union_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/property_templates/uuid_property.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/pyproject.toml.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/pyproject_pdm.toml.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/pyproject_poetry.toml.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/pyproject_ruff.toml.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/pyproject_uv.toml.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/setup.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/str_enum.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/templates/types.py.jinja +0 -0
- {openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openapi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.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>
|
|
@@ -26,9 +26,9 @@ Requires-Dist: jinja2<4.0.0,>=3.0.0
|
|
|
26
26
|
Requires-Dist: pydantic<3.0.0,>=2.10
|
|
27
27
|
Requires-Dist: python-dateutil<3.0.0,>=2.8.1
|
|
28
28
|
Requires-Dist: ruamel-yaml<0.19.0,>=0.18.6
|
|
29
|
-
Requires-Dist: ruff<0.
|
|
29
|
+
Requires-Dist: ruff<0.14,>=0.2
|
|
30
30
|
Requires-Dist: shellingham<2.0.0,>=1.3.2
|
|
31
|
-
Requires-Dist: typer<0.
|
|
31
|
+
Requires-Dist: typer<0.18,>0.6
|
|
32
32
|
Requires-Dist: typing-extensions<5.0.0,>=4.8.0
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
@@ -2,7 +2,6 @@ import re
|
|
|
2
2
|
from collections.abc import Iterator
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from http import HTTPStatus
|
|
6
5
|
from typing import Any, Optional, Protocol, Union
|
|
7
6
|
|
|
8
7
|
from pydantic import ValidationError
|
|
@@ -26,7 +25,7 @@ from .properties import (
|
|
|
26
25
|
property_from_data,
|
|
27
26
|
)
|
|
28
27
|
from .properties.schemas import parameter_from_reference
|
|
29
|
-
from .responses import
|
|
28
|
+
from .responses import HTTPStatusPattern, Responses, response_from_data
|
|
30
29
|
|
|
31
30
|
_PATH_PARAM_REGEX = re.compile("{([a-zA-Z_-][a-zA-Z0-9_-]*)}")
|
|
32
31
|
|
|
@@ -147,7 +146,7 @@ class Endpoint:
|
|
|
147
146
|
path_parameters: list[Property] = field(default_factory=list)
|
|
148
147
|
header_parameters: list[Property] = field(default_factory=list)
|
|
149
148
|
cookie_parameters: list[Property] = field(default_factory=list)
|
|
150
|
-
responses:
|
|
149
|
+
responses: Responses = field(default_factory=lambda: Responses(patterns=[], default=None))
|
|
151
150
|
bodies: list[Body] = field(default_factory=list)
|
|
152
151
|
errors: list[ParseError] = field(default_factory=list)
|
|
153
152
|
|
|
@@ -162,19 +161,9 @@ class Endpoint:
|
|
|
162
161
|
) -> tuple["Endpoint", Schemas]:
|
|
163
162
|
endpoint = deepcopy(endpoint)
|
|
164
163
|
for code, response_data in data.items():
|
|
165
|
-
status_code
|
|
166
|
-
|
|
167
|
-
status_code
|
|
168
|
-
except ValueError:
|
|
169
|
-
endpoint.errors.append(
|
|
170
|
-
ParseError(
|
|
171
|
-
detail=(
|
|
172
|
-
f"Invalid response status code {code} (not a valid HTTP "
|
|
173
|
-
f"status code), response will be omitted from generated "
|
|
174
|
-
f"client"
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
)
|
|
164
|
+
status_code = HTTPStatusPattern.parse(code)
|
|
165
|
+
if isinstance(status_code, ParseError):
|
|
166
|
+
endpoint.errors.append(status_code)
|
|
178
167
|
continue
|
|
179
168
|
|
|
180
169
|
response, schemas = response_from_data(
|
|
@@ -190,7 +179,7 @@ class Endpoint:
|
|
|
190
179
|
endpoint.errors.append(
|
|
191
180
|
ParseError(
|
|
192
181
|
detail=(
|
|
193
|
-
f"Cannot parse response for status code {
|
|
182
|
+
f"Cannot parse response for status code {code}{detail_suffix}, "
|
|
194
183
|
f"response will be omitted from generated client"
|
|
195
184
|
),
|
|
196
185
|
data=response.data,
|
|
@@ -201,7 +190,11 @@ class Endpoint:
|
|
|
201
190
|
# No reasons to use lazy imports in endpoints, so add lazy imports to relative here.
|
|
202
191
|
endpoint.relative_imports |= response.prop.get_lazy_imports(prefix=models_relative_prefix)
|
|
203
192
|
endpoint.relative_imports |= response.prop.get_imports(prefix=models_relative_prefix)
|
|
204
|
-
|
|
193
|
+
if response.is_default():
|
|
194
|
+
endpoint.responses.default = response
|
|
195
|
+
else:
|
|
196
|
+
endpoint.responses.patterns.append(response)
|
|
197
|
+
endpoint.responses.patterns.sort()
|
|
205
198
|
return endpoint, schemas
|
|
206
199
|
|
|
207
200
|
@staticmethod
|
|
@@ -480,7 +473,7 @@ class Endpoint:
|
|
|
480
473
|
if len(types) == 0:
|
|
481
474
|
return "Any"
|
|
482
475
|
if len(types) == 1:
|
|
483
|
-
return
|
|
476
|
+
return types[0]
|
|
484
477
|
return f"Union[{', '.join(types)}]"
|
|
485
478
|
|
|
486
479
|
def iter_all_parameters(self) -> Iterator[tuple[oai.ParameterLocation, Property]]:
|
|
@@ -40,6 +40,7 @@ from .schemas import (
|
|
|
40
40
|
Parameters,
|
|
41
41
|
ReferencePath,
|
|
42
42
|
Schemas,
|
|
43
|
+
get_reference_simple_name,
|
|
43
44
|
parse_reference_path,
|
|
44
45
|
update_parameters_with_data,
|
|
45
46
|
update_schemas_with_data,
|
|
@@ -324,17 +325,30 @@ def _create_schemas(
|
|
|
324
325
|
while still_making_progress:
|
|
325
326
|
still_making_progress = False
|
|
326
327
|
errors = []
|
|
327
|
-
next_round = []
|
|
328
|
+
next_round: list[tuple[str, oai.Reference | oai.Schema]] = []
|
|
328
329
|
# Only accumulate errors from the last round, since we might fix some along the way
|
|
329
330
|
for name, data in to_process:
|
|
330
|
-
|
|
331
|
-
schemas.errors.append(PropertyError(data=data, detail="Reference schemas are not supported."))
|
|
332
|
-
continue
|
|
331
|
+
schema_data: oai.Reference | oai.Schema | None = data
|
|
333
332
|
ref_path = parse_reference_path(f"#/components/schemas/{name}")
|
|
334
333
|
if isinstance(ref_path, ParseError):
|
|
335
334
|
schemas.errors.append(PropertyError(detail=ref_path.detail, data=data))
|
|
336
335
|
continue
|
|
337
|
-
|
|
336
|
+
if isinstance(data, oai.Reference):
|
|
337
|
+
# Fully dereference reference schemas
|
|
338
|
+
seen = [name]
|
|
339
|
+
while isinstance(schema_data, oai.Reference):
|
|
340
|
+
data_ref_schema = get_reference_simple_name(schema_data.ref)
|
|
341
|
+
if data_ref_schema in seen:
|
|
342
|
+
schemas.errors.append(PropertyError(detail="Circular schema references found", data=data))
|
|
343
|
+
break
|
|
344
|
+
# use derefenced schema definition for this schema
|
|
345
|
+
schema_data = components.get(data_ref_schema)
|
|
346
|
+
if isinstance(schema_data, oai.Schema):
|
|
347
|
+
schemas_or_err = update_schemas_with_data(
|
|
348
|
+
ref_path=ref_path, data=schema_data, schemas=schemas, config=config
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
schemas.errors.append(PropertyError(detail="Referent schema not found", data=data))
|
|
338
352
|
if isinstance(schemas_or_err, PropertyError):
|
|
339
353
|
next_round.append((name, data))
|
|
340
354
|
errors.append(schemas_or_err)
|
|
@@ -28,7 +28,14 @@ class UnionProperty(PropertyProtocol):
|
|
|
28
28
|
|
|
29
29
|
@classmethod
|
|
30
30
|
def build(
|
|
31
|
-
cls,
|
|
31
|
+
cls,
|
|
32
|
+
*,
|
|
33
|
+
data: oai.Schema,
|
|
34
|
+
name: str,
|
|
35
|
+
required: bool,
|
|
36
|
+
schemas: Schemas,
|
|
37
|
+
parent_name: str,
|
|
38
|
+
config: Config,
|
|
32
39
|
) -> tuple[UnionProperty | PropertyError, Schemas]:
|
|
33
40
|
"""
|
|
34
41
|
Create a `UnionProperty` the right way.
|
|
@@ -55,8 +62,19 @@ class UnionProperty(PropertyProtocol):
|
|
|
55
62
|
type_list_data.append(data.model_copy(update={"type": _type, "default": None}))
|
|
56
63
|
|
|
57
64
|
for i, sub_prop_data in enumerate(chain(data.anyOf, data.oneOf, type_list_data)):
|
|
65
|
+
# If a schema has a unique title property, we can use that to carry forward a descriptive name instead of "type_0"
|
|
66
|
+
subscript: str
|
|
67
|
+
if (
|
|
68
|
+
isinstance(sub_prop_data, oai.Schema)
|
|
69
|
+
and sub_prop_data.title is not None
|
|
70
|
+
and sub_prop_data.title != data.title
|
|
71
|
+
):
|
|
72
|
+
subscript = sub_prop_data.title
|
|
73
|
+
else:
|
|
74
|
+
subscript = f"type_{i}"
|
|
75
|
+
|
|
58
76
|
sub_prop, schemas = property_from_data(
|
|
59
|
-
name=f"{name}
|
|
77
|
+
name=f"{name}_{subscript}",
|
|
60
78
|
required=True,
|
|
61
79
|
data=sub_prop_data,
|
|
62
80
|
schemas=schemas,
|
|
@@ -64,7 +82,10 @@ class UnionProperty(PropertyProtocol):
|
|
|
64
82
|
config=config,
|
|
65
83
|
)
|
|
66
84
|
if isinstance(sub_prop, PropertyError):
|
|
67
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
PropertyError(detail=f"Invalid property in union {name}", data=sub_prop_data),
|
|
87
|
+
schemas,
|
|
88
|
+
)
|
|
68
89
|
sub_properties.append(sub_prop)
|
|
69
90
|
|
|
70
91
|
def flatten_union_properties(sub_properties: list[PropertyProtocol]) -> list[PropertyProtocol]:
|
|
@@ -108,7 +129,12 @@ class UnionProperty(PropertyProtocol):
|
|
|
108
129
|
|
|
109
130
|
def _get_inner_type_strings(self, json: bool) -> set[str]:
|
|
110
131
|
return {
|
|
111
|
-
p.get_type_string(
|
|
132
|
+
p.get_type_string(
|
|
133
|
+
no_optional=True,
|
|
134
|
+
json=json,
|
|
135
|
+
quoted=not p.is_base_type,
|
|
136
|
+
)
|
|
137
|
+
for p in self.inner_properties
|
|
112
138
|
}
|
|
113
139
|
|
|
114
140
|
@staticmethod
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
__all__ = ["Response", "response_from_data"]
|
|
1
|
+
__all__ = ["HTTPStatusPattern", "Response", "Responses", "response_from_data"]
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import Iterator
|
|
4
4
|
from typing import Optional, TypedDict, Union
|
|
5
5
|
|
|
6
6
|
from attrs import define
|
|
@@ -15,6 +15,20 @@ from .errors import ParseError, PropertyError
|
|
|
15
15
|
from .properties import AnyProperty, Property, Schemas, property_from_data
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
@define
|
|
19
|
+
class Responses:
|
|
20
|
+
patterns: list["Response"]
|
|
21
|
+
default: Optional["Response"]
|
|
22
|
+
|
|
23
|
+
def __iter__(self) -> Iterator["Response"]:
|
|
24
|
+
yield from self.patterns
|
|
25
|
+
if self.default:
|
|
26
|
+
yield self.default
|
|
27
|
+
|
|
28
|
+
def __len__(self) -> int:
|
|
29
|
+
return len(self.patterns) + (1 if self.default else 0)
|
|
30
|
+
|
|
31
|
+
|
|
18
32
|
class _ResponseSource(TypedDict):
|
|
19
33
|
"""What data should be pulled from the httpx Response object"""
|
|
20
34
|
|
|
@@ -28,15 +42,91 @@ TEXT_SOURCE = _ResponseSource(attribute="response.text", return_type="str")
|
|
|
28
42
|
NONE_SOURCE = _ResponseSource(attribute="None", return_type="None")
|
|
29
43
|
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
class HTTPStatusPattern:
|
|
46
|
+
"""Status code patterns come in three flavors, in order of precedence:
|
|
47
|
+
1. Specific status codes, such as 200. This is represented by `min` and `max` being the same.
|
|
48
|
+
2. Ranges of status codes, such as 2XX. This is represented by `min` and `max` being different.
|
|
49
|
+
3. The special `default` status code, which is used when no other status codes match. `range` is `None` in this case.
|
|
50
|
+
|
|
51
|
+
https://github.com/openapi-generators/openapi-python-client/blob/61b6c54994e2a6285bb422ee3b864c45b5d88c15/openapi_python_client/schema/3.1.0.md#responses-object
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
pattern: str
|
|
55
|
+
range: Optional[tuple[int, int]]
|
|
56
|
+
|
|
57
|
+
def __init__(self, *, pattern: str, code_range: Optional[tuple[int, int]]):
|
|
58
|
+
"""Initialize with a range of status codes or None for the default case."""
|
|
59
|
+
self.pattern = pattern
|
|
60
|
+
self.range = code_range
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def parse(pattern: str) -> Union["HTTPStatusPattern", ParseError]:
|
|
64
|
+
"""Parse a status code pattern such as 2XX or 404"""
|
|
65
|
+
if pattern == "default":
|
|
66
|
+
return HTTPStatusPattern(pattern=pattern, code_range=None)
|
|
67
|
+
|
|
68
|
+
if pattern.endswith("XX") and pattern[0].isdigit():
|
|
69
|
+
first_digit = int(pattern[0])
|
|
70
|
+
return HTTPStatusPattern(pattern=pattern, code_range=(first_digit * 100, first_digit * 100 + 99))
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
code = int(pattern)
|
|
74
|
+
return HTTPStatusPattern(pattern=pattern, code_range=(code, code))
|
|
75
|
+
except ValueError:
|
|
76
|
+
return ParseError(
|
|
77
|
+
detail=(
|
|
78
|
+
f"Invalid response status code pattern: {pattern}, response will be omitted from generated client"
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def is_range(self) -> bool:
|
|
83
|
+
"""Check if this is a range of status codes, such as 2XX"""
|
|
84
|
+
return self.range is not None and self.range[0] != self.range[1]
|
|
85
|
+
|
|
86
|
+
def __lt__(self, other: "HTTPStatusPattern") -> bool:
|
|
87
|
+
"""Compare two HTTPStatusPattern objects based on the order they should be applied in"""
|
|
88
|
+
if self.range is None:
|
|
89
|
+
return False # Default gets applied last
|
|
90
|
+
if other.range is None:
|
|
91
|
+
return True # Other is default, so this one gets applied first
|
|
92
|
+
|
|
93
|
+
# Specific codes appear before ranges
|
|
94
|
+
if self.is_range() and not other.is_range():
|
|
95
|
+
return False
|
|
96
|
+
if not self.is_range() and other.is_range():
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
# Order specific codes numerically
|
|
100
|
+
return self.range[0] < other.range[0]
|
|
101
|
+
|
|
102
|
+
def __eq__(self, other: object) -> bool: # pragma: no cover
|
|
103
|
+
if not isinstance(other, HTTPStatusPattern):
|
|
104
|
+
return False
|
|
105
|
+
return self.range == other.range
|
|
106
|
+
|
|
107
|
+
def __hash__(self) -> int: # pragma: no cover
|
|
108
|
+
return hash(self.range)
|
|
109
|
+
|
|
110
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
111
|
+
return f"<HTTPStatusPattern {self.pattern}>"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@define(order=False)
|
|
32
115
|
class Response:
|
|
33
116
|
"""Describes a single response for an endpoint"""
|
|
34
117
|
|
|
35
|
-
status_code:
|
|
118
|
+
status_code: HTTPStatusPattern
|
|
36
119
|
prop: Property
|
|
37
120
|
source: _ResponseSource
|
|
38
121
|
data: Union[oai.Response, oai.Reference] # Original data which created this response, useful for custom templates
|
|
39
122
|
|
|
123
|
+
def is_default(self) -> bool:
|
|
124
|
+
return self.status_code.range is None
|
|
125
|
+
|
|
126
|
+
def __lt__(self, other: "Response") -> bool:
|
|
127
|
+
"""Compare two responses based on the order in which they should be applied in"""
|
|
128
|
+
return self.status_code < other.status_code
|
|
129
|
+
|
|
40
130
|
|
|
41
131
|
def _source_by_content_type(content_type: str, config: Config) -> Optional[_ResponseSource]:
|
|
42
132
|
parsed_content_type = utils.get_content_type(content_type, config)
|
|
@@ -59,7 +149,7 @@ def _source_by_content_type(content_type: str, config: Config) -> Optional[_Resp
|
|
|
59
149
|
|
|
60
150
|
def empty_response(
|
|
61
151
|
*,
|
|
62
|
-
status_code:
|
|
152
|
+
status_code: HTTPStatusPattern,
|
|
63
153
|
response_name: str,
|
|
64
154
|
config: Config,
|
|
65
155
|
data: Union[oai.Response, oai.Reference],
|
|
@@ -82,7 +172,7 @@ def empty_response(
|
|
|
82
172
|
|
|
83
173
|
def response_from_data( # noqa: PLR0911
|
|
84
174
|
*,
|
|
85
|
-
status_code:
|
|
175
|
+
status_code: HTTPStatusPattern,
|
|
86
176
|
data: Union[oai.Response, oai.Reference],
|
|
87
177
|
schemas: Schemas,
|
|
88
178
|
responses: dict[str, Union[oai.Response, oai.Reference]],
|
|
@@ -91,7 +181,7 @@ def response_from_data( # noqa: PLR0911
|
|
|
91
181
|
) -> tuple[Union[Response, ParseError], Schemas]:
|
|
92
182
|
"""Generate a Response from the OpenAPI dictionary representation of it"""
|
|
93
183
|
|
|
94
|
-
response_name = f"response_{status_code}"
|
|
184
|
+
response_name = f"response_{status_code.pattern}"
|
|
95
185
|
if isinstance(data, oai.Reference):
|
|
96
186
|
ref_path = parse_reference_path(data.ref)
|
|
97
187
|
if isinstance(ref_path, ParseError):
|
|
@@ -184,3 +184,18 @@ Returns:
|
|
|
184
184
|
{% macro docstring(endpoint, return_string, is_detailed) %}
|
|
185
185
|
{{ safe_docstring(docstring_content(endpoint, return_string, is_detailed)) }}
|
|
186
186
|
{% endmacro %}
|
|
187
|
+
|
|
188
|
+
{% macro parse_response(parsed_responses, response) %}
|
|
189
|
+
{% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %}
|
|
190
|
+
{% if prop_template.construct %}
|
|
191
|
+
{{ prop_template.construct(response.prop, response.source.attribute) }}
|
|
192
|
+
{% elif response.source.return_type == response.prop.get_type_string() %}
|
|
193
|
+
{{ response.prop.python_name }} = {{ response.source.attribute }}
|
|
194
|
+
{% else %}
|
|
195
|
+
{{ response.prop.python_name }} = cast({{ response.prop.get_type_string() }}, {{ response.source.attribute }})
|
|
196
|
+
{% endif %}
|
|
197
|
+
return {{ response.prop.python_name }}
|
|
198
|
+
{% else %}
|
|
199
|
+
return None
|
|
200
|
+
{% endif %}
|
|
201
|
+
{% endmacro %}
|
|
@@ -64,27 +64,31 @@ def _get_kwargs(
|
|
|
64
64
|
{% endif %}
|
|
65
65
|
return _kwargs
|
|
66
66
|
|
|
67
|
+
{% if endpoint.responses.default %}
|
|
68
|
+
{% set return_type = return_string %}
|
|
69
|
+
{% else %}
|
|
70
|
+
{% set return_type = "Optional[" + return_string + "]" %}
|
|
71
|
+
{% endif %}
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{{
|
|
78
|
-
{% endif %}
|
|
79
|
-
return {{ response.prop.python_name }}
|
|
80
|
-
{% else %}
|
|
81
|
-
return None
|
|
82
|
-
{% endif %}
|
|
73
|
+
|
|
74
|
+
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> {{return_type}}:
|
|
75
|
+
{% for response in endpoint.responses.patterns %}
|
|
76
|
+
{% set code_range = response.status_code.range %}
|
|
77
|
+
{% if code_range[0] == code_range[1] %}
|
|
78
|
+
if response.status_code == {{ code_range[0] }}:
|
|
79
|
+
{% else %}
|
|
80
|
+
if {{ code_range[0] }} <= response.status_code <= {{ code_range[1] }}:
|
|
81
|
+
{% endif %}
|
|
82
|
+
{{ parse_response(parsed_responses, response) | indent(8) }}
|
|
83
83
|
{% endfor %}
|
|
84
|
+
{% if endpoint.responses.default %}
|
|
85
|
+
{{ parse_response(parsed_responses, endpoint.responses.default) | indent(4) }}
|
|
86
|
+
{% else %}
|
|
84
87
|
if client.raise_on_unexpected_status:
|
|
85
88
|
raise errors.UnexpectedStatus(response.status_code, response.content)
|
|
86
89
|
else:
|
|
87
90
|
return None
|
|
91
|
+
{% endif %}
|
|
88
92
|
|
|
89
93
|
|
|
90
94
|
def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]:
|
|
@@ -6,7 +6,7 @@ license = { text = "MIT" }
|
|
|
6
6
|
requires-python = ">=3.9,<4.0"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"jinja2>=3.0.0,<4.0.0",
|
|
9
|
-
"typer>0.6,<0.
|
|
9
|
+
"typer>0.6,<0.18",
|
|
10
10
|
"colorama>=0.4.3; sys_platform == \"win32\"",
|
|
11
11
|
"shellingham>=1.3.2,<2.0.0",
|
|
12
12
|
"pydantic>=2.10,<3.0.0",
|
|
@@ -14,11 +14,11 @@ dependencies = [
|
|
|
14
14
|
"python-dateutil>=2.8.1,<3.0.0",
|
|
15
15
|
"httpx>=0.23.0,<0.29.0",
|
|
16
16
|
"ruamel.yaml>=0.18.6,<0.19.0",
|
|
17
|
-
"ruff>=0.2,<0.
|
|
17
|
+
"ruff>=0.2,<0.14",
|
|
18
18
|
"typing-extensions>=4.8.0,<5.0.0",
|
|
19
19
|
]
|
|
20
20
|
name = "openapi-python-client"
|
|
21
|
-
version = "0.
|
|
21
|
+
version = "0.26.1"
|
|
22
22
|
description = "Generate modern Python clients from OpenAPI"
|
|
23
23
|
keywords = [
|
|
24
24
|
"OpenAPI",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/__init__.py
RENAMED
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/bodies.py
RENAMED
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/parser/errors.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/py.typed
RENAMED
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/3.0.3.md
RENAMED
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/schema/3.1.0.md
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
{openapi_python_client-0.25.3 → openapi_python_client-0.26.1}/openapi_python_client/utils.py
RENAMED
|
File without changes
|