Skip to content

Commit 9952667

Browse files
authored
Merge branch 'main' into renovate/lock-file-maintenance
2 parents 5e0c6b2 + 305229b commit 9952667

File tree

89 files changed

+1236
-1128
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+1236
-1128
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
default: major
3+
---
4+
5+
# Raise minimum httpx version to 0.23
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
default: major
3+
---
4+
5+
# Removed ability to set an array as a multipart body
6+
7+
Previously, when defining a request's body as `multipart/form-data`, the generator would attempt to generate code
8+
for both `object` schemas and `array` schemas. However, most arrays could not generate valid multipart bodies, as
9+
there would be no field names (required to set the `Content-Disposition` headers).
10+
11+
The code to generate any body for `multipart/form-data` where the schema is `array` has been removed, and any such
12+
bodies will be skipped. This is not _expected_ to be a breaking change in practice, since the code generated would
13+
probably never work.
14+
15+
If you have a use-case for `multipart/form-data` with an `array` schema, please [open a new discussion](https://github.com/openapi-generators/openapi-python-client/discussions) with an example schema and the desired functional Python code.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
default: major
3+
---
4+
5+
# Change default multipart array serialization
6+
7+
Previously, any arrays of values in a `multipart/form-data` body would be serialized as an `application/json` part.
8+
This matches the default behavior specified by OpenAPI and supports arrays of files (`binary` format strings).
9+
However, because this generator doesn't yet support specifying `encoding` per property, this may result in
10+
now-incorrect code when the encoding _was_ explicitly set to `application/json` for arrays of scalar values.
11+
12+
PR #938 fixes #692. Thanks @micha91 for the fix, @ratgen and @FabianSchurig for testing, and @davidlizeng for the original report... many years ago 😅.

.github/workflows/checks.yml

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,12 @@ jobs:
153153
runs-on: ubuntu-latest
154154
strategy:
155155
matrix:
156-
httpx_version:
157-
- "0.20.0"
158-
- ""
156+
lockfile:
157+
- "pdm.lock"
158+
- "pdm.minimal.lock"
159159
services:
160160
openapi-test-server:
161-
image: ghcr.io/openapi-generators/openapi-test-server:0.0.1
161+
image: ghcr.io/openapi-generators/openapi-test-server:0.2.1
162162
ports:
163163
- "3000:3000"
164164
steps:
@@ -170,34 +170,18 @@ jobs:
170170
- name: Get Python Version
171171
id: get_python_version
172172
run: echo "python_version=$(python --version)" >> $GITHUB_OUTPUT
173-
- name: Cache dependencies
174-
uses: actions/cache@v4
175-
with:
176-
path: .venv
177-
key: ${{ runner.os }}-${{ steps.get_python_version.outputs.python_version }}-dependencies-${{ hashFiles('**/pdm.lock') }}
178-
restore-keys: |
179-
${{ runner.os }}-${{ steps.get_python_version.outputs.python_version }}-dependencies
180-
- name: Install dependencies
181-
run: |
182-
pip install pdm
183-
python -m venv .venv
184-
pdm install
185173
- name: Cache Generated Client Dependencies
186174
uses: actions/cache@v4
187175
with:
188176
path: integration-tests/.venv
189-
key: ${{ runner.os }}-${{ steps.get_python_version.outputs.python_version }}-integration-dependencies-${{ hashFiles('**/pdm.lock') }}
177+
key: ${{ runner.os }}-${{ steps.get_python_version.outputs.python_version }}-integration-dependencies-${{ hashFiles('integration-tests/pdm*.lock') }}
190178
restore-keys: |
191179
${{ runner.os }}-${{ steps.get_python_version.outputs.python_version }}-integration-dependencies
192-
- name: Set httpx version
193-
if: matrix.httpx_version != ''
194-
run: |
195-
cd integration-tests
196-
pdm add httpx==${{ matrix.httpx_version }}
197180
- name: Install Integration Dependencies
198181
run: |
199182
cd integration-tests
200-
pdm install
183+
pip install pdm
184+
pdm install -L ${{ matrix.lockfile }}
201185
- name: Run Tests
202186
run: |
203187
cd integration-tests

end_to_end_tests/baseline_openapi_3.0.json

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -431,51 +431,6 @@
431431
}
432432
}
433433
},
434-
"/tests/upload/multiple": {
435-
"post": {
436-
"tags": [
437-
"tests"
438-
],
439-
"summary": "Upload multiple files",
440-
"description": "Upload several files in the same request",
441-
"operationId": "upload_multiple_files_tests_upload_post",
442-
"parameters": [],
443-
"requestBody": {
444-
"content": {
445-
"multipart/form-data": {
446-
"schema": {
447-
"type": "array",
448-
"items": {
449-
"type": "string",
450-
"format": "binary"
451-
}
452-
}
453-
}
454-
},
455-
"required": true
456-
},
457-
"responses": {
458-
"200": {
459-
"description": "Successful Response",
460-
"content": {
461-
"application/json": {
462-
"schema": {}
463-
}
464-
}
465-
},
466-
"422": {
467-
"description": "Validation Error",
468-
"content": {
469-
"application/json": {
470-
"schema": {
471-
"$ref": "#/components/schemas/HTTPValidationError"
472-
}
473-
}
474-
}
475-
}
476-
}
477-
}
478-
},
479434
"/tests/json_body": {
480435
"post": {
481436
"tags": [

end_to_end_tests/baseline_openapi_3.1.yaml

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -418,51 +418,6 @@ info:
418418
}
419419
}
420420
},
421-
"/tests/upload/multiple": {
422-
"post": {
423-
"tags": [
424-
"tests"
425-
],
426-
"summary": "Upload multiple files",
427-
"description": "Upload several files in the same request",
428-
"operationId": "upload_multiple_files_tests_upload_post",
429-
"parameters": [ ],
430-
"requestBody": {
431-
"content": {
432-
"multipart/form-data": {
433-
"schema": {
434-
"type": "array",
435-
"items": {
436-
"type": "string",
437-
"format": "binary"
438-
}
439-
}
440-
}
441-
},
442-
"required": true
443-
},
444-
"responses": {
445-
"200": {
446-
"description": "Successful Response",
447-
"content": {
448-
"application/json": {
449-
"schema": { }
450-
}
451-
}
452-
},
453-
"422": {
454-
"description": "Validation Error",
455-
"content": {
456-
"application/json": {
457-
"schema": {
458-
"$ref": "#/components/schemas/HTTPValidationError"
459-
}
460-
}
461-
}
462-
}
463-
}
464-
}
465-
},
466421
"/tests/json_body": {
467422
"post": {
468423
"tags": [

end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/tests/__init__.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
token_with_cookie_auth_token_with_cookie_get,
2222
unsupported_content_tests_unsupported_content_get,
2323
upload_file_tests_upload_post,
24-
upload_multiple_files_tests_upload_post,
2524
)
2625

2726

@@ -82,13 +81,6 @@ def upload_file_tests_upload_post(cls) -> types.ModuleType:
8281
"""
8382
return upload_file_tests_upload_post
8483

85-
@classmethod
86-
def upload_multiple_files_tests_upload_post(cls) -> types.ModuleType:
87-
"""
88-
Upload several files in the same request
89-
"""
90-
return upload_multiple_files_tests_upload_post
91-
9284
@classmethod
9385
def json_body_tests_json_body_post(cls) -> types.ModuleType:
9486
"""

end_to_end_tests/docstrings-on-attributes-golden-record/my_test_api_client/types.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Contains some shared types for properties"""
22

3-
from collections.abc import MutableMapping
3+
from collections.abc import Mapping, MutableMapping
44
from http import HTTPStatus
5-
from typing import BinaryIO, Generic, Literal, Optional, TypeVar
5+
from typing import IO, BinaryIO, Generic, Literal, Optional, TypeVar, Union
66

77
from attrs import define
88

@@ -14,7 +14,15 @@ def __bool__(self) -> Literal[False]:
1414

1515
UNSET: Unset = Unset()
1616

17-
FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]]
17+
# The types that `httpx.Client(files=)` can accept, copied from that library.
18+
FileContent = Union[IO[bytes], bytes, str]
19+
FileTypes = Union[
20+
# (filename, file (or bytes), content_type)
21+
tuple[Optional[str], FileContent, Optional[str]],
22+
# (filename, file (or bytes), content_type, headers)
23+
tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
24+
]
25+
RequestFiles = list[tuple[str, FileTypes]]
1826

1927

2028
@define
@@ -25,7 +33,7 @@ class File:
2533
file_name: Optional[str] = None
2634
mime_type: Optional[str] = None
2735

28-
def to_tuple(self) -> FileJsonType:
36+
def to_tuple(self) -> FileTypes:
2937
"""Return a tuple representation that httpx will accept for multipart/form-data"""
3038
return self.file_name, self.payload, self.mime_type
3139

@@ -43,4 +51,4 @@ class Response(Generic[T]):
4351
parsed: Optional[T]
4452

4553

46-
__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"]
54+
__all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"]

end_to_end_tests/docstrings-on-attributes-golden-record/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ include = ["CHANGELOG.md", "my_test_api_client/py.typed"]
1212

1313
[tool.poetry.dependencies]
1414
python = "^3.9"
15-
httpx = ">=0.20.0,<0.29.0"
15+
httpx = ">=0.23.0,<0.29.0"
1616
attrs = ">=22.2.0"
1717
python-dateutil = "^2.8.0"
1818

end_to_end_tests/golden-record/my_test_api_client/api/bodies/json_like.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ def _get_kwargs(
2020
"url": "/bodies/json-like",
2121
}
2222

23-
_body = body.to_dict()
23+
_kwargs["json"] = body.to_dict()
2424

25-
_kwargs["json"] = _body
2625
headers["Content-Type"] = "application/vnd+json"
2726

2827
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/bodies/post_bodies_multiple.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,20 @@ def _get_kwargs(
2828
}
2929

3030
if isinstance(body, PostBodiesMultipleJsonBody):
31-
_json_body = body.to_dict()
31+
_kwargs["json"] = body.to_dict()
3232

33-
_kwargs["json"] = _json_body
3433
headers["Content-Type"] = "application/json"
3534
if isinstance(body, File):
36-
_content_body = body.payload
35+
_kwargs["content"] = body.payload
3736

38-
_kwargs["content"] = _content_body
3937
headers["Content-Type"] = "application/octet-stream"
4038
if isinstance(body, PostBodiesMultipleDataBody):
41-
_data_body = body.to_dict()
39+
_kwargs["data"] = body.to_dict()
4240

43-
_kwargs["data"] = _data_body
4441
headers["Content-Type"] = "application/x-www-form-urlencoded"
4542
if isinstance(body, PostBodiesMultipleFilesBody):
46-
_files_body = body.to_multipart()
43+
_kwargs["files"] = body.to_multipart()
4744

48-
_kwargs["files"] = _files_body
4945
headers["Content-Type"] = "multipart/form-data"
5046

5147
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/bodies/refs.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ def _get_kwargs(
2020
"url": "/bodies/refs",
2121
}
2222

23-
_body = body.to_dict()
23+
_kwargs["json"] = body.to_dict()
2424

25-
_kwargs["json"] = _body
2625
headers["Content-Type"] = "application/json"
2726

2827
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/config/content_type_override.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ def _get_kwargs(
1919
"url": "/config/content-type-override",
2020
}
2121

22-
_body = body
22+
_kwargs["json"] = body
2323

24-
_kwargs["json"] = _body
2524
headers["Content-Type"] = "openapi/python/client"
2625

2726
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/naming/post_naming_property_conflict_with_import.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ def _get_kwargs(
2323
"url": "/naming/property-conflict-with-import",
2424
}
2525

26-
_body = body.to_dict()
26+
_kwargs["json"] = body.to_dict()
2727

28-
_kwargs["json"] = _body
2928
headers["Content-Type"] = "application/json"
3029

3130
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ def _get_kwargs(
2121
"url": "/tests/callback",
2222
}
2323

24-
_body = body.to_dict()
24+
_kwargs["json"] = body.to_dict()
2525

26-
_kwargs["json"] = _body
2726
headers["Content-Type"] = "application/json"
2827

2928
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/tests/json_body_tests_json_body_post.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ def _get_kwargs(
2121
"url": "/tests/json_body",
2222
}
2323

24-
_body = body.to_dict()
24+
_kwargs["json"] = body.to_dict()
2525

26-
_kwargs["json"] = _body
2726
headers["Content-Type"] = "application/json"
2827

2928
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/tests/octet_stream_tests_octet_stream_post.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ def _get_kwargs(
2020
"url": "/tests/octet_stream",
2121
}
2222

23-
_body = body.payload
23+
_kwargs["content"] = body.payload
2424

25-
_kwargs["content"] = _body
2625
headers["Content-Type"] = "application/octet-stream"
2726

2827
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ def _get_kwargs(
2020
"url": "/tests/post_form_data",
2121
}
2222

23-
_body = body.to_dict()
23+
_kwargs["data"] = body.to_dict()
2424

25-
_kwargs["data"] = _body
2625
headers["Content-Type"] = "application/x-www-form-urlencoded"
2726

2827
_kwargs["headers"] = headers

end_to_end_tests/golden-record/my_test_api_client/api/tests/post_form_data_inline.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ def _get_kwargs(
2020
"url": "/tests/post_form_data_inline",
2121
}
2222

23-
_body = body.to_dict()
23+
_kwargs["data"] = body.to_dict()
2424

25-
_kwargs["data"] = _body
2625
headers["Content-Type"] = "application/x-www-form-urlencoded"
2726

2827
_kwargs["headers"] = headers

0 commit comments

Comments
 (0)