openapi-python-client 0.25.2__tar.gz → 0.26.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/.gitignore +2 -1
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/PKG-INFO +1 -1
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/__init__.py +1 -1
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/config.py +1 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/openapi.py +12 -19
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/union.py +30 -4
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/responses.py +97 -7
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/README.md.jinja +14 -1
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/endpoint_macros.py.jinja +15 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/endpoint_module.py.jinja +19 -15
- openapi_python_client-0.26.0/openapi_python_client/templates/pyproject.toml.jinja +9 -0
- openapi_python_client-0.26.0/openapi_python_client/templates/pyproject_pdm.toml.jinja +19 -0
- openapi_python_client-0.26.0/openapi_python_client/templates/pyproject_poetry.toml.jinja +20 -0
- openapi_python_client-0.26.0/openapi_python_client/templates/pyproject_uv.toml.jinja +23 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/pyproject.toml +1 -1
- openapi_python_client-0.25.2/openapi_python_client/templates/pyproject.toml.jinja +0 -49
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/LICENSE +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/README.md +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/__main__.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/cli.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/__init__.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/bodies.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/errors.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/__init__.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/any.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/boolean.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/const.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/date.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/datetime.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/enum_property.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/file.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/float.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/int.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/list_property.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/literal_enum_property.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/merge_properties.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/model_property.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/none.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/property.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/protocol.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/schemas.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/string.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/properties/uuid.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/py.typed +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/3.0.3.md +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/3.1.0.md +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/__init__.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/data_type.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/parameter_location.py +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/.gitignore.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/api_init.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/client.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/errors.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/helpers.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/int_enum.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/literal_enum.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/model.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/models_init.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/package_init.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/const_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/date_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/enum_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/file_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/list_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/literal_enum_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/union_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/property_templates/uuid_property.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/pyproject_ruff.toml.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/setup.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/str_enum.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/templates/types.py.jinja +0 -0
- {openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/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.0
|
|
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>
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/__init__.py
RENAMED
|
@@ -184,7 +184,7 @@ class Project:
|
|
|
184
184
|
readme = self.project_dir / "README.md"
|
|
185
185
|
readme_template = self.env.get_template("README.md.jinja")
|
|
186
186
|
readme.write_text(
|
|
187
|
-
readme_template.render(
|
|
187
|
+
readme_template.render(meta=self.config.meta_type),
|
|
188
188
|
encoding=self.config.file_encoding,
|
|
189
189
|
)
|
|
190
190
|
|
|
@@ -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]]:
|
|
@@ -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):
|
|
@@ -109,7 +109,7 @@ client = Client(
|
|
|
109
109
|
client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030"))
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
{% if poetry %}
|
|
112
|
+
{% if meta == "poetry" %}
|
|
113
113
|
## Building / publishing this package
|
|
114
114
|
This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics:
|
|
115
115
|
1. Update the metadata in pyproject.toml (e.g. authors, version)
|
|
@@ -123,4 +123,17 @@ If you want to install this client into another project without publishing it (e
|
|
|
123
123
|
1. If that project is not using Poetry:
|
|
124
124
|
1. Build a wheel with `poetry build -f wheel`
|
|
125
125
|
1. Install that wheel from the other project `pip install <path-to-wheel>`
|
|
126
|
+
{% elif meta == 'uv' %}
|
|
127
|
+
## Building / publishing this package
|
|
128
|
+
This project uses [uv](https://github.com/astral-sh/uv) to manage dependencies and packaging. Here are the basics:
|
|
129
|
+
1. Update the metadata in `pyproject.toml` (e.g. authors, version).
|
|
130
|
+
2. If you're using a private repository: https://docs.astral.sh/uv/guides/integration/alternative-indexes/
|
|
131
|
+
3. Build a distribution with `uv build`, builds `sdist` and `wheel` by default.
|
|
132
|
+
1. Publish the client with `uv publish`, see documentation for publishing to private indexes.
|
|
133
|
+
|
|
134
|
+
If you want to install this client into another project without publishing it (e.g. for development) then:
|
|
135
|
+
1. If that project **is using uv**, you can simply do `uv add <path-to-this-client>` from that project
|
|
136
|
+
1. If that project is not using uv:
|
|
137
|
+
1. Build a wheel with `uv build --wheel`.
|
|
138
|
+
1. Install that wheel from the other project `pip install <path-to-wheel>`.
|
|
126
139
|
{% endif %}
|
|
@@ -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 }}]:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{% if meta == "poetry" %}
|
|
2
|
+
{% include "pyproject_poetry.toml.jinja" %}
|
|
3
|
+
{% elif meta == "pdm" %}
|
|
4
|
+
{% include "pyproject_pdm.toml.jinja" %}
|
|
5
|
+
{% elif meta == "uv" %}
|
|
6
|
+
{% include "pyproject_uv.toml.jinja" %}
|
|
7
|
+
{% endif %}
|
|
8
|
+
|
|
9
|
+
{% include "pyproject_ruff.toml.jinja" %}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{ project_name }}"
|
|
3
|
+
version = "{{ package_version }}"
|
|
4
|
+
description = "{{ package_description }}"
|
|
5
|
+
authors = []
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.9,<4.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"httpx>=0.23.0,<0.29.0",
|
|
10
|
+
"attrs>=22.2.0",
|
|
11
|
+
"python-dateutil>=2.8.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[tool.pdm]
|
|
15
|
+
distribution = true
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["pdm-backend"]
|
|
19
|
+
build-backend = "pdm.backend"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "{{ project_name }}"
|
|
3
|
+
version = "{{ package_version }}"
|
|
4
|
+
description = "{{ package_description }}"
|
|
5
|
+
authors = []
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [
|
|
8
|
+
{ include = "{{ package_name }}" },
|
|
9
|
+
]
|
|
10
|
+
include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]
|
|
11
|
+
|
|
12
|
+
[tool.poetry.dependencies]
|
|
13
|
+
python = "^3.9"
|
|
14
|
+
httpx = ">=0.23.0,<0.29.0"
|
|
15
|
+
attrs = ">=22.2.0"
|
|
16
|
+
python-dateutil = "^2.8.0"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
20
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{ project_name }}"
|
|
3
|
+
version = "{{ package_version }}"
|
|
4
|
+
description = "{{ package_description }}"
|
|
5
|
+
authors = []
|
|
6
|
+
requires-python = "~=3.9"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"httpx>=0.23.0,<0.29.0",
|
|
10
|
+
"attrs>=22.2.0",
|
|
11
|
+
"python-dateutil>=2.8.0,<3",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[tool.uv.build-backend]
|
|
15
|
+
module-name = "{{ package_name }}"
|
|
16
|
+
module-root = ""
|
|
17
|
+
data = [
|
|
18
|
+
"CHANGELOG.md",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["uv_build>=0.8.0,<0.9.0"]
|
|
23
|
+
build-backend = "uv_build"
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
{% set poetry = meta == "poetry" %}
|
|
2
|
-
{% set pdm = meta == "pdm" %}
|
|
3
|
-
{% if poetry or pdm %}
|
|
4
|
-
{% if poetry %}[tool.poetry]
|
|
5
|
-
{% elif pdm %}[project]
|
|
6
|
-
{% endif %}
|
|
7
|
-
name = "{{ project_name }}"
|
|
8
|
-
version = "{{ package_version }}"
|
|
9
|
-
description = "{{ package_description }}"
|
|
10
|
-
authors = []
|
|
11
|
-
readme = "README.md"
|
|
12
|
-
{% if pdm %}requires-python = ">=3.9,<4.0"{% endif %}
|
|
13
|
-
{% if poetry %}
|
|
14
|
-
packages = [
|
|
15
|
-
{include = "{{ package_name }}"},
|
|
16
|
-
]
|
|
17
|
-
include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]
|
|
18
|
-
{% endif %}
|
|
19
|
-
|
|
20
|
-
{% if pdm %}
|
|
21
|
-
dependencies = [
|
|
22
|
-
"httpx>=0.23.0,<0.29.0",
|
|
23
|
-
"attrs>=22.2.0",
|
|
24
|
-
"python-dateutil>=2.8.0",
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
[tool.pdm]
|
|
28
|
-
distribution = true
|
|
29
|
-
{% endif %}
|
|
30
|
-
{% if poetry %}
|
|
31
|
-
|
|
32
|
-
[tool.poetry.dependencies]
|
|
33
|
-
python = "^3.9"
|
|
34
|
-
httpx = ">=0.23.0,<0.29.0"
|
|
35
|
-
attrs = ">=22.2.0"
|
|
36
|
-
python-dateutil = "^2.8.0"
|
|
37
|
-
{% endif %}
|
|
38
|
-
|
|
39
|
-
[build-system]
|
|
40
|
-
{% if poetry %}
|
|
41
|
-
requires = ["poetry-core>=1.0.0"]
|
|
42
|
-
build-backend = "poetry.core.masonry.api"
|
|
43
|
-
{% elif pdm %}
|
|
44
|
-
requires = ["pdm-backend"]
|
|
45
|
-
build-backend = "pdm.backend"
|
|
46
|
-
{% endif %}
|
|
47
|
-
{% endif %}{# poetry or pdm #}
|
|
48
|
-
|
|
49
|
-
{% include "pyproject_ruff.toml.jinja" %}
|
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/parser/bodies.py
RENAMED
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/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
|
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/py.typed
RENAMED
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/schema/3.0.3.md
RENAMED
|
File without changes
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/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
|
{openapi_python_client-0.25.2 → openapi_python_client-0.26.0}/openapi_python_client/utils.py
RENAMED
|
File without changes
|