From fa37a696a8efe84c6110e73f9592ccfe3d3bcf43 Mon Sep 17 00:00:00 2001 From: Sebastien Rosset Date: Sun, 10 May 2020 19:02:41 -0700 Subject: [PATCH] [python-experimental] Raise builtin AttributeError instead of custom ApiKeyError (#6229) * Use AttributeError instead of ApiKeyError because that's what the hasattr builtin function uses * Use AttributeError instead of ApiKeyError because that's what the hasattr builtin function uses * fix unit tests * create ApiAttributeError exception * fix formatting * run samples scripts --- .../resources/python/__init__package.mustache | 1 + .../main/resources/python/exceptions.mustache | 19 ++++++++++++++ .../method_set_attribute.mustache | 5 ++-- .../methods_setattr_getattr_composed.mustache | 10 ++++--- .../methods_setattr_getattr_normal.mustache | 5 ++-- .../python-experimental/model_utils.mustache | 1 + .../python-asyncio/petstore_api/__init__.py | 1 + .../python-asyncio/petstore_api/exceptions.py | 19 ++++++++++++++ .../petstore_api/exceptions.py | 19 ++++++++++++++ .../petstore_api/model_utils.py | 26 ++++++++++++------- .../python-experimental/test/test_child.py | 15 +++++++---- .../python-experimental/test/test_dog.py | 12 +++++---- .../tests/test_enum_arrays.py | 4 +-- .../python-tornado/petstore_api/__init__.py | 1 + .../python-tornado/petstore_api/exceptions.py | 19 ++++++++++++++ .../petstore/python/petstore_api/__init__.py | 1 + .../python/petstore_api/exceptions.py | 19 ++++++++++++++ .../petstore_api/exceptions.py | 19 ++++++++++++++ .../petstore_api/model_utils.py | 26 ++++++++++++------- .../python-experimental/test/test_fruit.py | 26 +++++++++++++++---- .../test/test_fruit_req.py | 12 +++++---- .../python-experimental/test/test_gm_fruit.py | 12 +++++---- .../petstore/python/petstore_api/__init__.py | 1 + .../python/petstore_api/exceptions.py | 19 ++++++++++++++ 24 files changed, 237 insertions(+), 55 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/__init__package.mustache b/modules/openapi-generator/src/main/resources/python/__init__package.mustache index 72376acdc3b..aee16448ad8 100644 --- a/modules/openapi-generator/src/main/resources/python/__init__package.mustache +++ b/modules/openapi-generator/src/main/resources/python/__init__package.mustache @@ -18,6 +18,7 @@ from {{packageName}}.exceptions import OpenApiException from {{packageName}}.exceptions import ApiTypeError from {{packageName}}.exceptions import ApiValueError from {{packageName}}.exceptions import ApiKeyError +from {{packageName}}.exceptions import ApiAttributeError from {{packageName}}.exceptions import ApiException # import models into sdk package {{#models}}{{#model}}from {{modelPackage}}.{{classFilename}} import {{classname}} diff --git a/modules/openapi-generator/src/main/resources/python/exceptions.mustache b/modules/openapi-generator/src/main/resources/python/exceptions.mustache index dd012f34a05..b187ee9d47e 100644 --- a/modules/openapi-generator/src/main/resources/python/exceptions.mustache +++ b/modules/openapi-generator/src/main/resources/python/exceptions.mustache @@ -56,6 +56,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/method_set_attribute.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/method_set_attribute.mustache index f4a36e42f25..15067fff80a 100644 --- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/method_set_attribute.mustache +++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/method_set_attribute.mustache @@ -9,8 +9,9 @@ if name in self.openapi_types: required_types_mixed = self.openapi_types[name] elif self.additional_properties_type is None: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif self.additional_properties_type is not None: diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_composed.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_composed.mustache index 9420fe1582c..dd118d30f91 100644 --- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_composed.mustache +++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_composed.mustache @@ -24,8 +24,9 @@ if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) @@ -54,8 +55,9 @@ values.append(v) len_values = len(values) if len_values == 0: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif len_values == 1: diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_normal.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_normal.mustache index f92663ab208..9fc63449089 100644 --- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_normal.mustache +++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_setattr_getattr_normal.mustache @@ -18,7 +18,8 @@ if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), [name] ) \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_utils.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_utils.mustache index e6b1df6b0e9..0be7362f6f6 100644 --- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_utils.mustache +++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_utils.mustache @@ -14,6 +14,7 @@ import six from {{packageName}}.exceptions import ( ApiKeyError, + ApiAttributeError, ApiTypeError, ApiValueError, ) diff --git a/samples/client/petstore/python-asyncio/petstore_api/__init__.py b/samples/client/petstore/python-asyncio/petstore_api/__init__.py index 513eaf779de..b9fdaf07ac1 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/__init__.py +++ b/samples/client/petstore/python-asyncio/petstore_api/__init__.py @@ -31,6 +31,7 @@ from petstore_api.exceptions import OpenApiException from petstore_api.exceptions import ApiTypeError from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiKeyError +from petstore_api.exceptions import ApiAttributeError from petstore_api.exceptions import ApiException # import models into sdk package from petstore_api.models.additional_properties_any_type import AdditionalPropertiesAnyType diff --git a/samples/client/petstore/python-asyncio/petstore_api/exceptions.py b/samples/client/petstore/python-asyncio/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/exceptions.py +++ b/samples/client/petstore/python-asyncio/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/samples/client/petstore/python-experimental/petstore_api/exceptions.py b/samples/client/petstore/python-experimental/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/client/petstore/python-experimental/petstore_api/exceptions.py +++ b/samples/client/petstore/python-experimental/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/samples/client/petstore/python-experimental/petstore_api/model_utils.py b/samples/client/petstore/python-experimental/petstore_api/model_utils.py index 519b5f7a5ed..385866c214a 100644 --- a/samples/client/petstore/python-experimental/petstore_api/model_utils.py +++ b/samples/client/petstore/python-experimental/petstore_api/model_utils.py @@ -22,6 +22,7 @@ import six from petstore_api.exceptions import ( ApiKeyError, + ApiAttributeError, ApiTypeError, ApiValueError, ) @@ -75,8 +76,9 @@ class OpenApiModel(object): if name in self.openapi_types: required_types_mixed = self.openapi_types[name] elif self.additional_properties_type is None: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif self.additional_properties_type is not None: @@ -204,8 +206,9 @@ class ModelSimple(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), [name] ) @@ -257,8 +260,9 @@ class ModelNormal(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), [name] ) @@ -323,8 +327,9 @@ class ModelComposed(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) @@ -353,8 +358,9 @@ class ModelComposed(OpenApiModel): values.append(v) len_values = len(values) if len_values == 0: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif len_values == 1: diff --git a/samples/client/petstore/python-experimental/test/test_child.py b/samples/client/petstore/python-experimental/test/test_child.py index 43f1341b923..660cfe637d9 100644 --- a/samples/client/petstore/python-experimental/test/test_child.py +++ b/samples/client/petstore/python-experimental/test/test_child.py @@ -64,19 +64,24 @@ class TestChild(unittest.TestCase): # setting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): child['invalid_variable'] = 'some value' # with setattr - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): setattr(child, 'invalid_variable', 'some value') + # with hasattr + self.assertFalse(hasattr(child, 'invalid_variable')) + # getting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): invalid_variable = child['invalid_variable'] # with getattr - with self.assertRaises(petstore_api.ApiKeyError): - invalid_variable = getattr(child, 'invalid_variable', 'some value') + self.assertEquals(getattr(child, 'invalid_variable', 'some value'), 'some value') + + with self.assertRaises(AttributeError): + invalid_variable = getattr(child, 'invalid_variable') # make sure that the ModelComposed class properties are correct # model.composed_schemas() stores the anyOf/allOf/oneOf info diff --git a/samples/client/petstore/python-experimental/test/test_dog.py b/samples/client/petstore/python-experimental/test/test_dog.py index cc165d8b27d..91f9318b9c6 100644 --- a/samples/client/petstore/python-experimental/test/test_dog.py +++ b/samples/client/petstore/python-experimental/test/test_dog.py @@ -64,19 +64,21 @@ class TestDog(unittest.TestCase): # setting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): dog['invalid_variable'] = 'some value' # with setattr - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): setattr(dog, 'invalid_variable', 'some value') # getting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): invalid_variable = dog['invalid_variable'] # with getattr - with self.assertRaises(petstore_api.ApiKeyError): - invalid_variable = getattr(dog, 'invalid_variable', 'some value') + self.assertEquals(getattr(dog, 'invalid_variable', 'some value'), 'some value') + + with self.assertRaises(AttributeError): + invalid_variable = getattr(dog, 'invalid_variable') # make sure that the ModelComposed class properties are correct # model.composed_schemas() stores the anyOf/allOf/oneOf info diff --git a/samples/client/petstore/python-experimental/tests/test_enum_arrays.py b/samples/client/petstore/python-experimental/tests/test_enum_arrays.py index 9ef5e2532a3..96edf49c43a 100644 --- a/samples/client/petstore/python-experimental/tests/test_enum_arrays.py +++ b/samples/client/petstore/python-experimental/tests/test_enum_arrays.py @@ -30,7 +30,7 @@ class EnumArraysTests(unittest.TestCase): fish_or_crab = petstore_api.EnumArrays(just_symbol=">=") self.assertEqual(fish_or_crab.just_symbol, ">=") # if optional property is unset we raise an exception - with self.assertRaises(ApiKeyError) as exc: + with self.assertRaises(AttributeError) as exc: self.assertEqual(fish_or_crab.array_enum, None) fish_or_crab = petstore_api.EnumArrays(just_symbol="$", array_enum=["fish"]) @@ -152,4 +152,4 @@ class EnumArraysTests(unittest.TestCase): dollar = petstore_api.EnumArrays(just_symbol="$") greater = petstore_api.EnumArrays(just_symbol=">=") - self.assertNotEqual(dollar, greater) \ No newline at end of file + self.assertNotEqual(dollar, greater) diff --git a/samples/client/petstore/python-tornado/petstore_api/__init__.py b/samples/client/petstore/python-tornado/petstore_api/__init__.py index 513eaf779de..b9fdaf07ac1 100644 --- a/samples/client/petstore/python-tornado/petstore_api/__init__.py +++ b/samples/client/petstore/python-tornado/petstore_api/__init__.py @@ -31,6 +31,7 @@ from petstore_api.exceptions import OpenApiException from petstore_api.exceptions import ApiTypeError from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiKeyError +from petstore_api.exceptions import ApiAttributeError from petstore_api.exceptions import ApiException # import models into sdk package from petstore_api.models.additional_properties_any_type import AdditionalPropertiesAnyType diff --git a/samples/client/petstore/python-tornado/petstore_api/exceptions.py b/samples/client/petstore/python-tornado/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/client/petstore/python-tornado/petstore_api/exceptions.py +++ b/samples/client/petstore/python-tornado/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/samples/client/petstore/python/petstore_api/__init__.py b/samples/client/petstore/python/petstore_api/__init__.py index 513eaf779de..b9fdaf07ac1 100644 --- a/samples/client/petstore/python/petstore_api/__init__.py +++ b/samples/client/petstore/python/petstore_api/__init__.py @@ -31,6 +31,7 @@ from petstore_api.exceptions import OpenApiException from petstore_api.exceptions import ApiTypeError from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiKeyError +from petstore_api.exceptions import ApiAttributeError from petstore_api.exceptions import ApiException # import models into sdk package from petstore_api.models.additional_properties_any_type import AdditionalPropertiesAnyType diff --git a/samples/client/petstore/python/petstore_api/exceptions.py b/samples/client/petstore/python/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/client/petstore/python/petstore_api/exceptions.py +++ b/samples/client/petstore/python/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/samples/openapi3/client/petstore/python-experimental/petstore_api/exceptions.py b/samples/openapi3/client/petstore/python-experimental/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/openapi3/client/petstore/python-experimental/petstore_api/exceptions.py +++ b/samples/openapi3/client/petstore/python-experimental/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """ diff --git a/samples/openapi3/client/petstore/python-experimental/petstore_api/model_utils.py b/samples/openapi3/client/petstore/python-experimental/petstore_api/model_utils.py index 519b5f7a5ed..385866c214a 100644 --- a/samples/openapi3/client/petstore/python-experimental/petstore_api/model_utils.py +++ b/samples/openapi3/client/petstore/python-experimental/petstore_api/model_utils.py @@ -22,6 +22,7 @@ import six from petstore_api.exceptions import ( ApiKeyError, + ApiAttributeError, ApiTypeError, ApiValueError, ) @@ -75,8 +76,9 @@ class OpenApiModel(object): if name in self.openapi_types: required_types_mixed = self.openapi_types[name] elif self.additional_properties_type is None: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif self.additional_properties_type is not None: @@ -204,8 +206,9 @@ class ModelSimple(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), [name] ) @@ -257,8 +260,9 @@ class ModelNormal(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), [name] ) @@ -323,8 +327,9 @@ class ModelComposed(OpenApiModel): if self._path_to_item: path_to_item.extend(self._path_to_item) path_to_item.append(name) - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) @@ -353,8 +358,9 @@ class ModelComposed(OpenApiModel): values.append(v) len_values = len(values) if len_values == 0: - raise ApiKeyError( - "{0} has no key '{1}'".format(type(self).__name__, name), + raise ApiAttributeError( + "{0} has no attribute '{1}'".format( + type(self).__name__, name), path_to_item ) elif len_values == 1: diff --git a/samples/openapi3/client/petstore/python-experimental/test/test_fruit.py b/samples/openapi3/client/petstore/python-experimental/test/test_fruit.py index 3b16da852e3..0c7c047c6ba 100644 --- a/samples/openapi3/client/petstore/python-experimental/test/test_fruit.py +++ b/samples/openapi3/client/petstore/python-experimental/test/test_fruit.py @@ -51,19 +51,35 @@ class TestFruit(unittest.TestCase): ) # setting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): fruit['invalid_variable'] = 'some value' + + # Assert that we can call the builtin hasattr() function. + # hasattr should return False for non-existent attribute. + # Internally hasattr catches the AttributeError exception. + self.assertFalse(hasattr(fruit, 'invalid_variable')) + + # Assert that we can call the builtin hasattr() function. + # hasattr should return True for existent attribute. + self.assertTrue(hasattr(fruit, 'color')) + # with setattr - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): setattr(fruit, 'invalid_variable', 'some value') # getting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): invalid_variable = fruit['cultivar'] # with getattr - with self.assertRaises(petstore_api.ApiKeyError): - invalid_variable = getattr(fruit, 'cultivar', 'some value') + # Per Python doc, if the named attribute does not exist, + # default is returned if provided. + self.assertEquals(getattr(fruit, 'cultivar', 'some value'), 'some value') + + # Per Python doc, if the named attribute does not exist, + # default is returned if provided, otherwise AttributeError is raised. + with self.assertRaises(AttributeError): + getattr(fruit, 'cultivar') # make sure that the ModelComposed class properties are correct # model._composed_schemas stores the anyOf/allOf/oneOf info diff --git a/samples/openapi3/client/petstore/python-experimental/test/test_fruit_req.py b/samples/openapi3/client/petstore/python-experimental/test/test_fruit_req.py index 89905eca750..c1aa9f2255a 100644 --- a/samples/openapi3/client/petstore/python-experimental/test/test_fruit_req.py +++ b/samples/openapi3/client/petstore/python-experimental/test/test_fruit_req.py @@ -46,19 +46,21 @@ class TestFruitReq(unittest.TestCase): ) # setting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): fruit['invalid_variable'] = 'some value' # with setattr - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): setattr(fruit, 'invalid_variable', 'some value') # getting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): invalid_variable = fruit['cultivar'] # with getattr - with self.assertRaises(petstore_api.ApiKeyError): - invalid_variable = getattr(fruit, 'cultivar', 'some value') + self.assertEquals(getattr(fruit, 'cultivar', 'some value'), 'some value') + + with self.assertRaises(AttributeError): + getattr(fruit, 'cultivar') # make sure that the ModelComposed class properties are correct # model._composed_schemas stores the anyOf/allOf/oneOf info diff --git a/samples/openapi3/client/petstore/python-experimental/test/test_gm_fruit.py b/samples/openapi3/client/petstore/python-experimental/test/test_gm_fruit.py index b8e02ed45a7..2e74359f074 100644 --- a/samples/openapi3/client/petstore/python-experimental/test/test_gm_fruit.py +++ b/samples/openapi3/client/petstore/python-experimental/test/test_gm_fruit.py @@ -51,19 +51,21 @@ class TestGmFruit(unittest.TestCase): ) # setting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): fruit['invalid_variable'] = 'some value' # with setattr - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): setattr(fruit, 'invalid_variable', 'some value') # getting a value that doesn't exist raises an exception # with a key - with self.assertRaises(petstore_api.ApiKeyError): + with self.assertRaises(AttributeError): invalid_variable = fruit['cultivar'] # with getattr - with self.assertRaises(petstore_api.ApiKeyError): - invalid_variable = getattr(fruit, 'cultivar', 'some value') + self.assertTrue(getattr(fruit, 'cultivar', 'some value'), 'some value') + + with self.assertRaises(AttributeError): + invalid_variable = getattr(fruit, 'cultivar') # make sure that the ModelComposed class properties are correct # model._composed_schemas stores the anyOf/allOf/oneOf info diff --git a/samples/openapi3/client/petstore/python/petstore_api/__init__.py b/samples/openapi3/client/petstore/python/petstore_api/__init__.py index 830ae0ff6d8..8a91e73ea15 100644 --- a/samples/openapi3/client/petstore/python/petstore_api/__init__.py +++ b/samples/openapi3/client/petstore/python/petstore_api/__init__.py @@ -32,6 +32,7 @@ from petstore_api.exceptions import OpenApiException from petstore_api.exceptions import ApiTypeError from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiKeyError +from petstore_api.exceptions import ApiAttributeError from petstore_api.exceptions import ApiException # import models into sdk package from petstore_api.models.additional_properties_class import AdditionalPropertiesClass diff --git a/samples/openapi3/client/petstore/python/petstore_api/exceptions.py b/samples/openapi3/client/petstore/python/petstore_api/exceptions.py index 100be3e0540..b55977ee5e7 100644 --- a/samples/openapi3/client/petstore/python/petstore_api/exceptions.py +++ b/samples/openapi3/client/petstore/python/petstore_api/exceptions.py @@ -64,6 +64,25 @@ class ApiValueError(OpenApiException, ValueError): super(ApiValueError, self).__init__(full_msg) +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None): + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + class ApiKeyError(OpenApiException, KeyError): def __init__(self, msg, path_to_item=None): """