openapi-python-client 0.15.1__tar.gz → 0.16.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.15.1 → openapi_python_client-0.16.0}/CHANGELOG.md +42 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/PKG-INFO +13 -11
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/README.md +8 -6
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/__init__.py +3 -4
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/cli.py +2 -3
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/config.py +2 -3
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/openapi.py +121 -68
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/__init__.py +2 -7
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/enum_property.py +0 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/model_property.py +42 -45
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/property.py +1 -2
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/schemas.py +1 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/responses.py +54 -15
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +1 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +1 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +1 -2
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +2 -2
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +1 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_macros.py.jinja +13 -2
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_module.py.jinja +7 -3
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/pyproject.toml.jinja +1 -1
- openapi_python_client-0.16.0/openapi_python_client/templates/pyproject_no_poetry.toml.jinja +3 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/setup.py.jinja +1 -1
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/utils.py +18 -10
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/pyproject.toml +19 -50
- openapi_python_client-0.15.1/openapi_python_client/templates/pyproject_no_poetry.toml.jinja +0 -16
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/LICENSE +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/__main__.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/__init__.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/errors.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/converter.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/py.typed +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/__init__.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/data_type.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/schema/parameter_location.py +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/.gitignore.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/README.md.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/api_init.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/client.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/errors.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/helpers.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/int_enum.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/model.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/models_init.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/package_init.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/date_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/enum_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/file_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/list_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/union_property.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/str_enum.py.jinja +0 -0
- {openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/templates/types.py.jinja +0 -0
|
@@ -13,6 +13,48 @@ Programmatic usage of this project (e.g., importing it as a Python module) and t
|
|
|
13
13
|
|
|
14
14
|
The 0.x prefix used in versions for this project is to indicate that breaking changes are expected frequently (several times a year). Breaking changes will increment the minor number, all other changes will increment the patch number. You can track the progress toward 1.0 [here](https://github.com/openapi-generators/openapi-python-client/projects/2).
|
|
15
15
|
|
|
16
|
+
## 0.16.0 (2023-12-07)
|
|
17
|
+
|
|
18
|
+
### Breaking Changes
|
|
19
|
+
|
|
20
|
+
#### Switch from Black to Ruff for formatting
|
|
21
|
+
|
|
22
|
+
`black` is no longer a runtime dependency, so if you have them set in custom `post_hooks` in a config file, you'll need to make sure they're being installed manually. [`ruff`](https://docs.astral.sh/ruff) is now installed and used by default instead.
|
|
23
|
+
|
|
24
|
+
#### Use Ruff instead of isort + autoflake at runtime
|
|
25
|
+
|
|
26
|
+
`isort` and `autoflake` are no longer runtime dependencies, so if you have them set in custom `post_hooks` in a config file, you'll need to make sure they're being installed manually. [`ruff`](https://docs.astral.sh/ruff) is now installed and used by default instead.
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
#### Support all `text/*` content types in responses
|
|
31
|
+
|
|
32
|
+
Within an API response, any content type which starts with `text/` will now be treated the same as `text/html` already was—they will return the `response.text` attribute from the [httpx Response](https://www.python-httpx.org/api/#response).
|
|
33
|
+
|
|
34
|
+
Thanks to @fdintino for the initial implementation, and thanks for the discussions from @kairntech, @rubenfiszel, and @antoneladestito.
|
|
35
|
+
|
|
36
|
+
Closes #797 and #821.
|
|
37
|
+
|
|
38
|
+
#### Support `application/octet-stream` request bodies
|
|
39
|
+
|
|
40
|
+
Endpoints that accept `application/octet-stream` request bodies are now supported using the same `File` type as octet-stream responses.
|
|
41
|
+
|
|
42
|
+
Thanks to @kgutwin for the implementation and @rtaycher for the discussion!
|
|
43
|
+
|
|
44
|
+
PR #899 closes #588
|
|
45
|
+
|
|
46
|
+
### Fixes
|
|
47
|
+
|
|
48
|
+
#### Remove useless `pass` statements from generated code
|
|
49
|
+
|
|
50
|
+
## 0.15.2 (2023-09-16)
|
|
51
|
+
|
|
52
|
+
### Features
|
|
53
|
+
|
|
54
|
+
#### support httpx 0.25 (#854)
|
|
55
|
+
|
|
56
|
+
#### Support content-type with attributes (#655, #809, #858). Thanks @sherbang!
|
|
57
|
+
|
|
16
58
|
## 0.15.1 (2023-08-12)
|
|
17
59
|
|
|
18
60
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openapi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: Generate modern Python clients from OpenAPI
|
|
5
5
|
Home-page: https://github.com/triaxtec/openapi-python-client
|
|
6
6
|
License: MIT
|
|
@@ -16,20 +16,20 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
20
|
Classifier: Topic :: Software Development :: Code Generators
|
|
20
21
|
Classifier: Typing :: Typed
|
|
21
22
|
Requires-Dist: PyYAML (>=6.0,<7.0)
|
|
22
23
|
Requires-Dist: attrs (>=21.3.0)
|
|
23
|
-
Requires-Dist: autoflake (>=1.4,<3.0.0)
|
|
24
|
-
Requires-Dist: black (>=23)
|
|
25
24
|
Requires-Dist: colorama (>=0.4.3,<0.5.0) ; sys_platform == "win32"
|
|
26
|
-
Requires-Dist: httpx (>=0.20.0,<0.
|
|
27
|
-
Requires-Dist: isort (>=5.0.5,<6.0.0)
|
|
25
|
+
Requires-Dist: httpx (>=0.20.0,<0.26.0)
|
|
28
26
|
Requires-Dist: jinja2 (>=3.0.0,<4.0.0)
|
|
29
27
|
Requires-Dist: pydantic (>=2.1.1,<3.0.0)
|
|
30
28
|
Requires-Dist: python-dateutil (>=2.8.1,<3.0.0)
|
|
29
|
+
Requires-Dist: ruff (>=0.1.2,<0.2.0)
|
|
31
30
|
Requires-Dist: shellingham (>=1.3.2,<2.0.0)
|
|
32
31
|
Requires-Dist: typer (>0.6,<0.10)
|
|
32
|
+
Requires-Dist: typing-extensions (>=4.8.0,<5.0.0)
|
|
33
33
|
Project-URL: Repository, https://github.com/triaxtec/openapi-python-client
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
|
|
@@ -37,7 +37,6 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
[](https://codecov.io/gh/triaxtec/openapi-python-client)
|
|
38
38
|
[](https://lbesson.mit-license.org/)
|
|
39
39
|
[](https://mypy.readthedocs.io/en/stable/introduction.html)
|
|
40
|
-
[](https://github.com/ambv/black)
|
|
41
40
|
[](https://pypi.python.org/pypi/openapi-python-client/)
|
|
42
41
|
[](https://pepy.tech/project/openapi-python-client)
|
|
43
42
|
|
|
@@ -56,13 +55,17 @@ This tool focuses on creating the best developer experience for Python developer
|
|
|
56
55
|
|
|
57
56
|
1. Using all the latest and greatest Python features like type annotations and dataclasses.
|
|
58
57
|
2. Having documentation and usage instructions specific to this one generator.
|
|
59
|
-
|
|
58
|
+
3. Being written in Python with Jinja2 templates, making it easier to improve and extend for Python developers. It's also much easier to install and use if you already have Python.
|
|
59
|
+
|
|
60
|
+
## Sponsors
|
|
61
|
+
|
|
62
|
+
<a href="https://www.devmark.ai/fern/?utm_source=openapi-python-client&utm_loc=readme&utm_type=logo" target="_blank" title="Fern | SDKs and API docs"><img src="https://raw.githubusercontent.com/openapi-generators/openapi-python-client/main/.github/sponsors/fern.png"></a>
|
|
60
63
|
|
|
61
64
|
## Installation
|
|
62
65
|
|
|
63
66
|
I recommend you install with [pipx](https://pipxproject.github.io/pipx/) so you don't conflict with any other packages you might have: `pipx install openapi-python-client --include-deps`.
|
|
64
67
|
|
|
65
|
-
> Note the `--include-deps` option which will also make `black
|
|
68
|
+
> Note the `--include-deps` option which will also make `black` and `ruff` available in your path so that `openapi-python-client` can use them to clean up the generated code.
|
|
66
69
|
|
|
67
70
|
**If you use `pipx run` then the post-generation hooks will not be available unless you install them manually.**
|
|
68
71
|
|
|
@@ -186,9 +189,8 @@ In the config file, there's an easy way to tell `openapi-python-client` to run a
|
|
|
186
189
|
|
|
187
190
|
```yaml
|
|
188
191
|
post_hooks:
|
|
189
|
-
- "
|
|
190
|
-
- "
|
|
191
|
-
- "black ."
|
|
192
|
+
- "ruff check . --fix"
|
|
193
|
+
- "ruff format ."
|
|
192
194
|
```
|
|
193
195
|
|
|
194
196
|
### use_path_prefixes_for_title_model_names
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
[](https://codecov.io/gh/triaxtec/openapi-python-client)
|
|
3
3
|
[](https://lbesson.mit-license.org/)
|
|
4
4
|
[](https://mypy.readthedocs.io/en/stable/introduction.html)
|
|
5
|
-
[](https://github.com/ambv/black)
|
|
6
5
|
[](https://pypi.python.org/pypi/openapi-python-client/)
|
|
7
6
|
[](https://pepy.tech/project/openapi-python-client)
|
|
8
7
|
|
|
@@ -21,13 +20,17 @@ This tool focuses on creating the best developer experience for Python developer
|
|
|
21
20
|
|
|
22
21
|
1. Using all the latest and greatest Python features like type annotations and dataclasses.
|
|
23
22
|
2. Having documentation and usage instructions specific to this one generator.
|
|
24
|
-
|
|
23
|
+
3. Being written in Python with Jinja2 templates, making it easier to improve and extend for Python developers. It's also much easier to install and use if you already have Python.
|
|
24
|
+
|
|
25
|
+
## Sponsors
|
|
26
|
+
|
|
27
|
+
<a href="https://www.devmark.ai/fern/?utm_source=openapi-python-client&utm_loc=readme&utm_type=logo" target="_blank" title="Fern | SDKs and API docs"><img src="https://raw.githubusercontent.com/openapi-generators/openapi-python-client/main/.github/sponsors/fern.png"></a>
|
|
25
28
|
|
|
26
29
|
## Installation
|
|
27
30
|
|
|
28
31
|
I recommend you install with [pipx](https://pipxproject.github.io/pipx/) so you don't conflict with any other packages you might have: `pipx install openapi-python-client --include-deps`.
|
|
29
32
|
|
|
30
|
-
> Note the `--include-deps` option which will also make `black
|
|
33
|
+
> Note the `--include-deps` option which will also make `black` and `ruff` available in your path so that `openapi-python-client` can use them to clean up the generated code.
|
|
31
34
|
|
|
32
35
|
**If you use `pipx run` then the post-generation hooks will not be available unless you install them manually.**
|
|
33
36
|
|
|
@@ -151,9 +154,8 @@ In the config file, there's an easy way to tell `openapi-python-client` to run a
|
|
|
151
154
|
|
|
152
155
|
```yaml
|
|
153
156
|
post_hooks:
|
|
154
|
-
- "
|
|
155
|
-
- "
|
|
156
|
-
- "black ."
|
|
157
|
+
- "ruff check . --fix"
|
|
158
|
+
- "ruff format ."
|
|
157
159
|
```
|
|
158
160
|
|
|
159
161
|
### use_path_prefixes_for_title_model_names
|
{openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/__init__.py
RENAMED
|
@@ -40,7 +40,7 @@ TEMPLATE_FILTERS = {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
class Project:
|
|
43
|
+
class Project:
|
|
44
44
|
"""Represents a Python project (the top level file-tree) to generate"""
|
|
45
45
|
|
|
46
46
|
def __init__(
|
|
@@ -151,7 +151,7 @@ class Project: # pylint: disable=too-many-instance-attributes
|
|
|
151
151
|
return
|
|
152
152
|
try:
|
|
153
153
|
cwd = self.package_dir if self.meta == MetaType.NONE else self.project_dir
|
|
154
|
-
subprocess.run(cmd, cwd=cwd, shell=True,
|
|
154
|
+
subprocess.run(cmd, cwd=cwd, shell=True, capture_output=True, check=True)
|
|
155
155
|
except CalledProcessError as err:
|
|
156
156
|
self.errors.append(
|
|
157
157
|
GeneratorError(
|
|
@@ -253,7 +253,6 @@ class Project: # pylint: disable=too-many-instance-attributes
|
|
|
253
253
|
models_init_template = self.env.get_template("models_init.py.jinja")
|
|
254
254
|
models_init.write_text(models_init_template.render(imports=imports, alls=alls), encoding=self.file_encoding)
|
|
255
255
|
|
|
256
|
-
# pylint: disable=too-many-locals
|
|
257
256
|
def _build_api(self) -> None:
|
|
258
257
|
# Generate Client
|
|
259
258
|
client_path = self.package_dir / "client.py"
|
|
@@ -297,7 +296,7 @@ class Project: # pylint: disable=too-many-instance-attributes
|
|
|
297
296
|
)
|
|
298
297
|
|
|
299
298
|
|
|
300
|
-
def _get_project_for_url_or_path(
|
|
299
|
+
def _get_project_for_url_or_path(
|
|
301
300
|
url: Optional[str],
|
|
302
301
|
path: Optional[Path],
|
|
303
302
|
meta: MetaType,
|
|
@@ -31,7 +31,8 @@ def _process_config(path: Optional[pathlib.Path]) -> Config:
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
# noinspection PyUnusedLocal
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
|
|
35
36
|
@app.callback(name="openapi-python-client")
|
|
36
37
|
def cli(
|
|
37
38
|
version: bool = typer.Option(False, "--version", callback=_version_callback, help="Print the version and exit"),
|
|
@@ -110,7 +111,6 @@ _meta_option = typer.Option(
|
|
|
110
111
|
CONFIG_OPTION = typer.Option(None, "--config", help="Path to the config file to use")
|
|
111
112
|
|
|
112
113
|
|
|
113
|
-
# pylint: disable=too-many-arguments
|
|
114
114
|
@app.command()
|
|
115
115
|
def generate(
|
|
116
116
|
url: Optional[str] = typer.Option(None, help="A URL to read the JSON from"),
|
|
@@ -149,7 +149,6 @@ def generate(
|
|
|
149
149
|
handle_errors(errors, fail_on_warning)
|
|
150
150
|
|
|
151
151
|
|
|
152
|
-
# pylint: disable=too-many-arguments
|
|
153
152
|
@app.command()
|
|
154
153
|
def update(
|
|
155
154
|
url: Optional[str] = typer.Option(None, help="A URL to read the JSON from"),
|
{openapi_python_client-0.15.1 → openapi_python_client-0.16.0}/openapi_python_client/config.py
RENAMED
|
@@ -29,9 +29,8 @@ class Config(BaseModel):
|
|
|
29
29
|
package_version_override: Optional[str] = None
|
|
30
30
|
use_path_prefixes_for_title_model_names: bool = True
|
|
31
31
|
post_hooks: List[str] = [
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"black .",
|
|
32
|
+
"ruff check --fix .",
|
|
33
|
+
"ruff format .",
|
|
35
34
|
]
|
|
36
35
|
field_prefix: str = "field_"
|
|
37
36
|
http_timeout: int = 5
|
|
@@ -3,7 +3,7 @@ from collections import OrderedDict
|
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
from http import HTTPStatus
|
|
6
|
-
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union
|
|
6
|
+
from typing import Any, Dict, Iterator, List, Optional, Protocol, Set, Tuple, Union
|
|
7
7
|
|
|
8
8
|
import attr
|
|
9
9
|
from pydantic import ValidationError
|
|
@@ -46,7 +46,11 @@ class EndpointCollection:
|
|
|
46
46
|
|
|
47
47
|
@staticmethod
|
|
48
48
|
def from_data(
|
|
49
|
-
*,
|
|
49
|
+
*,
|
|
50
|
+
data: Dict[str, oai.PathItem],
|
|
51
|
+
schemas: Schemas,
|
|
52
|
+
parameters: Parameters,
|
|
53
|
+
config: Config,
|
|
50
54
|
) -> Tuple[Dict[utils.PythonIdentifier, "EndpointCollection"], Schemas, Parameters]:
|
|
51
55
|
"""Parse the openapi paths data to get EndpointCollections by tag"""
|
|
52
56
|
endpoints_by_tag: Dict[utils.PythonIdentifier, EndpointCollection] = {}
|
|
@@ -72,7 +76,11 @@ class EndpointCollection:
|
|
|
72
76
|
# Add `PathItem` parameters
|
|
73
77
|
if not isinstance(endpoint, ParseError):
|
|
74
78
|
endpoint, schemas, parameters = Endpoint.add_parameters(
|
|
75
|
-
endpoint=endpoint,
|
|
79
|
+
endpoint=endpoint,
|
|
80
|
+
data=path_data,
|
|
81
|
+
schemas=schemas,
|
|
82
|
+
parameters=parameters,
|
|
83
|
+
config=config,
|
|
76
84
|
)
|
|
77
85
|
if not isinstance(endpoint, ParseError):
|
|
78
86
|
endpoint = Endpoint.sort_parameters(endpoint=endpoint)
|
|
@@ -103,7 +111,15 @@ def generate_operation_id(*, path: str, method: str) -> str:
|
|
|
103
111
|
models_relative_prefix: str = "..."
|
|
104
112
|
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
class RequestBodyParser(Protocol):
|
|
115
|
+
__name__: str = "RequestBodyParser"
|
|
116
|
+
|
|
117
|
+
def __call__(
|
|
118
|
+
self, *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config
|
|
119
|
+
) -> Tuple[Union[Property, PropertyError, None], Schemas]:
|
|
120
|
+
... # pragma: no cover
|
|
121
|
+
|
|
122
|
+
|
|
107
123
|
@dataclass
|
|
108
124
|
class Endpoint:
|
|
109
125
|
"""
|
|
@@ -126,6 +142,7 @@ class Endpoint:
|
|
|
126
142
|
form_body: Optional[Property] = None
|
|
127
143
|
json_body: Optional[Property] = None
|
|
128
144
|
multipart_body: Optional[Property] = None
|
|
145
|
+
binary_body: Optional[Property] = None
|
|
129
146
|
errors: List[ParseError] = field(default_factory=list)
|
|
130
147
|
used_python_identifiers: Set[PythonIdentifier] = field(default_factory=set)
|
|
131
148
|
|
|
@@ -146,7 +163,13 @@ class Endpoint:
|
|
|
146
163
|
config=config,
|
|
147
164
|
)
|
|
148
165
|
if isinstance(prop, ModelProperty):
|
|
149
|
-
schemas = attr.evolve(
|
|
166
|
+
schemas = attr.evolve(
|
|
167
|
+
schemas,
|
|
168
|
+
classes_by_name={
|
|
169
|
+
**schemas.classes_by_name,
|
|
170
|
+
prop.class_info.name: prop,
|
|
171
|
+
},
|
|
172
|
+
)
|
|
150
173
|
return prop, schemas
|
|
151
174
|
return None, schemas
|
|
152
175
|
|
|
@@ -168,7 +191,13 @@ class Endpoint:
|
|
|
168
191
|
)
|
|
169
192
|
if isinstance(prop, ModelProperty):
|
|
170
193
|
prop = attr.evolve(prop, is_multipart_body=True)
|
|
171
|
-
schemas = attr.evolve(
|
|
194
|
+
schemas = attr.evolve(
|
|
195
|
+
schemas,
|
|
196
|
+
classes_by_name={
|
|
197
|
+
**schemas.classes_by_name,
|
|
198
|
+
prop.class_info.name: prop,
|
|
199
|
+
},
|
|
200
|
+
)
|
|
172
201
|
return prop, schemas
|
|
173
202
|
return None, schemas
|
|
174
203
|
|
|
@@ -179,9 +208,11 @@ class Endpoint:
|
|
|
179
208
|
"""Return json_body"""
|
|
180
209
|
json_body = None
|
|
181
210
|
for content_type, schema in body.content.items():
|
|
182
|
-
|
|
211
|
+
parsed_content_type = get_content_type(content_type)
|
|
183
212
|
|
|
184
|
-
if
|
|
213
|
+
if parsed_content_type is not None and (
|
|
214
|
+
parsed_content_type == "application/json" or parsed_content_type.endswith("+json")
|
|
215
|
+
):
|
|
185
216
|
json_body = schema
|
|
186
217
|
break
|
|
187
218
|
|
|
@@ -196,6 +227,30 @@ class Endpoint:
|
|
|
196
227
|
)
|
|
197
228
|
return None, schemas
|
|
198
229
|
|
|
230
|
+
@staticmethod
|
|
231
|
+
def parse_request_binary_body(
|
|
232
|
+
*, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config
|
|
233
|
+
) -> Tuple[Union[Property, PropertyError, None], Schemas]:
|
|
234
|
+
"""Return binary_body"""
|
|
235
|
+
binary_body = None
|
|
236
|
+
for content_type, schema in body.content.items():
|
|
237
|
+
parsed_content_type = get_content_type(content_type)
|
|
238
|
+
|
|
239
|
+
if parsed_content_type == "application/octet-stream":
|
|
240
|
+
binary_body = schema
|
|
241
|
+
break
|
|
242
|
+
|
|
243
|
+
if binary_body is not None and binary_body.media_type_schema is not None:
|
|
244
|
+
return property_from_data(
|
|
245
|
+
name="binary_body",
|
|
246
|
+
required=True,
|
|
247
|
+
data=binary_body.media_type_schema,
|
|
248
|
+
schemas=schemas,
|
|
249
|
+
parent_name=parent_name,
|
|
250
|
+
config=config,
|
|
251
|
+
)
|
|
252
|
+
return None, schemas
|
|
253
|
+
|
|
199
254
|
@staticmethod
|
|
200
255
|
def _add_body(
|
|
201
256
|
*,
|
|
@@ -209,59 +264,34 @@ class Endpoint:
|
|
|
209
264
|
if data.requestBody is None or isinstance(data.requestBody, oai.Reference):
|
|
210
265
|
return endpoint, schemas
|
|
211
266
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
267
|
+
request_body_parsers: List[Tuple[str, RequestBodyParser]] = [
|
|
268
|
+
("form_body", Endpoint.parse_request_form_body),
|
|
269
|
+
("json_body", Endpoint.parse_request_json_body),
|
|
270
|
+
("binary_body", Endpoint.parse_request_binary_body),
|
|
271
|
+
("multipart_body", Endpoint.parse_multipart_body),
|
|
272
|
+
]
|
|
215
273
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
ParseError(
|
|
219
|
-
header=f"Cannot parse form body of endpoint {endpoint.name}",
|
|
220
|
-
detail=form_body.detail,
|
|
221
|
-
data=form_body.data,
|
|
222
|
-
),
|
|
223
|
-
schemas,
|
|
224
|
-
)
|
|
274
|
+
for property_name, parser in request_body_parsers:
|
|
275
|
+
body, schemas = parser(body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config)
|
|
225
276
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
277
|
+
if isinstance(body, ParseError):
|
|
278
|
+
property_type = property_name
|
|
279
|
+
if property_type.endswith("_body"):
|
|
280
|
+
property_type = property_type[:-5]
|
|
281
|
+
return (
|
|
282
|
+
ParseError(
|
|
283
|
+
header=f"Cannot parse {property_type} request body of endpoint {endpoint.name}",
|
|
284
|
+
detail=body.detail,
|
|
285
|
+
data=body.data,
|
|
286
|
+
),
|
|
287
|
+
schemas,
|
|
288
|
+
)
|
|
238
289
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return (
|
|
244
|
-
ParseError(
|
|
245
|
-
header=f"Cannot parse multipart body of endpoint {endpoint.name}",
|
|
246
|
-
detail=multipart_body.detail,
|
|
247
|
-
data=multipart_body.data,
|
|
248
|
-
),
|
|
249
|
-
schemas,
|
|
250
|
-
)
|
|
290
|
+
if body is not None:
|
|
291
|
+
setattr(endpoint, property_name, body)
|
|
292
|
+
endpoint.relative_imports.update(body.get_imports(prefix=models_relative_prefix))
|
|
293
|
+
endpoint.relative_imports.update(body.get_lazy_imports(prefix=models_relative_prefix))
|
|
251
294
|
|
|
252
|
-
# No reasons to use lazy imports in endpoints, so add lazy imports to relative here.
|
|
253
|
-
if form_body is not None:
|
|
254
|
-
endpoint.form_body = form_body
|
|
255
|
-
endpoint.relative_imports.update(endpoint.form_body.get_imports(prefix=models_relative_prefix))
|
|
256
|
-
endpoint.relative_imports.update(endpoint.form_body.get_lazy_imports(prefix=models_relative_prefix))
|
|
257
|
-
if multipart_body is not None:
|
|
258
|
-
endpoint.multipart_body = multipart_body
|
|
259
|
-
endpoint.relative_imports.update(endpoint.multipart_body.get_imports(prefix=models_relative_prefix))
|
|
260
|
-
endpoint.relative_imports.update(endpoint.multipart_body.get_lazy_imports(prefix=models_relative_prefix))
|
|
261
|
-
if json_body is not None:
|
|
262
|
-
endpoint.json_body = json_body
|
|
263
|
-
endpoint.relative_imports.update(endpoint.json_body.get_imports(prefix=models_relative_prefix))
|
|
264
|
-
endpoint.relative_imports.update(endpoint.json_body.get_lazy_imports(prefix=models_relative_prefix))
|
|
265
295
|
return endpoint, schemas
|
|
266
296
|
|
|
267
297
|
@staticmethod
|
|
@@ -286,7 +316,11 @@ class Endpoint:
|
|
|
286
316
|
continue
|
|
287
317
|
|
|
288
318
|
response, schemas = response_from_data(
|
|
289
|
-
status_code=status_code,
|
|
319
|
+
status_code=status_code,
|
|
320
|
+
data=response_data,
|
|
321
|
+
schemas=schemas,
|
|
322
|
+
parent_name=endpoint.name,
|
|
323
|
+
config=config,
|
|
290
324
|
)
|
|
291
325
|
if isinstance(response, ParseError):
|
|
292
326
|
detail_suffix = "" if response.detail is None else f" ({response.detail})"
|
|
@@ -307,9 +341,8 @@ class Endpoint:
|
|
|
307
341
|
endpoint.responses.append(response)
|
|
308
342
|
return endpoint, schemas
|
|
309
343
|
|
|
310
|
-
# pylint: disable=too-many-return-statements
|
|
311
344
|
@staticmethod
|
|
312
|
-
def add_parameters(
|
|
345
|
+
def add_parameters( # noqa: PLR0911, PLR0912
|
|
313
346
|
*,
|
|
314
347
|
endpoint: "Endpoint",
|
|
315
348
|
data: Union[oai.Operation, oai.PathItem],
|
|
@@ -338,7 +371,6 @@ class Endpoint:
|
|
|
338
371
|
- https://swagger.io/docs/specification/describing-parameters/
|
|
339
372
|
- https://swagger.io/docs/specification/paths-and-operations/
|
|
340
373
|
"""
|
|
341
|
-
# pylint: disable=too-many-branches, too-many-locals
|
|
342
374
|
# There isn't much value in breaking down this function further other than to satisfy the linter.
|
|
343
375
|
|
|
344
376
|
if data.parameters is None:
|
|
@@ -353,7 +385,15 @@ class Endpoint:
|
|
|
353
385
|
oai.ParameterLocation.HEADER: endpoint.header_parameters,
|
|
354
386
|
oai.ParameterLocation.COOKIE: endpoint.cookie_parameters,
|
|
355
387
|
"RESERVED": { # These can't be param names because codegen needs them as vars, the properties don't matter
|
|
356
|
-
"client": AnyProperty(
|
|
388
|
+
"client": AnyProperty(
|
|
389
|
+
"client",
|
|
390
|
+
True,
|
|
391
|
+
False,
|
|
392
|
+
None,
|
|
393
|
+
PythonIdentifier("client", ""),
|
|
394
|
+
None,
|
|
395
|
+
None,
|
|
396
|
+
),
|
|
357
397
|
"url": AnyProperty("url", True, False, None, PythonIdentifier("url", ""), None, None),
|
|
358
398
|
},
|
|
359
399
|
}
|
|
@@ -363,7 +403,7 @@ class Endpoint:
|
|
|
363
403
|
param_or_error = parameter_from_reference(param=param, parameters=parameters)
|
|
364
404
|
if isinstance(param_or_error, ParseError):
|
|
365
405
|
return param_or_error, schemas, parameters
|
|
366
|
-
param = param_or_error
|
|
406
|
+
param = param_or_error # noqa: PLW2901
|
|
367
407
|
|
|
368
408
|
if param.param_schema is None:
|
|
369
409
|
continue
|
|
@@ -396,7 +436,10 @@ class Endpoint:
|
|
|
396
436
|
|
|
397
437
|
if isinstance(prop, ParseError):
|
|
398
438
|
return (
|
|
399
|
-
ParseError(
|
|
439
|
+
ParseError(
|
|
440
|
+
detail=f"cannot parse parameter of endpoint {endpoint.name}",
|
|
441
|
+
data=prop.data,
|
|
442
|
+
),
|
|
400
443
|
schemas,
|
|
401
444
|
parameters,
|
|
402
445
|
)
|
|
@@ -435,7 +478,8 @@ class Endpoint:
|
|
|
435
478
|
if prop.python_name in endpoint.used_python_identifiers:
|
|
436
479
|
return (
|
|
437
480
|
ParseError(
|
|
438
|
-
detail=f"Parameters with same Python identifier `{prop.python_name}` detected",
|
|
481
|
+
detail=f"Parameters with same Python identifier `{prop.python_name}` detected",
|
|
482
|
+
data=data,
|
|
439
483
|
),
|
|
440
484
|
schemas,
|
|
441
485
|
parameters,
|
|
@@ -468,7 +512,8 @@ class Endpoint:
|
|
|
468
512
|
parameters_from_path = re.findall(_PATH_PARAM_REGEX, endpoint.path)
|
|
469
513
|
try:
|
|
470
514
|
sorted_params = sorted(
|
|
471
|
-
endpoint.path_parameters.values(),
|
|
515
|
+
endpoint.path_parameters.values(),
|
|
516
|
+
key=lambda param: parameters_from_path.index(param.name),
|
|
472
517
|
)
|
|
473
518
|
endpoint.path_parameters = OrderedDict((param.name, param) for param in sorted_params)
|
|
474
519
|
except ValueError:
|
|
@@ -509,7 +554,11 @@ class Endpoint:
|
|
|
509
554
|
)
|
|
510
555
|
|
|
511
556
|
result, schemas, parameters = Endpoint.add_parameters(
|
|
512
|
-
endpoint=endpoint,
|
|
557
|
+
endpoint=endpoint,
|
|
558
|
+
data=data,
|
|
559
|
+
schemas=schemas,
|
|
560
|
+
parameters=parameters,
|
|
561
|
+
config=config,
|
|
513
562
|
)
|
|
514
563
|
if isinstance(result, ParseError):
|
|
515
564
|
return result, schemas, parameters
|
|
@@ -537,6 +586,8 @@ class Endpoint:
|
|
|
537
586
|
yield self.multipart_body
|
|
538
587
|
if self.json_body:
|
|
539
588
|
yield self.json_body
|
|
589
|
+
if self.binary_body:
|
|
590
|
+
yield self.binary_body
|
|
540
591
|
|
|
541
592
|
def list_all_parameters(self) -> List[Property]:
|
|
542
593
|
"""Return a List of all the parameters of this endpoint"""
|
|
@@ -573,7 +624,9 @@ class GeneratorData:
|
|
|
573
624
|
schemas = build_schemas(components=openapi.components.schemas, schemas=schemas, config=config)
|
|
574
625
|
if openapi.components and openapi.components.parameters:
|
|
575
626
|
parameters = build_parameters(
|
|
576
|
-
components=openapi.components.parameters,
|
|
627
|
+
components=openapi.components.parameters,
|
|
628
|
+
parameters=parameters,
|
|
629
|
+
config=config,
|
|
577
630
|
)
|
|
578
631
|
endpoint_collections_by_tag, schemas, parameters = EndpointCollection.from_data(
|
|
579
632
|
data=openapi.paths, schemas=schemas, parameters=parameters, config=config
|
|
@@ -16,9 +16,8 @@ from typing import Any, ClassVar, Dict, Generic, Iterable, List, Optional, Set,
|
|
|
16
16
|
|
|
17
17
|
from attrs import define, evolve
|
|
18
18
|
|
|
19
|
-
from ... import Config
|
|
19
|
+
from ... import Config, utils
|
|
20
20
|
from ... import schema as oai
|
|
21
|
-
from ... import utils
|
|
22
21
|
from ..errors import ParameterError, ParseError, PropertyError, ValidationError
|
|
23
22
|
from .converter import convert, convert_chain
|
|
24
23
|
from .enum_property import EnumProperty
|
|
@@ -188,7 +187,6 @@ class ListProperty(Property, Generic[InnerProp]):
|
|
|
188
187
|
inner_property: InnerProp
|
|
189
188
|
template: ClassVar[str] = "list_property.py.jinja"
|
|
190
189
|
|
|
191
|
-
# pylint: disable=unused-argument
|
|
192
190
|
def get_base_type_string(self, *, quoted: bool = False) -> str:
|
|
193
191
|
return f"List[{self.inner_property.get_type_string(quoted=not self.inner_property.is_base_type)}]"
|
|
194
192
|
|
|
@@ -236,7 +234,6 @@ class UnionProperty(Property):
|
|
|
236
234
|
return inner_types.pop()
|
|
237
235
|
return f"Union[{', '.join(sorted(inner_types))}]"
|
|
238
236
|
|
|
239
|
-
# pylint: disable=unused-argument
|
|
240
237
|
def get_base_type_string(self, *, quoted: bool = False) -> str:
|
|
241
238
|
return self._get_type_string_from_inner_type_strings(self._get_inner_type_strings(json=False))
|
|
242
239
|
|
|
@@ -570,7 +567,6 @@ def build_list_property(
|
|
|
570
567
|
)
|
|
571
568
|
|
|
572
569
|
|
|
573
|
-
# pylint: disable=too-many-arguments
|
|
574
570
|
def _property_from_ref(
|
|
575
571
|
name: str,
|
|
576
572
|
required: bool,
|
|
@@ -605,8 +601,7 @@ def _property_from_ref(
|
|
|
605
601
|
return prop, schemas
|
|
606
602
|
|
|
607
603
|
|
|
608
|
-
#
|
|
609
|
-
def _property_from_data(
|
|
604
|
+
def _property_from_data( # noqa: PLR0911
|
|
610
605
|
name: str,
|
|
611
606
|
required: bool,
|
|
612
607
|
data: Union[oai.Reference, oai.Schema],
|