openapi-python-client 0.15.2__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.
Files changed (89) hide show
  1. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/CHANGELOG.md +34 -0
  2. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/PKG-INFO +12 -10
  3. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/README.md +8 -6
  4. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/__init__.py +3 -4
  5. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/cli.py +2 -3
  6. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/config.py +2 -3
  7. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/openapi.py +121 -68
  8. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/__init__.py +2 -7
  9. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/enum_property.py +0 -1
  10. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/model_property.py +42 -45
  11. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/property.py +1 -2
  12. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/schemas.py +1 -1
  13. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/responses.py +51 -16
  14. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +1 -1
  15. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +1 -1
  16. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +1 -2
  17. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +2 -2
  18. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +1 -1
  19. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_macros.py.jinja +13 -2
  20. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_module.py.jinja +7 -3
  21. openapi_python_client-0.16.0/openapi_python_client/templates/pyproject_no_poetry.toml.jinja +3 -0
  22. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/utils.py +18 -10
  23. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/pyproject.toml +18 -49
  24. openapi_python_client-0.15.2/openapi_python_client/templates/pyproject_no_poetry.toml.jinja +0 -16
  25. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/LICENSE +0 -0
  26. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/__main__.py +0 -0
  27. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/__init__.py +0 -0
  28. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/errors.py +0 -0
  29. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/parser/properties/converter.py +0 -0
  30. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/py.typed +0 -0
  31. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/__init__.py +0 -0
  32. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/data_type.py +0 -0
  33. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
  34. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
  35. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
  36. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
  37. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
  38. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
  39. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
  40. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
  41. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
  42. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
  43. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
  44. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
  45. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
  46. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
  47. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
  48. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
  49. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
  50. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
  51. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
  52. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
  53. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
  54. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
  55. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
  56. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
  57. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
  58. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
  59. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
  60. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
  61. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/schema/parameter_location.py +0 -0
  62. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/.gitignore.jinja +0 -0
  63. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/README.md.jinja +0 -0
  64. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/api_init.py.jinja +0 -0
  65. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/client.py.jinja +0 -0
  66. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
  67. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/errors.py.jinja +0 -0
  68. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/helpers.jinja +0 -0
  69. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/int_enum.py.jinja +0 -0
  70. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/model.py.jinja +0 -0
  71. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/models_init.py.jinja +0 -0
  72. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/package_init.py.jinja +0 -0
  73. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
  74. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -0
  75. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/date_property.py.jinja +0 -0
  76. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +0 -0
  77. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/enum_property.py.jinja +0 -0
  78. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/file_property.py.jinja +0 -0
  79. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -0
  80. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
  81. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -0
  82. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/list_property.py.jinja +0 -0
  83. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -0
  84. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
  85. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/property_templates/union_property.py.jinja +0 -0
  86. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/pyproject.toml.jinja +0 -0
  87. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/setup.py.jinja +0 -0
  88. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/str_enum.py.jinja +0 -0
  89. {openapi_python_client-0.15.2 → openapi_python_client-0.16.0}/openapi_python_client/templates/types.py.jinja +0 -0
@@ -13,6 +13,40 @@ 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
+
16
50
  ## 0.15.2 (2023-09-16)
17
51
 
18
52
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openapi-python-client
3
- Version: 0.15.2
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
25
  Requires-Dist: httpx (>=0.20.0,<0.26.0)
27
- Requires-Dist: isort (>=5.0.5,<6.0.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
  [![codecov](https://codecov.io/gh/openapi-generators/openapi-python-client/branch/main/graph/badge.svg)](https://codecov.io/gh/triaxtec/openapi-python-client)
38
38
  [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
39
39
  [![Generic badge](https://img.shields.io/badge/type_checked-mypy-informational.svg)](https://mypy.readthedocs.io/en/stable/introduction.html)
40
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
41
40
  [![PyPI version shields.io](https://img.shields.io/pypi/v/openapi-python-client.svg)](https://pypi.python.org/pypi/openapi-python-client/)
42
41
  [![Downloads](https://static.pepy.tech/personalized-badge/openapi-python-client?period=total&units=international_system&left_color=blue&right_color=green&left_text=Downloads)](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
- 1. 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.
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`, `isort`, and `autoflake` available in your path so that `openapi-python-client` can use them to clean up the generated code.
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
- - "autoflake -i -r --remove-all-unused-imports --remove-unused-variables --ignore-init-module-imports ."
190
- - "isort ."
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
  [![codecov](https://codecov.io/gh/openapi-generators/openapi-python-client/branch/main/graph/badge.svg)](https://codecov.io/gh/triaxtec/openapi-python-client)
3
3
  [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
4
4
  [![Generic badge](https://img.shields.io/badge/type_checked-mypy-informational.svg)](https://mypy.readthedocs.io/en/stable/introduction.html)
5
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
6
5
  [![PyPI version shields.io](https://img.shields.io/pypi/v/openapi-python-client.svg)](https://pypi.python.org/pypi/openapi-python-client/)
7
6
  [![Downloads](https://static.pepy.tech/personalized-badge/openapi-python-client?period=total&units=international_system&left_color=blue&right_color=green&left_text=Downloads)](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
- 1. 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.
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`, `isort`, and `autoflake` available in your path so that `openapi-python-client` can use them to clean up the generated code.
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
- - "autoflake -i -r --remove-all-unused-imports --remove-unused-variables --ignore-init-module-imports ."
155
- - "isort ."
156
- - "black ."
157
+ - "ruff check . --fix"
158
+ - "ruff format ."
157
159
  ```
158
160
 
159
161
  ### use_path_prefixes_for_title_model_names
@@ -40,7 +40,7 @@ TEMPLATE_FILTERS = {
40
40
  }
41
41
 
42
42
 
43
- class Project: # pylint: disable=too-many-instance-attributes
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, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=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( # pylint: disable=too-many-arguments
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
- # pylint: disable=unused-argument
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"),
@@ -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
- "autoflake -i -r --remove-all-unused-imports --remove-unused-variables --ignore-init-module-imports .",
33
- "isort .",
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
- *, data: Dict[str, oai.PathItem], schemas: Schemas, parameters: Parameters, config: Config
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, data=path_data, schemas=schemas, parameters=parameters, config=config
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
- # pylint: disable=too-many-instance-attributes
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(schemas, classes_by_name={**schemas.classes_by_name, prop.class_info.name: prop})
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(schemas, classes_by_name={**schemas.classes_by_name, prop.class_info.name: prop})
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
- content_type = get_content_type(content_type)
211
+ parsed_content_type = get_content_type(content_type)
183
212
 
184
- if content_type == "application/json" or content_type.endswith("+json"):
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
- form_body, schemas = Endpoint.parse_request_form_body(
213
- body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
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
- if isinstance(form_body, ParseError):
217
- return (
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
- json_body, schemas = Endpoint.parse_request_json_body(
227
- body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
228
- )
229
- if isinstance(json_body, ParseError):
230
- return (
231
- ParseError(
232
- header=f"Cannot parse JSON body of endpoint {endpoint.name}",
233
- detail=json_body.detail,
234
- data=json_body.data,
235
- ),
236
- schemas,
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
- multipart_body, schemas = Endpoint.parse_multipart_body(
240
- body=data.requestBody, schemas=schemas, parent_name=endpoint.name, config=config
241
- )
242
- if isinstance(multipart_body, ParseError):
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, data=response_data, schemas=schemas, parent_name=endpoint.name, config=config
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("client", True, False, None, PythonIdentifier("client", ""), None, None),
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(detail=f"cannot parse parameter of endpoint {endpoint.name}", data=prop.data),
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", data=data
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(), key=lambda param: parameters_from_path.index(param.name)
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, data=data, schemas=schemas, parameters=parameters, config=config
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, parameters=parameters, config=config
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
- # pylint: disable=too-many-arguments,too-many-return-statements
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],
@@ -30,7 +30,6 @@ class EnumProperty(Property):
30
30
  oai.ParameterLocation.HEADER,
31
31
  }
32
32
 
33
- # pylint: disable=unused-argument
34
33
  def get_base_type_string(self, *, quoted: bool = False) -> str:
35
34
  return self.class_info.name
36
35