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 eef8edc60de5..874d9cd3efef 100644 --- a/modules/openapi-generator/src/main/resources/python/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/python/api_client.mustache @@ -591,6 +591,12 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" 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 cf6c5499750e..17c439964cee 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 @@ -440,6 +440,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" 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 cf6c5499750e..17c439964cee 100644 --- a/samples/client/echo_api/python/openapi_client/api_client.py +++ b/samples/client/echo_api/python/openapi_client/api_client.py @@ -440,6 +440,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py index d9538b2c5e36..baab728d4dd5 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/api_client.py @@ -548,6 +548,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" 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 51dedc06d75c..49b32fc8edd6 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 @@ -439,6 +439,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py index 439f7b281e22..b7eb3a9170cb 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api_client.py @@ -442,6 +442,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py index 439f7b281e22..b7eb3a9170cb 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/api_client.py @@ -442,6 +442,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py index 2712a55fb468..8dcae18708cf 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api_client.py @@ -439,6 +439,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" 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 e790556da632..899983e443d6 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api_client.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api_client.py @@ -439,6 +439,12 @@ def __deserialize(self, data, klass): return None if isinstance(klass, str): + if klass.startswith('Optional['): + m = re.match(r'Optional\[(.*)]', klass) + assert m is not None, "Malformed Optional type definition" + # data is not None here, so the optionality is already resolved + return self.__deserialize(data, m.group(1)) + if klass.startswith('List['): m = re.match(r'List\[(.*)]', klass) assert m is not None, "Malformed List type definition" diff --git a/samples/openapi3/client/petstore/python/tests/test_deserialization.py b/samples/openapi3/client/petstore/python/tests/test_deserialization.py index b3626e5cc9cb..ba9d9521599b 100644 --- a/samples/openapi3/client/petstore/python/tests/test_deserialization.py +++ b/samples/openapi3/client/petstore/python/tests/test_deserialization.py @@ -251,6 +251,59 @@ def test_deserialize_none(self): deserialized = self.deserialize(response, "datetime", 'application/json') self.assertIsNone(deserialized) + def test_deserialize_optional_dict_str_object(self): + """ deserialize Dict[str, Optional[object]] """ + data = { + "foo": 1, + "bar": None + } + response = json.dumps(data) + + deserialized = self.deserialize(response, "Dict[str, Optional[object]]", 'application/json') + self.assertEqual(deserialized, {"foo": 1, "bar": None}) + + def test_deserialize_optional_pet(self): + """ deserialize Optional[Pet] """ + data = { + "id": 0, + "category": { + "id": 0, + "name": "string" + }, + "name": "doggie", + "photoUrls": [ + "string" + ], + "tags": [ + { + "id": 0, + "name": "string" + } + ], + "status": "available" + } + response = json.dumps(data) + + deserialized = self.deserialize(response, "Optional[Pet]", 'application/json') + self.assertTrue(isinstance(deserialized, petstore_api.Pet)) + self.assertEqual(deserialized.id, 0) + self.assertEqual(deserialized.name, "doggie") + + def test_deserialize_optional_list_of_str(self): + """ deserialize Optional[List[str]] """ + data = ["foo", "bar"] + response = json.dumps(data) + + deserialized = self.deserialize(response, "Optional[List[str]]", 'application/json') + self.assertEqual(deserialized, ["foo", "bar"]) + + def test_deserialize_optional_none(self): + """ deserialize Optional[Pet] when the body is null """ + response = json.dumps(None) + + deserialized = self.deserialize(response, "Optional[Pet]", 'application/json') + self.assertIsNone(deserialized) + def test_deserialize_pig(self): """ deserialize pig (oneOf) """ wire_name = """class'"\\Name"""