Don't cast list to tuple in python-prior binding (#14014)

* 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: https://github.com/OpenAPITools/openapi-generator/issues/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: https://github.com/OpenAPITools/openapi-generator/issues/14012
This commit is contained in:
Jeremy Audet
2022-11-15 20:40:28 -05:00
committed by GitHub
parent 77226981b6
commit 92ecee8c27
6 changed files with 60 additions and 5 deletions

View File

@@ -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(

View File

@@ -286,8 +286,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(

View File

@@ -286,8 +286,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(

View File

@@ -286,8 +286,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(

View File

@@ -286,8 +286,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(

View File

@@ -14,8 +14,11 @@ from collections import namedtuple
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
@@ -490,6 +493,48 @@ class TestFakeApi(unittest.TestCase):
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"""