Skip to content

Commit

Permalink
Don't cast list to tuple in python-prior binding (#14014)
Browse files Browse the repository at this point in the history
* Add test for python-prior type conversion error

In the spirit of test driven development, this test intentionally fails.
A following commit will fix the code to comply with the test.

See: #14012

* Don't cast list to tuple in python-prior binding

Tweak the python-prior API bindings, so that they no longer cast lists
to tuples when making a POST request with a multipart/form-data
content-type. This fixes an interaction with
`urllib3.request_encode_body`, whose `fields` parameter expects tuples,
not lists.

cc @spacether

See: https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html

Fix: #14012
  • Loading branch information
Ichimonji10 authored Nov 16, 2022
1 parent 7722698 commit 92ecee8
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,10 @@ class ApiClient(object):
return obj.isoformat()
elif isinstance(obj, ModelSimple):
return cls.sanitize_for_serialization(obj.value)
elif isinstance(obj, (list, tuple)):
elif isinstance(obj, list):
return [cls.sanitize_for_serialization(item) for item in obj]
elif isinstance(obj, tuple):
return tuple(cls.sanitize_for_serialization(item) for item in obj)
if isinstance(obj, dict):
return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
raise ApiValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,10 @@ def sanitize_for_serialization(cls, obj):
return obj.isoformat()
elif isinstance(obj, ModelSimple):
return cls.sanitize_for_serialization(obj.value)
elif isinstance(obj, (list, tuple)):
elif isinstance(obj, list):
return [cls.sanitize_for_serialization(item) for item in obj]
elif isinstance(obj, tuple):
return tuple(cls.sanitize_for_serialization(item) for item in obj)
if isinstance(obj, dict):
return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
raise ApiValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,10 @@ def sanitize_for_serialization(cls, obj):
return obj.isoformat()
elif isinstance(obj, ModelSimple):
return cls.sanitize_for_serialization(obj.value)
elif isinstance(obj, (list, tuple)):
elif isinstance(obj, list):
return [cls.sanitize_for_serialization(item) for item in obj]
elif isinstance(obj, tuple):
return tuple(cls.sanitize_for_serialization(item) for item in obj)
if isinstance(obj, dict):
return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
raise ApiValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,10 @@ def sanitize_for_serialization(cls, obj):
return obj.isoformat()
elif isinstance(obj, ModelSimple):
return cls.sanitize_for_serialization(obj.value)
elif isinstance(obj, (list, tuple)):
elif isinstance(obj, list):
return [cls.sanitize_for_serialization(item) for item in obj]
elif isinstance(obj, tuple):
return tuple(cls.sanitize_for_serialization(item) for item in obj)
if isinstance(obj, dict):
return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
raise ApiValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,10 @@ def sanitize_for_serialization(cls, obj):
return obj.isoformat()
elif isinstance(obj, ModelSimple):
return cls.sanitize_for_serialization(obj.value)
elif isinstance(obj, (list, tuple)):
elif isinstance(obj, list):
return [cls.sanitize_for_serialization(item) for item in obj]
elif isinstance(obj, tuple):
return tuple(cls.sanitize_for_serialization(item) for item in obj)
if isinstance(obj, dict):
return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
raise ApiValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
import os
import json
import unittest
from pathlib import Path
from unittest.mock import patch

from urllib3.request import RequestMethods

import petstore_api
from petstore_api.api.fake_api import FakeApi # noqa: E501
from petstore_api.rest import RESTClientObject, RESTResponse
Expand Down Expand Up @@ -490,6 +493,48 @@ def get_header(name, default=None):
finally:
file.close()

def test_upload_with_mime_type(self):
"""Upload a file, while setting a MIME type for that file.
Verify that:
* ``post_params`` may contain a three-tuple in the form ``(file_name, file_handle,
file_mime_type)``
* This three-tuple is passed to urllib3 as a tuple, without being converted to a list.
See:
* https://github.com/OpenAPITools/openapi-generator/issues/14012
* https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html
"""
file_path = Path(__file__, "..", "..", "testfiles", "1px_pic1.png").resolve()
file_mime_type = "image/png"
with patch.object(RequestMethods, 'request') as request:
with open(file_path, mode="rb") as file_handle:
request.return_value.status = 200
resp = self.api.api_client.call_api(
resource_path="/fake/uploadFile",
method="POST",
header_params={"Content-Type": "multipart/form-data"},
post_params={"file": (file_path.name, file_handle, file_mime_type)},
)

# a single multipart/form-data POST call was made, with a single form field
request.assert_called_once()
fields = request.call_args.kwargs['fields']
self.assertEqual(len(fields), 1, fields)
field = fields[0]

# it is in the form (form_field_name, (filename, filedata, mimetype))
self.assertEqual(field[0], "file")
self.assertEqual(field[1][0], file_path.name)
with open(file_path, mode="rb") as file_handle:
self.assertEqual(field[1][1], file_handle.read())
self.assertEqual(field[1][2], file_mime_type)

# the form field value wasn't cast to a list
self.assertIsInstance(fields[0][1], tuple)

def test_download_attachment(self):
"""Ensures that file deserialization works"""

Expand Down

0 comments on commit 92ecee8

Please sign in to comment.