openapi-python-client 0.17.3__tar.gz → 0.18.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.17.3 → openapi_python_client-0.18.0}/PKG-INFO +3 -3
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/openapi.py +83 -66
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/model_property.py +23 -2
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/protocol.py +6 -2
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/endpoint_macros.py.jinja +11 -11
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/endpoint_module.py.jinja +1 -1
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/pyproject.toml.jinja +2 -2
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/pyproject_ruff.toml.jinja +3 -1
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/setup.py.jinja +1 -1
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/utils.py +5 -2
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/pyproject.toml +7 -5
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/.gitignore +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/LICENSE +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/README.md +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/__init__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/__main__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/cli.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/config.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/__init__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/bodies.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/errors.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/__init__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/any.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/boolean.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/const.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/date.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/datetime.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/enum_property.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/file.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/float.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/int.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/list_property.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/none.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/property.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/schemas.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/string.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/properties/union.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/responses.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/py.typed +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/3.0.3.md +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/3.1.0.md +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/__init__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/data_type.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/parameter_location.py +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/.gitignore.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/README.md.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/api_init.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/client.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/errors.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/helpers.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/int_enum.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/model.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/models_init.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/package_init.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/date_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/enum_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/file_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/list_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/property_templates/union_property.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/str_enum.py.jinja +0 -0
- {openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/templates/types.py.jinja +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openapi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.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>
|
|
@@ -21,12 +21,12 @@ Classifier: Typing :: Typed
|
|
|
21
21
|
Requires-Python: <4.0,>=3.8
|
|
22
22
|
Requires-Dist: attrs>=21.3.0
|
|
23
23
|
Requires-Dist: colorama>=0.4.3; sys_platform == 'win32'
|
|
24
|
-
Requires-Dist: httpx<0.
|
|
24
|
+
Requires-Dist: httpx<0.28.0,>=0.20.0
|
|
25
25
|
Requires-Dist: jinja2<4.0.0,>=3.0.0
|
|
26
26
|
Requires-Dist: pydantic<3.0.0,>=2.1.1
|
|
27
27
|
Requires-Dist: python-dateutil<3.0.0,>=2.8.1
|
|
28
28
|
Requires-Dist: pyyaml<7.0,>=6.0
|
|
29
|
-
Requires-Dist: ruff<
|
|
29
|
+
Requires-Dist: ruff<0.3,>=0.2
|
|
30
30
|
Requires-Dist: shellingham<2.0.0,>=1.3.2
|
|
31
31
|
Requires-Dist: typer<0.10,>0.6
|
|
32
32
|
Requires-Dist: typing-extensions<5.0.0,>=4.8.0
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from collections import OrderedDict
|
|
3
2
|
from copy import deepcopy
|
|
4
3
|
from dataclasses import dataclass, field
|
|
5
4
|
from http import HTTPStatus
|
|
@@ -14,7 +13,6 @@ from ..utils import PythonIdentifier
|
|
|
14
13
|
from .bodies import Body, body_from_data
|
|
15
14
|
from .errors import GeneratorError, ParseError, PropertyError
|
|
16
15
|
from .properties import (
|
|
17
|
-
AnyProperty,
|
|
18
16
|
Class,
|
|
19
17
|
EnumProperty,
|
|
20
18
|
ModelProperty,
|
|
@@ -134,14 +132,13 @@ class Endpoint:
|
|
|
134
132
|
tag: str
|
|
135
133
|
summary: Optional[str] = ""
|
|
136
134
|
relative_imports: Set[str] = field(default_factory=set)
|
|
137
|
-
query_parameters:
|
|
138
|
-
path_parameters:
|
|
139
|
-
header_parameters:
|
|
140
|
-
cookie_parameters:
|
|
135
|
+
query_parameters: List[Property] = field(default_factory=list)
|
|
136
|
+
path_parameters: List[Property] = field(default_factory=list)
|
|
137
|
+
header_parameters: List[Property] = field(default_factory=list)
|
|
138
|
+
cookie_parameters: List[Property] = field(default_factory=list)
|
|
141
139
|
responses: List[Response] = field(default_factory=list)
|
|
142
140
|
bodies: List[Body] = field(default_factory=list)
|
|
143
141
|
errors: List[ParseError] = field(default_factory=list)
|
|
144
|
-
used_python_identifiers: Set[PythonIdentifier] = field(default_factory=set)
|
|
145
142
|
|
|
146
143
|
@staticmethod
|
|
147
144
|
def _add_responses(
|
|
@@ -191,7 +188,7 @@ class Endpoint:
|
|
|
191
188
|
return endpoint, schemas
|
|
192
189
|
|
|
193
190
|
@staticmethod
|
|
194
|
-
def add_parameters(
|
|
191
|
+
def add_parameters(
|
|
195
192
|
*,
|
|
196
193
|
endpoint: "Endpoint",
|
|
197
194
|
data: Union[oai.Operation, oai.PathItem],
|
|
@@ -228,22 +225,11 @@ class Endpoint:
|
|
|
228
225
|
endpoint = deepcopy(endpoint)
|
|
229
226
|
|
|
230
227
|
unique_parameters: Set[Tuple[str, oai.ParameterLocation]] = set()
|
|
231
|
-
parameters_by_location: Dict[str,
|
|
228
|
+
parameters_by_location: Dict[str, List[Property]] = {
|
|
232
229
|
oai.ParameterLocation.QUERY: endpoint.query_parameters,
|
|
233
230
|
oai.ParameterLocation.PATH: endpoint.path_parameters,
|
|
234
231
|
oai.ParameterLocation.HEADER: endpoint.header_parameters,
|
|
235
232
|
oai.ParameterLocation.COOKIE: endpoint.cookie_parameters,
|
|
236
|
-
"RESERVED": { # These can't be param names because codegen needs them as vars, the properties don't matter
|
|
237
|
-
"client": AnyProperty(
|
|
238
|
-
"client",
|
|
239
|
-
True,
|
|
240
|
-
None,
|
|
241
|
-
PythonIdentifier("client", ""),
|
|
242
|
-
None,
|
|
243
|
-
None,
|
|
244
|
-
),
|
|
245
|
-
"url": AnyProperty("url", True, None, PythonIdentifier("url", ""), None, None),
|
|
246
|
-
},
|
|
247
233
|
}
|
|
248
234
|
|
|
249
235
|
for param in data.parameters:
|
|
@@ -273,6 +259,12 @@ class Endpoint:
|
|
|
273
259
|
|
|
274
260
|
unique_parameters.add(unique_param)
|
|
275
261
|
|
|
262
|
+
if any(
|
|
263
|
+
other_param for other_param in parameters_by_location[param.param_in] if other_param.name == param.name
|
|
264
|
+
):
|
|
265
|
+
# Defined at the operation level, ignore it here
|
|
266
|
+
continue
|
|
267
|
+
|
|
276
268
|
prop, new_schemas = property_from_data(
|
|
277
269
|
name=param.name,
|
|
278
270
|
required=param.required,
|
|
@@ -299,47 +291,69 @@ class Endpoint:
|
|
|
299
291
|
location_error.data = param
|
|
300
292
|
return location_error, schemas, parameters
|
|
301
293
|
|
|
302
|
-
|
|
303
|
-
|
|
294
|
+
# No reasons to use lazy imports in endpoints, so add lazy imports to relative here.
|
|
295
|
+
endpoint.relative_imports.update(prop.get_lazy_imports(prefix=models_relative_prefix))
|
|
296
|
+
endpoint.relative_imports.update(prop.get_imports(prefix=models_relative_prefix))
|
|
297
|
+
parameters_by_location[param.param_in].append(prop)
|
|
298
|
+
|
|
299
|
+
return endpoint._check_parameters_for_conflicts(config=config), schemas, parameters
|
|
300
|
+
|
|
301
|
+
def _check_parameters_for_conflicts(
|
|
302
|
+
self,
|
|
303
|
+
*,
|
|
304
|
+
config: Config,
|
|
305
|
+
previously_modified_params: Optional[Set[Tuple[oai.ParameterLocation, str]]] = None,
|
|
306
|
+
) -> Union["Endpoint", ParseError]:
|
|
307
|
+
"""Check for conflicting parameters
|
|
308
|
+
|
|
309
|
+
For parameters that have the same python_name but are in different locations, append the location to the
|
|
310
|
+
python_name. For parameters that have the same name but are in the same location, use their raw name without
|
|
311
|
+
snake casing instead.
|
|
312
|
+
|
|
313
|
+
Function stops when there's a conflict that can't be resolved or all parameters are guaranteed to have a
|
|
314
|
+
unique python_name.
|
|
315
|
+
"""
|
|
316
|
+
modified_params = previously_modified_params or set()
|
|
317
|
+
used_python_names: Dict[PythonIdentifier, Tuple[oai.ParameterLocation, Property]] = {}
|
|
318
|
+
reserved_names = ["client", "url"]
|
|
319
|
+
for parameter in self.iter_all_parameters():
|
|
320
|
+
location, prop = parameter
|
|
321
|
+
|
|
322
|
+
if prop.python_name in reserved_names:
|
|
323
|
+
prop.set_python_name(new_name=f"{prop.python_name}_{location}", config=config)
|
|
324
|
+
modified_params.add((location, prop.name))
|
|
304
325
|
continue
|
|
305
326
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
data=data,
|
|
319
|
-
),
|
|
320
|
-
schemas,
|
|
321
|
-
parameters,
|
|
322
|
-
)
|
|
323
|
-
endpoint.used_python_identifiers.add(existing_prop.python_name)
|
|
324
|
-
prop.set_python_name(new_name=f"{param.name}_{param.param_in}", config=config)
|
|
327
|
+
conflicting = used_python_names.pop(prop.python_name, None)
|
|
328
|
+
if conflicting is None:
|
|
329
|
+
used_python_names[prop.python_name] = parameter
|
|
330
|
+
continue
|
|
331
|
+
conflicting_location, conflicting_prop = conflicting
|
|
332
|
+
if (conflicting_location, conflicting_prop.name) in modified_params or (
|
|
333
|
+
location,
|
|
334
|
+
prop.name,
|
|
335
|
+
) in modified_params:
|
|
336
|
+
return ParseError(
|
|
337
|
+
detail=f"Parameters with same Python identifier {conflicting_prop.python_name} detected",
|
|
338
|
+
)
|
|
325
339
|
|
|
326
|
-
if
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
detail=f"Parameters with same Python identifier `{prop.python_name}` detected",
|
|
330
|
-
data=data,
|
|
331
|
-
),
|
|
332
|
-
schemas,
|
|
333
|
-
parameters,
|
|
340
|
+
if location != conflicting_location:
|
|
341
|
+
conflicting_prop.set_python_name(
|
|
342
|
+
new_name=f"{conflicting_prop.python_name}_{conflicting_location}", config=config
|
|
334
343
|
)
|
|
344
|
+
prop.set_python_name(new_name=f"{prop.python_name}_{location}", config=config)
|
|
345
|
+
elif conflicting_prop.name != prop.name: # Use the name to differentiate
|
|
346
|
+
conflicting_prop.set_python_name(new_name=conflicting_prop.name, config=config, skip_snake_case=True)
|
|
347
|
+
prop.set_python_name(new_name=prop.name, config=config, skip_snake_case=True)
|
|
335
348
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
parameters_by_location[param.param_in][prop.name] = prop
|
|
349
|
+
modified_params.add((location, conflicting_prop.name))
|
|
350
|
+
modified_params.add((conflicting_location, conflicting_prop.name))
|
|
351
|
+
used_python_names[prop.python_name] = parameter
|
|
352
|
+
used_python_names[conflicting_prop.python_name] = conflicting
|
|
341
353
|
|
|
342
|
-
|
|
354
|
+
if len(modified_params) > 0 and modified_params != previously_modified_params:
|
|
355
|
+
return self._check_parameters_for_conflicts(config=config, previously_modified_params=modified_params)
|
|
356
|
+
return self
|
|
343
357
|
|
|
344
358
|
@staticmethod
|
|
345
359
|
def sort_parameters(*, endpoint: "Endpoint") -> Union["Endpoint", ParseError]:
|
|
@@ -356,15 +370,13 @@ class Endpoint:
|
|
|
356
370
|
endpoint = deepcopy(endpoint)
|
|
357
371
|
parameters_from_path = re.findall(_PATH_PARAM_REGEX, endpoint.path)
|
|
358
372
|
try:
|
|
359
|
-
|
|
360
|
-
endpoint.path_parameters.values(),
|
|
373
|
+
endpoint.path_parameters.sort(
|
|
361
374
|
key=lambda param: parameters_from_path.index(param.name),
|
|
362
375
|
)
|
|
363
|
-
endpoint.path_parameters = OrderedDict((param.name, param) for param in sorted_params)
|
|
364
376
|
except ValueError:
|
|
365
377
|
pass # We're going to catch the difference down below
|
|
366
378
|
|
|
367
|
-
if parameters_from_path !=
|
|
379
|
+
if parameters_from_path != [param.name for param in endpoint.path_parameters]:
|
|
368
380
|
return ParseError(
|
|
369
381
|
detail=f"Incorrect path templating for {endpoint.path} (Path parameters do not match with path)",
|
|
370
382
|
)
|
|
@@ -442,17 +454,22 @@ class Endpoint:
|
|
|
442
454
|
return self.responses[0].prop.get_type_string(quoted=False)
|
|
443
455
|
return f"Union[{', '.join(types)}]"
|
|
444
456
|
|
|
445
|
-
def iter_all_parameters(self) -> Iterator[Property]:
|
|
457
|
+
def iter_all_parameters(self) -> Iterator[Tuple[oai.ParameterLocation, Property]]:
|
|
446
458
|
"""Iterate through all the parameters of this endpoint"""
|
|
447
|
-
yield from self.path_parameters
|
|
448
|
-
yield from self.query_parameters
|
|
449
|
-
yield from self.header_parameters
|
|
450
|
-
yield from self.cookie_parameters
|
|
451
|
-
yield from (body.prop for body in self.bodies)
|
|
459
|
+
yield from ((oai.ParameterLocation.PATH, param) for param in self.path_parameters)
|
|
460
|
+
yield from ((oai.ParameterLocation.QUERY, param) for param in self.query_parameters)
|
|
461
|
+
yield from ((oai.ParameterLocation.HEADER, param) for param in self.header_parameters)
|
|
462
|
+
yield from ((oai.ParameterLocation.COOKIE, param) for param in self.cookie_parameters)
|
|
452
463
|
|
|
453
464
|
def list_all_parameters(self) -> List[Property]:
|
|
454
465
|
"""Return a List of all the parameters of this endpoint"""
|
|
455
|
-
return
|
|
466
|
+
return (
|
|
467
|
+
self.path_parameters
|
|
468
|
+
+ self.query_parameters
|
|
469
|
+
+ self.header_parameters
|
|
470
|
+
+ self.cookie_parameters
|
|
471
|
+
+ [body.prop for body in self.bodies]
|
|
472
|
+
)
|
|
456
473
|
|
|
457
474
|
|
|
458
475
|
@dataclass
|
|
@@ -267,6 +267,17 @@ def _merge_properties(first: Property, second: Property) -> Property | PropertyE
|
|
|
267
267
|
)
|
|
268
268
|
|
|
269
269
|
|
|
270
|
+
def _resolve_naming_conflict(first: Property, second: Property, config: Config) -> PropertyError | None:
|
|
271
|
+
first.set_python_name(first.name, config=config, skip_snake_case=True)
|
|
272
|
+
second.set_python_name(second.name, config=config, skip_snake_case=True)
|
|
273
|
+
if first.python_name == second.python_name:
|
|
274
|
+
return PropertyError(
|
|
275
|
+
header="Conflicting property names",
|
|
276
|
+
detail=f"Properties {first.name} and {second.name} have the same python_name",
|
|
277
|
+
)
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
|
|
270
281
|
class _PropertyData(NamedTuple):
|
|
271
282
|
optional_props: list[Property]
|
|
272
283
|
required_props: list[Property]
|
|
@@ -293,13 +304,23 @@ def _process_properties( # noqa: PLR0912, PLR0911
|
|
|
293
304
|
def _add_if_no_conflict(new_prop: Property) -> PropertyError | None:
|
|
294
305
|
nonlocal properties
|
|
295
306
|
|
|
296
|
-
|
|
297
|
-
merged_prop_or_error = _merge_properties(
|
|
307
|
+
name_conflict = properties.get(new_prop.name)
|
|
308
|
+
merged_prop_or_error = _merge_properties(name_conflict, new_prop) if name_conflict else new_prop
|
|
298
309
|
if isinstance(merged_prop_or_error, PropertyError):
|
|
299
310
|
merged_prop_or_error.header = (
|
|
300
311
|
f"Found conflicting properties named {new_prop.name} when creating {class_name}"
|
|
301
312
|
)
|
|
302
313
|
return merged_prop_or_error
|
|
314
|
+
|
|
315
|
+
for other_prop in properties.values():
|
|
316
|
+
if other_prop.name == merged_prop_or_error.name:
|
|
317
|
+
continue # Same property, probably just got merged
|
|
318
|
+
if other_prop.python_name != merged_prop_or_error.python_name:
|
|
319
|
+
continue
|
|
320
|
+
naming_error = _resolve_naming_conflict(merged_prop_or_error, other_prop, config)
|
|
321
|
+
if naming_error is not None:
|
|
322
|
+
return naming_error
|
|
323
|
+
|
|
303
324
|
properties[merged_prop_or_error.name] = merged_prop_or_error
|
|
304
325
|
return None
|
|
305
326
|
|
|
@@ -67,14 +67,18 @@ class PropertyProtocol(Protocol):
|
|
|
67
67
|
return ParseError(detail="Path parameter must be required")
|
|
68
68
|
return None
|
|
69
69
|
|
|
70
|
-
def set_python_name(self, new_name: str, config: Config) -> None:
|
|
70
|
+
def set_python_name(self, new_name: str, config: Config, skip_snake_case: bool = False) -> None:
|
|
71
71
|
"""Mutates this Property to set a new python_name.
|
|
72
72
|
|
|
73
73
|
Required to mutate due to how Properties are stored and the difficulty of updating them in-dict.
|
|
74
74
|
`new_name` will be validated before it is set, so `python_name` is not guaranteed to equal `new_name` after
|
|
75
75
|
calling this.
|
|
76
76
|
"""
|
|
77
|
-
object.__setattr__(
|
|
77
|
+
object.__setattr__(
|
|
78
|
+
self,
|
|
79
|
+
"python_name",
|
|
80
|
+
PythonIdentifier(value=new_name, prefix=config.field_prefix, skip_snake_case=skip_snake_case),
|
|
81
|
+
)
|
|
78
82
|
|
|
79
83
|
def get_base_type_string(self, *, quoted: bool = False) -> str:
|
|
80
84
|
"""Get the string describing the Python type of this property. Base types no require quoting."""
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{% if endpoint.header_parameters or endpoint.bodies | length > 0 %}
|
|
6
6
|
headers: Dict[str, Any] = {}
|
|
7
7
|
{% if endpoint.header_parameters %}
|
|
8
|
-
{% for parameter in endpoint.header_parameters
|
|
8
|
+
{% for parameter in endpoint.header_parameters %}
|
|
9
9
|
{% import "property_templates/" + parameter.template as param_template %}
|
|
10
10
|
{% if param_template.transform_header %}
|
|
11
11
|
{% set expression = param_template.transform_header(parameter.python_name) %}
|
|
@@ -22,7 +22,7 @@ headers: Dict[str, Any] = {}
|
|
|
22
22
|
{% macro cookie_params(endpoint) %}
|
|
23
23
|
{% if endpoint.cookie_parameters %}
|
|
24
24
|
cookies = {}
|
|
25
|
-
{% for parameter in endpoint.cookie_parameters
|
|
25
|
+
{% for parameter in endpoint.cookie_parameters %}
|
|
26
26
|
{% if parameter.required %}
|
|
27
27
|
cookies["{{ parameter.name}}"] = {{ parameter.python_name }}
|
|
28
28
|
{% else %}
|
|
@@ -39,7 +39,7 @@ if {{ parameter.python_name }} is not UNSET:
|
|
|
39
39
|
{% if endpoint.query_parameters %}
|
|
40
40
|
params: Dict[str, Any] = {}
|
|
41
41
|
|
|
42
|
-
{% for property in endpoint.query_parameters
|
|
42
|
+
{% for property in endpoint.query_parameters %}
|
|
43
43
|
{% set destination = property.python_name %}
|
|
44
44
|
{% import "property_templates/" + property.template as prop_template %}
|
|
45
45
|
{% if prop_template.transform %}
|
|
@@ -91,7 +91,7 @@ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
|
|
|
91
91
|
{# The all the kwargs passed into an endpoint (and variants thereof)) #}
|
|
92
92
|
{% macro arguments(endpoint, include_client=True) %}
|
|
93
93
|
{# path parameters #}
|
|
94
|
-
{% for parameter in endpoint.path_parameters
|
|
94
|
+
{% for parameter in endpoint.path_parameters %}
|
|
95
95
|
{{ parameter.to_string() }},
|
|
96
96
|
{% endfor %}
|
|
97
97
|
{% if include_client or ((endpoint.list_all_parameters() | length) > (endpoint.path_parameters | length)) %}
|
|
@@ -116,21 +116,21 @@ body: Union[
|
|
|
116
116
|
],
|
|
117
117
|
{% endif %}
|
|
118
118
|
{# query parameters #}
|
|
119
|
-
{% for parameter in endpoint.query_parameters
|
|
119
|
+
{% for parameter in endpoint.query_parameters %}
|
|
120
120
|
{{ parameter.to_string() }},
|
|
121
121
|
{% endfor %}
|
|
122
|
-
{% for parameter in endpoint.header_parameters
|
|
122
|
+
{% for parameter in endpoint.header_parameters %}
|
|
123
123
|
{{ parameter.to_string() }},
|
|
124
124
|
{% endfor %}
|
|
125
125
|
{# cookie parameters #}
|
|
126
|
-
{% for parameter in endpoint.cookie_parameters
|
|
126
|
+
{% for parameter in endpoint.cookie_parameters %}
|
|
127
127
|
{{ parameter.to_string() }},
|
|
128
128
|
{% endfor %}
|
|
129
129
|
{% endmacro %}
|
|
130
130
|
|
|
131
131
|
{# Just lists all kwargs to endpoints as name=name for passing to other functions #}
|
|
132
132
|
{% macro kwargs(endpoint, include_client=True) %}
|
|
133
|
-
{% for parameter in endpoint.path_parameters
|
|
133
|
+
{% for parameter in endpoint.path_parameters %}
|
|
134
134
|
{{ parameter.python_name }}={{ parameter.python_name }},
|
|
135
135
|
{% endfor %}
|
|
136
136
|
{% if include_client %}
|
|
@@ -139,13 +139,13 @@ client=client,
|
|
|
139
139
|
{% if endpoint.bodies | length > 0 %}
|
|
140
140
|
body=body,
|
|
141
141
|
{% endif %}
|
|
142
|
-
{% for parameter in endpoint.query_parameters
|
|
142
|
+
{% for parameter in endpoint.query_parameters %}
|
|
143
143
|
{{ parameter.python_name }}={{ parameter.python_name }},
|
|
144
144
|
{% endfor %}
|
|
145
|
-
{% for parameter in endpoint.header_parameters
|
|
145
|
+
{% for parameter in endpoint.header_parameters %}
|
|
146
146
|
{{ parameter.python_name }}={{ parameter.python_name }},
|
|
147
147
|
{% endfor %}
|
|
148
|
-
{% for parameter in endpoint.cookie_parameters
|
|
148
|
+
{% for parameter in endpoint.cookie_parameters %}
|
|
149
149
|
{{ parameter.python_name }}={{ parameter.python_name }},
|
|
150
150
|
{% endfor %}
|
|
151
151
|
{% endmacro %}
|
|
@@ -30,7 +30,7 @@ def _get_kwargs(
|
|
|
30
30
|
"method": "{{ endpoint.method }}",
|
|
31
31
|
{% if endpoint.path_parameters %}
|
|
32
32
|
"url": "{{ endpoint.path }}".format(
|
|
33
|
-
{%- for parameter in endpoint.path_parameters
|
|
33
|
+
{%- for parameter in endpoint.path_parameters -%}
|
|
34
34
|
{{parameter.name}}={{parameter.python_name}},
|
|
35
35
|
{%- endfor -%}
|
|
36
36
|
),
|
|
@@ -19,7 +19,7 @@ include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]
|
|
|
19
19
|
|
|
20
20
|
{% if pdm %}
|
|
21
21
|
dependencies = [
|
|
22
|
-
"httpx>=0.20.0,<0.
|
|
22
|
+
"httpx>=0.20.0,<0.28.0",
|
|
23
23
|
"attrs>=21.3.0",
|
|
24
24
|
"python-dateutil>=2.8.0",
|
|
25
25
|
]
|
|
@@ -31,7 +31,7 @@ package-type = "library"
|
|
|
31
31
|
|
|
32
32
|
[tool.poetry.dependencies]
|
|
33
33
|
python = "^3.8"
|
|
34
|
-
httpx = ">=0.20.0,<0.
|
|
34
|
+
httpx = ">=0.20.0,<0.28.0"
|
|
35
35
|
attrs = ">=21.3.0"
|
|
36
36
|
python-dateutil = "^2.8.0"
|
|
37
37
|
{% endif %}
|
|
@@ -13,6 +13,6 @@ setup(
|
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
packages=find_packages(),
|
|
15
15
|
python_requires=">=3.8, <4",
|
|
16
|
-
install_requires=["httpx >= 0.20.0, < 0.
|
|
16
|
+
install_requires=["httpx >= 0.20.0, < 0.28.0", "attrs >= 21.3.0", "python-dateutil >= 2.8.0, < 3"],
|
|
17
17
|
package_data={"{{ package_name }}": ["py.typed"]},
|
|
18
18
|
)
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/utils.py
RENAMED
|
@@ -12,8 +12,11 @@ DELIMITERS = r"\. _-"
|
|
|
12
12
|
class PythonIdentifier(str):
|
|
13
13
|
"""A snake_case string which has been validated / transformed into a valid identifier for Python"""
|
|
14
14
|
|
|
15
|
-
def __new__(cls, value: str, prefix: str) -> PythonIdentifier:
|
|
16
|
-
new_value =
|
|
15
|
+
def __new__(cls, value: str, prefix: str, skip_snake_case: bool = False) -> PythonIdentifier:
|
|
16
|
+
new_value = sanitize(value)
|
|
17
|
+
if not skip_snake_case:
|
|
18
|
+
new_value = snake_case(new_value)
|
|
19
|
+
new_value = fix_reserved_words(new_value)
|
|
17
20
|
|
|
18
21
|
if not new_value.isidentifier() or value.startswith("_"):
|
|
19
22
|
new_value = f"{prefix}{new_value}"
|
|
@@ -12,13 +12,13 @@ dependencies = [
|
|
|
12
12
|
"pydantic>=2.1.1,<3.0.0",
|
|
13
13
|
"attrs>=21.3.0",
|
|
14
14
|
"python-dateutil>=2.8.1,<3.0.0",
|
|
15
|
-
"httpx>=0.20.0,<0.
|
|
15
|
+
"httpx>=0.20.0,<0.28.0",
|
|
16
16
|
"PyYAML>=6.0,<7.0",
|
|
17
|
-
"ruff>=0.
|
|
17
|
+
"ruff>=0.2,<0.3",
|
|
18
18
|
"typing-extensions>=4.8.0,<5.0.0",
|
|
19
19
|
]
|
|
20
20
|
name = "openapi-python-client"
|
|
21
|
-
version = "0.
|
|
21
|
+
version = "0.18.0"
|
|
22
22
|
description = "Generate modern Python clients from OpenAPI"
|
|
23
23
|
keywords = [
|
|
24
24
|
"OpenAPI",
|
|
@@ -47,7 +47,6 @@ repository = "https://github.com/openapi-generators/openapi-python-client"
|
|
|
47
47
|
openapi-python-client = "openapi_python_client.cli:app"
|
|
48
48
|
|
|
49
49
|
[tool.ruff]
|
|
50
|
-
select = ["E", "F", "I", "UP", "B", "PL", "RUF"]
|
|
51
50
|
line-length = 120
|
|
52
51
|
exclude = [
|
|
53
52
|
".git",
|
|
@@ -57,9 +56,12 @@ exclude = [
|
|
|
57
56
|
"end_to_end_tests/*",
|
|
58
57
|
"tests/test_templates/*",
|
|
59
58
|
]
|
|
59
|
+
|
|
60
|
+
[tool.ruff.lint]
|
|
61
|
+
select = ["E", "F", "I", "UP", "B", "PL", "RUF"]
|
|
60
62
|
ignore = ["E501", "PLR0913"]
|
|
61
63
|
|
|
62
|
-
[tool.ruff.per-file-ignores]
|
|
64
|
+
[tool.ruff.lint.per-file-ignores]
|
|
63
65
|
"openapi_python_client/cli.py" = ["B008"]
|
|
64
66
|
|
|
65
67
|
[tool.coverage.run]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/__init__.py
RENAMED
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/parser/bodies.py
RENAMED
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.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
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/py.typed
RENAMED
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.0}/openapi_python_client/schema/3.0.3.md
RENAMED
|
File without changes
|
{openapi_python_client-0.17.3 → openapi_python_client-0.18.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
|