From 50e2575ace09dadf12903419a86aa1ca63ab07d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 03:00:22 +0000 Subject: [PATCH 1/9] [python] fix #18774 Deserialize on basic str fails --- .../main/resources/python/api_client.mustache | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index 97b8f8d84c72..a75f6d8f1cf3 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -322,10 +322,7 @@ class ApiClient: match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" response_text = response_data.data.decode(encoding) - if response_type in ["bytearray", "str"]: - return_data = self.__deserialize_primitive(response_text, response_type) - else: - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -393,21 +390,32 @@ class ApiClient: for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith('application/json'): data = json.loads(response_text) - except ValueError: + elif content_type.startswith('text/plain'): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) From 952bacd212d787c6f20d7e0a84f3b06799df74d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 03:01:32 +0000 Subject: [PATCH 2/9] [python] update sample --- .../openapi_client/api_client.py | 22 +++++++++++++------ .../python/openapi_client/api_client.py | 22 +++++++++++++------ .../python-aiohttp/petstore_api/api_client.py | 22 +++++++++++++------ .../python/petstore_api/api_client.py | 22 +++++++++++++------ 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py index 5e39f780d88a..2d78998b0f42 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py @@ -315,10 +315,7 @@ def response_deserialize( match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" response_text = response_data.data.decode(encoding) - if response_type in ["bytearray", "str"]: - return_data = self.__deserialize_primitive(response_text, response_type) - else: - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -386,21 +383,32 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith('application/json'): data = json.loads(response_text) - except ValueError: + elif content_type.startswith('text/plain'): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) diff --git a/samples/client/echo_api/python/openapi_client/api_client.py b/samples/client/echo_api/python/openapi_client/api_client.py index 5e39f780d88a..2d78998b0f42 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -315,10 +315,7 @@ def response_deserialize( match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" response_text = response_data.data.decode(encoding) - if response_type in ["bytearray", "str"]: - return_data = self.__deserialize_primitive(response_text, response_type) - else: - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -386,21 +383,32 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith('application/json'): data = json.loads(response_text) - except ValueError: + elif content_type.startswith('text/plain'): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py index 991b0d96cc1d..5aa9e52fd682 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py @@ -317,10 +317,7 @@ def response_deserialize( match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" response_text = response_data.data.decode(encoding) - if response_type in ["bytearray", "str"]: - return_data = self.__deserialize_primitive(response_text, response_type) - else: - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -388,21 +385,32 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith('application/json'): data = json.loads(response_text) - except ValueError: + elif content_type.startswith('text/plain'): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 7e17903a95fd..00d8d5a602e3 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -314,10 +314,7 @@ def response_deserialize( match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" response_text = response_data.data.decode(encoding) - if response_type in ["bytearray", "str"]: - return_data = self.__deserialize_primitive(response_text, response_type) - else: - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -385,21 +382,32 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith('application/json'): data = json.loads(response_text) - except ValueError: + elif content_type.startswith('text/plain'): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) From b49bce1027330cd36dbae08e093cb6696d28a966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 03:02:23 +0000 Subject: [PATCH 3/9] [python] update test --- .../client/petstore/python/tests/test_api.py | 6 ++++ .../python/tests/test_deserialization.py | 30 +++++++++---------- .../petstore/python/tests/test_fake_api.py | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/samples/openapi3/client/petstore/python/tests/test_api.py b/samples/openapi3/client/petstore/python/tests/test_api.py index 8237969c4943..643e0fc61b5e 100644 --- a/samples/openapi3/client/petstore/python/tests/test_api.py +++ b/samples/openapi3/client/petstore/python/tests/test_api.py @@ -53,6 +53,9 @@ def test_400(self): mock_resp.data = json.dumps({"reason400": "400 reason"}).encode("utf-8") mock_resp.getheaders.return_value = {} mock_resp.getheader.return_value = "" + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) with patch( "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp @@ -71,6 +74,9 @@ def test_404(self): mock_resp.data = json.dumps({"reason404": "404 reason"}).encode("utf-8") mock_resp.getheaders.return_value = {} mock_resp.getheader.return_value = "" + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) with patch( "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp diff --git a/samples/openapi3/client/petstore/python/tests/test_deserialization.py b/samples/openapi3/client/petstore/python/tests/test_deserialization.py index 08e09edea265..8fd654e4bb74 100644 --- a/samples/openapi3/client/petstore/python/tests/test_deserialization.py +++ b/samples/openapi3/client/petstore/python/tests/test_deserialization.py @@ -39,7 +39,7 @@ def test_enum_test(self): } response = json.dumps(data) - deserialized = self.deserialize(response, 'Dict[str, EnumTest]') + deserialized = self.deserialize(response, 'Dict[str, EnumTest]', 'application/json') self.assertTrue(isinstance(deserialized, dict)) self.assertTrue(isinstance(deserialized['enum_test'], petstore_api.EnumTest)) self.assertEqual(deserialized['enum_test'], @@ -73,7 +73,7 @@ def test_deserialize_dict_str_pet(self): } response = json.dumps(data) - deserialized = self.deserialize(response, 'Dict[str, Pet]') + deserialized = self.deserialize(response, 'Dict[str, Pet]', 'application/json') self.assertTrue(isinstance(deserialized, dict)) self.assertTrue(isinstance(deserialized['pet'], petstore_api.Pet)) @@ -90,7 +90,7 @@ def test_deserialize_dict_str_dog(self): } response = json.dumps(data) - deserialized = self.deserialize(response, 'Dict[str, Animal]') + deserialized = self.deserialize(response, 'Dict[str, Animal]', 'application/json') self.assertTrue(isinstance(deserialized, dict)) self.assertTrue(isinstance(deserialized['dog'], petstore_api.Dog)) @@ -102,7 +102,7 @@ def test_deserialize_dict_str_int(self): } response = json.dumps(data) - deserialized = self.deserialize(response, 'Dict[str, int]') + deserialized = self.deserialize(response, 'Dict[str, int]', 'application/json') self.assertTrue(isinstance(deserialized, dict)) self.assertTrue(isinstance(deserialized['integer'], int)) @@ -111,7 +111,7 @@ def test_deserialize_str(self): data = "test str" response = data=json.dumps(data) - deserialized = self.deserialize(response, "str") + deserialized = self.deserialize(response, "str", 'application/json') self.assertTrue(isinstance(deserialized, str)) def test_deserialize_date(self): @@ -119,7 +119,7 @@ def test_deserialize_date(self): data = "1997-07-16" response = data=json.dumps(data) - deserialized = self.deserialize(response, "date") + deserialized = self.deserialize(response, "date", 'application/json') self.assertTrue(isinstance(deserialized, datetime.date)) def test_deserialize_datetime(self): @@ -127,7 +127,7 @@ def test_deserialize_datetime(self): data = "1997-07-16T19:20:30.45+01:00" response = json.dumps(data) - deserialized = self.deserialize(response, "datetime") + deserialized = self.deserialize(response, "datetime", 'application/json') self.assertTrue(isinstance(deserialized, datetime.datetime)) def test_deserialize_pet(self): @@ -152,7 +152,7 @@ def test_deserialize_pet(self): } response = json.dumps(data) - deserialized = self.deserialize(response, "Pet") + deserialized = self.deserialize(response, "Pet", 'application/json') self.assertTrue(isinstance(deserialized, petstore_api.Pet)) self.assertEqual(deserialized.id, 0) self.assertEqual(deserialized.name, "doggie") @@ -202,7 +202,7 @@ def test_deserialize_list_of_pet(self): }] response = json.dumps(data) - deserialized = self.deserialize(response, "List[Pet]") + deserialized = self.deserialize(response, "List[Pet]", 'application/json') self.assertTrue(isinstance(deserialized, list)) self.assertTrue(isinstance(deserialized[0], petstore_api.Pet)) self.assertEqual(deserialized[0].id, 0) @@ -219,7 +219,7 @@ def test_deserialize_nested_dict(self): } response = json.dumps(data) - deserialized = self.deserialize(response, "Dict[str, Dict[str, int]]") + deserialized = self.deserialize(response, "Dict[str, Dict[str, int]]", 'application/json') self.assertTrue(isinstance(deserialized, dict)) self.assertTrue(isinstance(deserialized["foo"], dict)) self.assertTrue(isinstance(deserialized["foo"]["bar"], int)) @@ -229,7 +229,7 @@ def test_deserialize_nested_list(self): data = [["foo"]] response = json.dumps(data) - deserialized = self.deserialize(response, "List[List[str]]") + deserialized = self.deserialize(response, "List[List[str]]", 'application/json') self.assertTrue(isinstance(deserialized, list)) self.assertTrue(isinstance(deserialized[0], list)) self.assertTrue(isinstance(deserialized[0][0], str)) @@ -238,7 +238,7 @@ def test_deserialize_none(self): """ deserialize None """ response = json.dumps(None) - deserialized = self.deserialize(response, "datetime") + deserialized = self.deserialize(response, "datetime", 'application/json') self.assertIsNone(deserialized) def test_deserialize_pig(self): @@ -249,7 +249,7 @@ def test_deserialize_pig(self): } response = json.dumps(data) - deserialized = self.deserialize(response, "Pig") + deserialized = self.deserialize(response, "Pig", 'application/json') self.assertTrue(isinstance(deserialized.actual_instance, petstore_api.BasquePig)) self.assertEqual(deserialized.actual_instance.class_name, "BasqueBig") @@ -265,7 +265,7 @@ def test_deserialize_animal(self): response = json.dumps(data) with pytest.raises(ValueError) as ex: - deserialized = self.deserialize(response, "Animal") + deserialized = self.deserialize(response, "Animal", 'application/json') assert str( ex.value) == 'Animal failed to lookup discriminator value from {"declawed": true, "className": ' \ '"Cat2222"}. Discriminator property name: className, mapping: {"Cat": "Cat", "Dog": "Dog"}' @@ -277,7 +277,7 @@ def test_deserialize_animal(self): response = json.dumps(data) - deserialized = self.deserialize(response, "Animal") + deserialized = self.deserialize(response, "Animal", 'application/json') self.assertTrue(isinstance(deserialized, petstore_api.Cat)) self.assertEqual(deserialized.class_name, "Cat") self.assertEqual(deserialized.declawed, True) diff --git a/samples/openapi3/client/petstore/python/tests/test_fake_api.py b/samples/openapi3/client/petstore/python/tests/test_fake_api.py index dec2dcb4954b..363eaed7aa29 100644 --- a/samples/openapi3/client/petstore/python/tests/test_fake_api.py +++ b/samples/openapi3/client/petstore/python/tests/test_fake_api.py @@ -155,7 +155,7 @@ def testIntEnumReturnsValue(self): mock_resp.data = b'{"value": "0"}' mock_resp.getheaders.return_value = {} mock_resp.getheader = ( - lambda name: "text/plain" if name == "content-type" else Mock() + lambda name: "application/json" if name == "content-type" else Mock() ) with patch( "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp From 965d7d4dc1434a7c884eaecdb4789b6c750262e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 03:12:22 +0000 Subject: [PATCH 4/9] [python] remove type --- .../src/main/resources/python/api_client.mustache | 2 +- .../openapi_client/api_client.py | 2 +- samples/client/echo_api/python/openapi_client/api_client.py | 2 +- .../client/petstore/python-aiohttp/petstore_api/api_client.py | 2 +- .../openapi3/client/petstore/python/petstore_api/api_client.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index a75f6d8f1cf3..392e004ad2a9 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -390,7 +390,7 @@ class ApiClient: for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: + def deserialize(self, response_text: str, response_type: str, content_type: str): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py index 2d78998b0f42..b96658058497 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py @@ -383,7 +383,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: + def deserialize(self, response_text: str, response_type: str, content_type: str): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. diff --git a/samples/client/echo_api/python/openapi_client/api_client.py b/samples/client/echo_api/python/openapi_client/api_client.py index 2d78998b0f42..b96658058497 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -383,7 +383,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: + def deserialize(self, response_text: str, response_type: str, content_type: str): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py index 5aa9e52fd682..4e190eeb6a26 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py @@ -385,7 +385,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: + def deserialize(self, response_text: str, response_type: str, content_type: str): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 00d8d5a602e3..1d0507bd9769 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -382,7 +382,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str) -> ApiResponseT: + def deserialize(self, response_text: str, response_type: str, content_type: str): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. From bdda14247cb31621bed4e955d39b96735106cd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 03:18:07 +0000 Subject: [PATCH 5/9] [python] fix test --- .../tests/test_manual.py | 5 +---- samples/client/echo_api/python/tests/test_manual.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py index 4fbe46dd563e..1a5d0bb4d83f 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py @@ -113,15 +113,12 @@ def testBodyParameter(self): n = openapi_client.Pet.from_dict({"name": "testing", "photoUrls": ["http://1", "http://2"]}) api_instance = openapi_client.BodyApi() api_response = api_instance.test_echo_body_pet_response_string(n) - self.assertEqual(api_response, '{"name": "testing", "photoUrls": ["http://1", "http://2"]}') + self.assertEqual(api_response, "{'name': 'testing', 'photoUrls': ['http://1', 'http://2']}") t = openapi_client.Tag() api_response = api_instance.test_echo_body_tag_response_string(t) self.assertEqual(api_response, "{}") # assertion to ensure {} is sent in the body - api_response = api_instance.test_echo_body_tag_response_string(None) - self.assertEqual(api_response, "") # assertion to ensure emtpy string is sent in the body - api_response = api_instance.test_echo_body_free_form_object_response_string({}) self.assertEqual(api_response, "{}") # assertion to ensure {} is sent in the body diff --git a/samples/client/echo_api/python/tests/test_manual.py b/samples/client/echo_api/python/tests/test_manual.py index 42ae3aafd85e..8311f87eb2a3 100644 --- a/samples/client/echo_api/python/tests/test_manual.py +++ b/samples/client/echo_api/python/tests/test_manual.py @@ -174,15 +174,12 @@ def testBodyParameter(self): n = openapi_client.Pet.from_dict({"name": "testing", "photoUrls": ["http://1", "http://2"]}) api_instance = openapi_client.BodyApi() api_response = api_instance.test_echo_body_pet_response_string(n) - self.assertEqual(api_response, '{"name": "testing", "photoUrls": ["http://1", "http://2"]}') + self.assertEqual(api_response, "{'name': 'testing', 'photoUrls': ['http://1', 'http://2']}") t = openapi_client.Tag() api_response = api_instance.test_echo_body_tag_response_string(t) self.assertEqual(api_response, "{}") # assertion to ensure {} is sent in the body - api_response = api_instance.test_echo_body_tag_response_string(None) - self.assertEqual(api_response, "") # assertion to ensure emtpy string is sent in the body - api_response = api_instance.test_echo_body_free_form_object_response_string({}) self.assertEqual(api_response, "{}") # assertion to ensure {} is sent in the body From 8d943de4f270dfb0e2b4021802d1bcf11936e225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 04:13:35 +0000 Subject: [PATCH 6/9] [python] add top level type test --- .../petstore/python/tests/test_fake_api.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/samples/openapi3/client/petstore/python/tests/test_fake_api.py b/samples/openapi3/client/petstore/python/tests/test_fake_api.py index 363eaed7aa29..eade99256c5f 100644 --- a/samples/openapi3/client/petstore/python/tests/test_fake_api.py +++ b/samples/openapi3/client/petstore/python/tests/test_fake_api.py @@ -165,3 +165,78 @@ def testIntEnumReturnsValue(self): param=[OuterEnumInteger.NUMBER_0]) self.assertEqual(call_api_mock.call_args[0][1], 'http://petstore.swagger.io:80/v2/fake/property/enum-int?param=0') + + def testTopLevelStrJson(self): + """Test TopLevelStrJson""" + mock_resp = Mock() + mock_resp.status = 200 + mock_resp.data = b'"a"' + mock_resp.getheaders.return_value = {} + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) + with patch( + "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp + ): + returned = self.fake_api.fake_return_string() + self.assertEqual('a', returned) + + def testTopLevelIntJson(self): + """Test TopLevelIntJson""" + mock_resp = Mock() + mock_resp.status = 200 + mock_resp.data = b'1' + mock_resp.getheaders.return_value = {} + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) + with patch( + "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp + ): + returned = self.fake_api.fake_return_int() + self.assertEqual(1, returned) + + def testTopLevelFloatJson(self): + """Test TopLevelFloatJson""" + mock_resp = Mock() + mock_resp.status = 200 + mock_resp.data = b'3.4' + mock_resp.getheaders.return_value = {} + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) + with patch( + "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp + ): + returned = self.fake_api.fake_return_float() + self.assertEqual(3.4, returned) + + def testTopLevelBoolJson(self): + """Test TopLevelBoolJson""" + mock_resp = Mock() + mock_resp.status = 200 + mock_resp.data = b'true' + mock_resp.getheaders.return_value = {} + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) + with patch( + "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp + ): + returned = self.fake_api.fake_return_boolean() + self.assertEqual(True, returned) + + def testTopLevelEnumJson(self): + """Test TopLevelEnumJson""" + mock_resp = Mock() + mock_resp.status = 200 + mock_resp.data = b'"a"' + mock_resp.getheaders.return_value = {} + mock_resp.getheader = ( + lambda name: "application/json" if name == "content-type" else Mock() + ) + with patch( + "petstore_api.api_client.ApiClient.call_api", return_value=mock_resp + ): + returned = self.fake_api.fake_return_enum() + self.assertEqual("a", returned) From 581b347a9e75c21500a5a2972496801f393e5f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Fri, 31 May 2024 06:42:48 +0000 Subject: [PATCH 7/9] Update deserialize content_type parameter and quote --- .../src/main/resources/python/api_client.mustache | 6 +++--- .../openapi_client/api_client.py | 6 +++--- samples/client/echo_api/python/openapi_client/api_client.py | 6 +++--- .../petstore/python-aiohttp/petstore_api/api_client.py | 6 +++--- .../client/petstore/python/petstore_api/api_client.py | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index 392e004ad2a9..b7bf2583fe8b 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -390,7 +390,7 @@ class ApiClient: for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. @@ -407,9 +407,9 @@ class ApiClient: data = json.loads(response_text) except ValueError: data = response_text - elif content_type.startswith('application/json'): + elif content_type.startswith("application/json"): data = json.loads(response_text) - elif content_type.startswith('text/plain'): + elif content_type.startswith("text/plain"): data = response_text else: raise ApiException( diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py index b96658058497..fc76c0cd7f12 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py @@ -383,7 +383,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. @@ -400,9 +400,9 @@ def deserialize(self, response_text: str, response_type: str, content_type: str) data = json.loads(response_text) except ValueError: data = response_text - elif content_type.startswith('application/json'): + elif content_type.startswith("application/json"): data = json.loads(response_text) - elif content_type.startswith('text/plain'): + elif content_type.startswith("text/plain"): data = response_text else: raise ApiException( diff --git a/samples/client/echo_api/python/openapi_client/api_client.py b/samples/client/echo_api/python/openapi_client/api_client.py index b96658058497..fc76c0cd7f12 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -383,7 +383,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. @@ -400,9 +400,9 @@ def deserialize(self, response_text: str, response_type: str, content_type: str) data = json.loads(response_text) except ValueError: data = response_text - elif content_type.startswith('application/json'): + elif content_type.startswith("application/json"): data = json.loads(response_text) - elif content_type.startswith('text/plain'): + elif content_type.startswith("text/plain"): data = response_text else: raise ApiException( diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py index 4e190eeb6a26..fe4f8f0cabb3 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py @@ -385,7 +385,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. @@ -402,9 +402,9 @@ def deserialize(self, response_text: str, response_type: str, content_type: str) data = json.loads(response_text) except ValueError: data = response_text - elif content_type.startswith('application/json'): + elif content_type.startswith("application/json"): data = json.loads(response_text) - elif content_type.startswith('text/plain'): + elif content_type.startswith("text/plain"): data = response_text else: raise ApiException( diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 1d0507bd9769..063956f4ee44 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -382,7 +382,7 @@ def sanitize_for_serialization(self, obj): for key, val in obj_dict.items() } - def deserialize(self, response_text: str, response_type: str, content_type: str): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. @@ -399,9 +399,9 @@ def deserialize(self, response_text: str, response_type: str, content_type: str) data = json.loads(response_text) except ValueError: data = response_text - elif content_type.startswith('application/json'): + elif content_type.startswith("application/json"): data = json.loads(response_text) - elif content_type.startswith('text/plain'): + elif content_type.startswith("text/plain"): data = response_text else: raise ApiException( From 334a7d0e1c3767e98446fb037a4d9fa670af4015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Wed, 5 Jun 2024 03:39:31 +0000 Subject: [PATCH 8/9] [python] restore echo_api test --- samples/client/echo_api/python/tests/test_manual.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/client/echo_api/python/tests/test_manual.py b/samples/client/echo_api/python/tests/test_manual.py index 8311f87eb2a3..e3a3771832a2 100644 --- a/samples/client/echo_api/python/tests/test_manual.py +++ b/samples/client/echo_api/python/tests/test_manual.py @@ -182,6 +182,9 @@ def testBodyParameter(self): api_response = api_instance.test_echo_body_free_form_object_response_string({}) self.assertEqual(api_response, "{}") # assertion to ensure {} is sent in the body + + api_response = api_instance.test_echo_body_tag_response_string(None) + self.assertEqual(api_response, "") # assertion to ensure emtpy string is sent in the body def testAuthHttpBasic(self): api_instance = openapi_client.AuthApi() From e77545e7aa0e28ce6cf383c22e58b9ecf9850434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=81=81?= Date: Thu, 6 Jun 2024 05:17:31 +0000 Subject: [PATCH 9/9] [python] add allow empty json in Response --- .../src/main/resources/python/api_client.mustache | 5 ++++- .../openapi_client/api_client.py | 5 ++++- samples/client/echo_api/python/openapi_client/api_client.py | 5 ++++- .../petstore/python-aiohttp/petstore_api/api_client.py | 5 ++++- .../client/petstore/python/petstore_api/api_client.py | 5 ++++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/api_client.mustache b/modules/openapi-generator/src/main/resources/python/api_client.mustache index b7bf2583fe8b..4d1d789e4e85 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -408,7 +408,10 @@ class ApiClient: except ValueError: data = response_text elif content_type.startswith("application/json"): - data = json.loads(response_text) + if response_text == "": + data = "" + else: + data = json.loads(response_text) elif content_type.startswith("text/plain"): data = response_text else: diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py index fc76c0cd7f12..2d5d7b55ad7d 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api_client.py @@ -401,7 +401,10 @@ def deserialize(self, response_text: str, response_type: str, content_type: Opti except ValueError: data = response_text elif content_type.startswith("application/json"): - data = json.loads(response_text) + if response_text == "": + data = "" + else: + data = json.loads(response_text) elif content_type.startswith("text/plain"): data = response_text else: diff --git a/samples/client/echo_api/python/openapi_client/api_client.py b/samples/client/echo_api/python/openapi_client/api_client.py index fc76c0cd7f12..2d5d7b55ad7d 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -401,7 +401,10 @@ def deserialize(self, response_text: str, response_type: str, content_type: Opti except ValueError: data = response_text elif content_type.startswith("application/json"): - data = json.loads(response_text) + if response_text == "": + data = "" + else: + data = json.loads(response_text) elif content_type.startswith("text/plain"): data = response_text else: diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py index fe4f8f0cabb3..5766c2842237 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api_client.py @@ -403,7 +403,10 @@ def deserialize(self, response_text: str, response_type: str, content_type: Opti except ValueError: data = response_text elif content_type.startswith("application/json"): - data = json.loads(response_text) + if response_text == "": + data = "" + else: + data = json.loads(response_text) elif content_type.startswith("text/plain"): data = response_text else: diff --git a/samples/openapi3/client/petstore/python/petstore_api/api_client.py b/samples/openapi3/client/petstore/python/petstore_api/api_client.py index 063956f4ee44..c4dbcb450a7b 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -400,7 +400,10 @@ def deserialize(self, response_text: str, response_type: str, content_type: Opti except ValueError: data = response_text elif content_type.startswith("application/json"): - data = json.loads(response_text) + if response_text == "": + data = "" + else: + data = json.loads(response_text) elif content_type.startswith("text/plain"): data = response_text else: