From f85a23be316ffa829fd04b862c597ce9c6cb632d Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Wed, 21 Oct 2020 06:22:05 -0700
Subject: [PATCH 1/7] add option to return None instead of raising exception
 when accessing unset attribute

---
 .../java/org/openapitools/codegen/CodegenConstants.java  | 3 +++
 .../languages/PythonClientExperimentalCodegen.java       | 9 +++++++++
 .../methods_setattr_getattr_composed.mustache            | 4 ++++
 .../methods_setattr_getattr_normal.mustache              | 5 ++++-
 4 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java
index 38528a6c6fe..04c0888e0a2 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java
@@ -67,6 +67,9 @@ public class CodegenConstants {
     public static final String PYTHON_PACKAGE_NAME = "pythonPackageName";
     public static final String PYTHON_PACKAGE_NAME_DESC = "package name for generated python code";
 
+    public static final String PYTHON_ATTR_NONE_IF_UNSET = "pythonAttrNoneIfUnset";
+    public static final String PYTHON_ATTR_NONE_IF_UNSET_DESC = "when accessing unset attribute, return `None` instead of raising `ApiAttributeError`";
+
     public static final String WITH_GO_CODEGEN_COMMENT = "withGoCodegenComment";
     public static final String WITH_GO_CODEGEN_COMMENT_DESC = "whether to include Go codegen comment to disable Go Lint and collapse by default in GitHub PRs and diffs";
 
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java
index 3ff8c20f406..5d205c9bddf 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java
@@ -122,6 +122,9 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen {
         // optional params/props with **kwargs in python
         cliOptions.remove(4);
 
+        cliOptions.add(new CliOption(CodegenConstants.PYTHON_ATTR_NONE_IF_UNSET, CodegenConstants.PYTHON_ATTR_NONE_IF_UNSET_DESC)
+                .defaultValue(Boolean.FALSE.toString()));
+
         generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
                 .stability(Stability.EXPERIMENTAL)
                 .build();
@@ -209,6 +212,12 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen {
         // default this to true so the python ModelSimple models will be generated
         ModelUtils.setGenerateAliasAsModel(true);
         LOGGER.info(CodegenConstants.GENERATE_ALIAS_AS_MODEL + " is hard coded to true in this generator. Alias models will only be generated if they contain validations or enums");
+
+        Boolean attrNoneIfUnset = false;
+        if (additionalProperties.containsKey(CodegenConstants.PYTHON_ATTR_NONE_IF_UNSET)) {
+            attrNoneIfUnset = Boolean.valueOf(additionalProperties.get(CodegenConstants.PYTHON_ATTR_NONE_IF_UNSET).toString());
+        }
+        additionalProperties.put("attrNoneIfUnset", attrNoneIfUnset);
     }
 
     /**
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 1a01fc472cd..2ca2621d80d 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
@@ -55,11 +55,15 @@
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
+{{#attrNoneIfUnset}}
+            return None
+{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
                 path_to_item
             )
+{{/attrNoneIfUnset}}
         elif len_values == 1:
             return values[0]
         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 32566dc684e..5ecb8171353 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
@@ -10,7 +10,9 @@
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
-
+{{#attrNoneIfUnset}}
+        return self.__dict__['_data_store'].get(name)
+{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}
         if name in self.__dict__['_data_store']:
             return self.__dict__['_data_store'][name]
 
@@ -23,6 +25,7 @@
                 type(self).__name__, name),
             [name]
         )
+{{/attrNoneIfUnset}}
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
-- 
GitLab


From 5b20d7b834fa65db952175464ff485dc91c873e3 Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Wed, 21 Oct 2020 08:29:00 -0700
Subject: [PATCH 2/7] update python samples

---
 .../petstore/python-experimental/petstore_api/model_utils.py     | 1 +
 .../python-experimental/x_auth_id_alias/model_utils.py           | 1 +
 .../python-experimental/dynamic_servers/model_utils.py           | 1 +
 3 files changed, 3 insertions(+)

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 88a7e8ba38b..391ff5cb003 100644
--- a/samples/client/petstore/python-experimental/petstore_api/model_utils.py
+++ b/samples/client/petstore/python-experimental/petstore_api/model_utils.py
@@ -489,6 +489,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
+
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
diff --git a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
index efdb666e7a7..edf1d67cdd8 100644
--- a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
+++ b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
@@ -489,6 +489,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
+
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
diff --git a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
index a5055253417..68926bcf189 100644
--- a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
+++ b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
@@ -489,6 +489,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
+
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
-- 
GitLab


From 62bd01c297b418ff15d095868ea5a38db30b145c Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Wed, 21 Oct 2020 13:36:24 -0700
Subject: [PATCH 3/7] reimplement getattr using getitem or get depending on
 attrNoneIfUnset

---
 docs/generators/python-experimental.md        |  1 +
 .../methods_setattr_getattr_composed.mustache | 38 ++++-----
 .../methods_setattr_getattr_normal.mustache   | 23 +++---
 .../model_templates/methods_shared.mustache   | 13 +--
 .../petstore_api/model_utils.py               | 82 +++++++++----------
 .../x_auth_id_alias/model_utils.py            | 82 +++++++++----------
 .../dynamic_servers/model_utils.py            | 82 +++++++++----------
 .../petstore_api/model_utils.py               | 81 +++++++++---------
 8 files changed, 184 insertions(+), 218 deletions(-)

diff --git a/docs/generators/python-experimental.md b/docs/generators/python-experimental.md
index 309ab81e9a4..e3331950f95 100644
--- a/docs/generators/python-experimental.md
+++ b/docs/generators/python-experimental.md
@@ -14,6 +14,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
 |packageUrl|python package URL.| |null|
 |packageVersion|python package version.| |1.0.0|
 |projectName|python project name in setup.py (e.g. petstore-api).| |null|
+|pythonAttrNoneIfUnset|when accessing unset attribute, return `None` instead of raising `ApiAttributeError`| |false|
 |recursionLimit|Set the recursion limit. If not set, use the system default value.| |null|
 |useNose|use the nose test framework| |false|
 
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 2ca2621d80d..f75284d844a 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
@@ -1,4 +1,4 @@
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -20,17 +20,15 @@
                     )
             return None
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            path_to_item
+            [e for e in [self._path_to_item, name] if e]
         )
 
-    def __getattr__(self, name):
+    __unset_attribute_value__ = object()
+
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
@@ -38,10 +36,6 @@
         # get the attribute from the correct instance
         model_instances = self._var_name_to_model_instances.get(
             name, self._additional_properties_model_instances)
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         values = []
         # A composed model stores child (oneof/anyOf/allOf) models under
         # self._var_name_to_model_instances. A named property can exist in
@@ -55,15 +49,7 @@
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
-{{#attrNoneIfUnset}}
-            return None
-{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
-{{/attrNoneIfUnset}}
+            return default
         elif len_values == 1:
             return values[0]
         elif len_values > 1:
@@ -71,8 +57,18 @@
                 "Values stored for property {0} in {1} differ when looking "
                 "at self and self's composed instances. All values must be "
                 "the same".format(name, type(self).__name__),
-                path_to_item
+                [e for e in [self._path_to_item, name] if e]
+            )
+
+    def __getitem__(self, name):
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
+            raise ApiAttributeError(
+                "{0} has no attribute '{1}'".format(
+                    type(self).__name__, name),
+                    [e for e in [self._path_to_item, name] if e]
             )
+        return value
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
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 5ecb8171353..48c7611622e 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
@@ -1,4 +1,4 @@
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -6,26 +6,23 @@
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
-{{#attrNoneIfUnset}}
-        return self.__dict__['_data_store'].get(name)
-{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
+
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
-{{/attrNoneIfUnset}}
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
index d3cf66e41b6..18036071a30 100644
--- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
+++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
@@ -1,15 +1,10 @@
-    def __setitem__(self, name, value):
-        """this allows us to set values with instance[field_name] = val"""
-        self.__setattr__(name, value)
-
-    def __getitem__(self, name):
-        """this allows us to get a value with val = instance[field_name]"""
-        return self.__getattr__(name)
-
     def __repr__(self):
         """For `print` and `pprint`"""
         return self.to_str()
 
     def __ne__(self, other):
         """Returns true if both objects are not equal"""
-        return not self == other
\ No newline at end of file
+        return not self == other
+
+    __setattr__ = __setitem__
+    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
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 391ff5cb003..90d111d582f 100644
--- a/samples/client/petstore/python-experimental/petstore_api/model_utils.py
+++ b/samples/client/petstore/python-experimental/petstore_api/model_utils.py
@@ -156,14 +156,6 @@ class OpenApiModel(object):
             )
         self.__dict__['_data_store'][name] = value
 
-    def __setitem__(self, name, value):
-        """this allows us to set values with instance[field_name] = val"""
-        self.__setattr__(name, value)
-
-    def __getitem__(self, name):
-        """this allows us to get a value with val = instance[field_name]"""
-        return self.__getattr__(name)
-
     def __repr__(self):
         """For `print` and `pprint`"""
         return self.to_str()
@@ -172,6 +164,9 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
+    __setattr__ = __setitem__
+    __getattr__ = __getitem__
+
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
         # pick a new schema/class to instantiate because a discriminator
@@ -290,7 +285,7 @@ class ModelSimple(OpenApiModel):
     """the parent class of models whose type != object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -298,22 +293,22 @@ class ModelSimple(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -346,7 +341,7 @@ class ModelNormal(OpenApiModel):
     """the parent class of models whose type == object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -354,22 +349,22 @@ class ModelNormal(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -432,7 +427,7 @@ class ModelComposed(OpenApiModel):
     which contain the value that the key is referring to.
     """
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -454,17 +449,15 @@ class ModelComposed(OpenApiModel):
                     )
             return None
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            path_to_item
+            [e for e in [self._path_to_item, name] if e]
         )
 
-    def __getattr__(self, name):
+    __unset_attribute_value__ = object()
+
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
@@ -472,10 +465,6 @@ class ModelComposed(OpenApiModel):
         # get the attribute from the correct instance
         model_instances = self._var_name_to_model_instances.get(
             name, self._additional_properties_model_instances)
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         values = []
         # A composed model stores child (oneof/anyOf/allOf) models under
         # self._var_name_to_model_instances. A named property can exist in
@@ -489,12 +478,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
-
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
+            return default
         elif len_values == 1:
             return values[0]
         elif len_values > 1:
@@ -502,8 +486,18 @@ class ModelComposed(OpenApiModel):
                 "Values stored for property {0} in {1} differ when looking "
                 "at self and self's composed instances. All values must be "
                 "the same".format(name, type(self).__name__),
-                path_to_item
+                [e for e in [self._path_to_item, name] if e]
+            )
+
+    def __getitem__(self, name):
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
+            raise ApiAttributeError(
+                "{0} has no attribute '{1}'".format(
+                    type(self).__name__, name),
+                    [e for e in [self._path_to_item, name] if e]
             )
+        return value
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
diff --git a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
index edf1d67cdd8..f85cabbb386 100644
--- a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
+++ b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
@@ -156,14 +156,6 @@ class OpenApiModel(object):
             )
         self.__dict__['_data_store'][name] = value
 
-    def __setitem__(self, name, value):
-        """this allows us to set values with instance[field_name] = val"""
-        self.__setattr__(name, value)
-
-    def __getitem__(self, name):
-        """this allows us to get a value with val = instance[field_name]"""
-        return self.__getattr__(name)
-
     def __repr__(self):
         """For `print` and `pprint`"""
         return self.to_str()
@@ -172,6 +164,9 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
+    __setattr__ = __setitem__
+    __getattr__ = __getitem__
+
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
         # pick a new schema/class to instantiate because a discriminator
@@ -290,7 +285,7 @@ class ModelSimple(OpenApiModel):
     """the parent class of models whose type != object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -298,22 +293,22 @@ class ModelSimple(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -346,7 +341,7 @@ class ModelNormal(OpenApiModel):
     """the parent class of models whose type == object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -354,22 +349,22 @@ class ModelNormal(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -432,7 +427,7 @@ class ModelComposed(OpenApiModel):
     which contain the value that the key is referring to.
     """
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -454,17 +449,15 @@ class ModelComposed(OpenApiModel):
                     )
             return None
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            path_to_item
+            [e for e in [self._path_to_item, name] if e]
         )
 
-    def __getattr__(self, name):
+    __unset_attribute_value__ = object()
+
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
@@ -472,10 +465,6 @@ class ModelComposed(OpenApiModel):
         # get the attribute from the correct instance
         model_instances = self._var_name_to_model_instances.get(
             name, self._additional_properties_model_instances)
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         values = []
         # A composed model stores child (oneof/anyOf/allOf) models under
         # self._var_name_to_model_instances. A named property can exist in
@@ -489,12 +478,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
-
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
+            return default
         elif len_values == 1:
             return values[0]
         elif len_values > 1:
@@ -502,8 +486,18 @@ class ModelComposed(OpenApiModel):
                 "Values stored for property {0} in {1} differ when looking "
                 "at self and self's composed instances. All values must be "
                 "the same".format(name, type(self).__name__),
-                path_to_item
+                [e for e in [self._path_to_item, name] if e]
+            )
+
+    def __getitem__(self, name):
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
+            raise ApiAttributeError(
+                "{0} has no attribute '{1}'".format(
+                    type(self).__name__, name),
+                    [e for e in [self._path_to_item, name] if e]
             )
+        return value
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
diff --git a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
index 68926bcf189..d14e117354c 100644
--- a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
+++ b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
@@ -156,14 +156,6 @@ class OpenApiModel(object):
             )
         self.__dict__['_data_store'][name] = value
 
-    def __setitem__(self, name, value):
-        """this allows us to set values with instance[field_name] = val"""
-        self.__setattr__(name, value)
-
-    def __getitem__(self, name):
-        """this allows us to get a value with val = instance[field_name]"""
-        return self.__getattr__(name)
-
     def __repr__(self):
         """For `print` and `pprint`"""
         return self.to_str()
@@ -172,6 +164,9 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
+    __setattr__ = __setitem__
+    __getattr__ = __getitem__
+
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
         # pick a new schema/class to instantiate because a discriminator
@@ -290,7 +285,7 @@ class ModelSimple(OpenApiModel):
     """the parent class of models whose type != object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -298,22 +293,22 @@ class ModelSimple(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -346,7 +341,7 @@ class ModelNormal(OpenApiModel):
     """the parent class of models whose type == object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -354,22 +349,22 @@ class ModelNormal(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -432,7 +427,7 @@ class ModelComposed(OpenApiModel):
     which contain the value that the key is referring to.
     """
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -454,17 +449,15 @@ class ModelComposed(OpenApiModel):
                     )
             return None
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            path_to_item
+            [e for e in [self._path_to_item, name] if e]
         )
 
-    def __getattr__(self, name):
+    __unset_attribute_value__ = object()
+
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
@@ -472,10 +465,6 @@ class ModelComposed(OpenApiModel):
         # get the attribute from the correct instance
         model_instances = self._var_name_to_model_instances.get(
             name, self._additional_properties_model_instances)
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         values = []
         # A composed model stores child (oneof/anyOf/allOf) models under
         # self._var_name_to_model_instances. A named property can exist in
@@ -489,12 +478,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
-
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
+            return default
         elif len_values == 1:
             return values[0]
         elif len_values > 1:
@@ -502,8 +486,18 @@ class ModelComposed(OpenApiModel):
                 "Values stored for property {0} in {1} differ when looking "
                 "at self and self's composed instances. All values must be "
                 "the same".format(name, type(self).__name__),
-                path_to_item
+                [e for e in [self._path_to_item, name] if e]
+            )
+
+    def __getitem__(self, name):
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
+            raise ApiAttributeError(
+                "{0} has no attribute '{1}'".format(
+                    type(self).__name__, name),
+                    [e for e in [self._path_to_item, name] if e]
             )
+        return value
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
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 88a7e8ba38b..90d111d582f 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
@@ -156,14 +156,6 @@ class OpenApiModel(object):
             )
         self.__dict__['_data_store'][name] = value
 
-    def __setitem__(self, name, value):
-        """this allows us to set values with instance[field_name] = val"""
-        self.__setattr__(name, value)
-
-    def __getitem__(self, name):
-        """this allows us to get a value with val = instance[field_name]"""
-        return self.__getattr__(name)
-
     def __repr__(self):
         """For `print` and `pprint`"""
         return self.to_str()
@@ -172,6 +164,9 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
+    __setattr__ = __setitem__
+    __getattr__ = __getitem__
+
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
         # pick a new schema/class to instantiate because a discriminator
@@ -290,7 +285,7 @@ class ModelSimple(OpenApiModel):
     """the parent class of models whose type != object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -298,22 +293,22 @@ class ModelSimple(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -346,7 +341,7 @@ class ModelNormal(OpenApiModel):
     """the parent class of models whose type == object in their
     swagger/openapi"""
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -354,22 +349,22 @@ class ModelNormal(OpenApiModel):
 
         self.set_attribute(name, value)
 
-    def __getattr__(self, name):
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
 
-        if name in self.__dict__['_data_store']:
-            return self.__dict__['_data_store'][name]
+        return self.__dict__['_data_store'].get(name, default)
+
+    def __getitem__(self, name):
+        """this allows us to get a value with val = instance.field_name"""
+        if name in self:
+            return self.get(name)
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            [name]
+            [e for e in [self._path_to_item, name] if e]
         )
 
     def __contains__(self, name):
@@ -432,7 +427,7 @@ class ModelComposed(OpenApiModel):
     which contain the value that the key is referring to.
     """
 
-    def __setattr__(self, name, value):
+    def __setitem__(self, name, value):
         """this allows us to set a value with instance.field_name = val"""
         if name in self.required_properties:
             self.__dict__[name] = value
@@ -454,17 +449,15 @@ class ModelComposed(OpenApiModel):
                     )
             return None
 
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         raise ApiAttributeError(
             "{0} has no attribute '{1}'".format(
                 type(self).__name__, name),
-            path_to_item
+            [e for e in [self._path_to_item, name] if e]
         )
 
-    def __getattr__(self, name):
+    __unset_attribute_value__ = object()
+
+    def get(self, name, default=None):
         """this allows us to get a value with val = instance.field_name"""
         if name in self.required_properties:
             return self.__dict__[name]
@@ -472,10 +465,6 @@ class ModelComposed(OpenApiModel):
         # get the attribute from the correct instance
         model_instances = self._var_name_to_model_instances.get(
             name, self._additional_properties_model_instances)
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
         values = []
         # A composed model stores child (oneof/anyOf/allOf) models under
         # self._var_name_to_model_instances. A named property can exist in
@@ -489,11 +478,7 @@ class ModelComposed(OpenApiModel):
                         values.append(v)
         len_values = len(values)
         if len_values == 0:
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
+            return default
         elif len_values == 1:
             return values[0]
         elif len_values > 1:
@@ -501,8 +486,18 @@ class ModelComposed(OpenApiModel):
                 "Values stored for property {0} in {1} differ when looking "
                 "at self and self's composed instances. All values must be "
                 "the same".format(name, type(self).__name__),
-                path_to_item
+                [e for e in [self._path_to_item, name] if e]
+            )
+
+    def __getitem__(self, name):
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
+            raise ApiAttributeError(
+                "{0} has no attribute '{1}'".format(
+                    type(self).__name__, name),
+                    [e for e in [self._path_to_item, name] if e]
             )
+        return value
 
     def __contains__(self, name):
         """this allows us to use `in` operator: `'attr' in instance`"""
-- 
GitLab


From 234c8f674c41b2ad4479eff8a31de67b002f81f2 Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Thu, 22 Oct 2020 02:07:57 -0700
Subject: [PATCH 4/7] move getattr and setattr to respective templates

---
 .../methods_setattr_getattr_composed.mustache                | 3 +++
 .../model_templates/methods_setattr_getattr_normal.mustache  | 3 +++
 .../model_templates/methods_shared.mustache                  | 5 +----
 3 files changed, 7 insertions(+), 4 deletions(-)

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 f75284d844a..72b565f321a 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
@@ -85,3 +85,6 @@
                     return True
 
         return False
+
+    __setattr__ = __setitem__
+    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
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 48c7611622e..1197eaff6e5 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
@@ -30,3 +30,6 @@
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
+
+    __setattr__ = __setitem__
+    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
index 18036071a30..5c9ab658d76 100644
--- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
+++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
@@ -4,7 +4,4 @@
 
     def __ne__(self, other):
         """Returns true if both objects are not equal"""
-        return not self == other
-
-    __setattr__ = __setitem__
-    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
+        return not self == other
\ No newline at end of file
-- 
GitLab


From d69a5980996d4973985ba9c0c4369fa58c8bafa3 Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Fri, 23 Oct 2020 19:12:00 +0200
Subject: [PATCH 5/7] update docstrings, def get/setattr methods to have
 docstrings in them, use __dict__ to avoid recursion issues

---
 .../methods_setattr_getattr_composed.mustache | 16 +++---
 .../methods_setattr_getattr_normal.mustache   | 19 +++----
 .../model_templates/methods_shared.mustache   | 10 +++-
 .../petstore_api/model_utils.py               | 51 ++++++++++---------
 .../x_auth_id_alias/model_utils.py            | 51 ++++++++++---------
 .../dynamic_servers/model_utils.py            | 51 ++++++++++---------
 .../petstore_api/model_utils.py               | 51 ++++++++++---------
 7 files changed, 132 insertions(+), 117 deletions(-)

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 72b565f321a..093528eb109 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
@@ -1,5 +1,5 @@
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
         if name in self.required_properties:
             self.__dict__[name] = value
             return
@@ -29,7 +29,7 @@
     __unset_attribute_value__ = object()
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
+        """returns the value of an attribute or some default value if the attribute was not set"""
         if name in self.required_properties:
             return self.__dict__[name]
 
@@ -61,8 +61,9 @@
             )
 
     def __getitem__(self, name):
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
+        value = self.get(name, self.__dict__['__unset_attribute_value__'])
+        if value is self.__dict__['__unset_attribute_value__']:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
@@ -71,7 +72,7 @@
         return value
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 
         if name in self.required_properties:
             return name in self.__dict__
@@ -84,7 +85,4 @@
                 if name in model_instance._data_store:
                     return True
 
-        return False
-
-    __setattr__ = __setitem__
-    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
+        return False
\ No newline at end of file
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 1197eaff6e5..0930c0f56e9 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
@@ -1,20 +1,20 @@
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -25,11 +25,8 @@
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
-        return name in self.__dict__['_data_store']
-
-    __setattr__ = __setitem__
-    __getattr__ = {{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}
\ No newline at end of file
+        return name in self.__dict__['_data_store']
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
index 5c9ab658d76..43bcf6fd0d5 100644
--- a/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
+++ b/modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/methods_shared.mustache
@@ -4,4 +4,12 @@
 
     def __ne__(self, other):
         """Returns true if both objects are not equal"""
-        return not self == other
\ No newline at end of file
+        return not self == other
+
+    def __setattr__(self, attr, value):
+        """set the value of an attribute using dot notation: `instance.attr = val`"""
+        self[attr] = value
+
+    def __getattr__(self, attr):
+        """get the value of an attribute using dot notation: `instance.attr`"""
+        return self.{{#attrNoneIfUnset}}get{{/attrNoneIfUnset}}{{^attrNoneIfUnset}}__getitem__{{/attrNoneIfUnset}}(attr)
\ No newline at end of file
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 90d111d582f..df1f427d76c 100644
--- a/samples/client/petstore/python-experimental/petstore_api/model_utils.py
+++ b/samples/client/petstore/python-experimental/petstore_api/model_utils.py
@@ -164,8 +164,13 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
-    __setattr__ = __setitem__
-    __getattr__ = __getitem__
+    def __setattr__(self, attr, value):
+        """set the value of an attribute using dot notation: `instance.attr = val`"""
+        self[attr] = value
+
+    def __getattr__(self, attr):
+        """get the value of an attribute using dot notation: `instance.attr`"""
+        return self.__getitem__(attr)
 
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
@@ -286,22 +291,22 @@ class ModelSimple(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -312,13 +317,12 @@ class ModelSimple(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_str(self):
         """Returns the string representation of the model"""
         return str(self.value)
@@ -342,22 +346,22 @@ class ModelNormal(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -368,13 +372,12 @@ class ModelNormal(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
@@ -428,7 +431,7 @@ class ModelComposed(OpenApiModel):
     """
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
         if name in self.required_properties:
             self.__dict__[name] = value
             return
@@ -458,7 +461,7 @@ class ModelComposed(OpenApiModel):
     __unset_attribute_value__ = object()
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
+        """returns the value of an attribute or some default value if the attribute was not set"""
         if name in self.required_properties:
             return self.__dict__[name]
 
@@ -490,8 +493,9 @@ class ModelComposed(OpenApiModel):
             )
 
     def __getitem__(self, name):
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
+        value = self.get(name, self.__dict__['__unset_attribute_value__'])
+        if value is self.__dict__['__unset_attribute_value__']:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
@@ -500,7 +504,7 @@ class ModelComposed(OpenApiModel):
         return value
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 
         if name in self.required_properties:
             return name in self.__dict__
@@ -515,7 +519,6 @@ class ModelComposed(OpenApiModel):
 
         return False
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
diff --git a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
index f85cabbb386..832dd085b77 100644
--- a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
+++ b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
@@ -164,8 +164,13 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
-    __setattr__ = __setitem__
-    __getattr__ = __getitem__
+    def __setattr__(self, attr, value):
+        """set the value of an attribute using dot notation: `instance.attr = val`"""
+        self[attr] = value
+
+    def __getattr__(self, attr):
+        """get the value of an attribute using dot notation: `instance.attr`"""
+        return self.__getitem__(attr)
 
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
@@ -286,22 +291,22 @@ class ModelSimple(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -312,13 +317,12 @@ class ModelSimple(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_str(self):
         """Returns the string representation of the model"""
         return str(self.value)
@@ -342,22 +346,22 @@ class ModelNormal(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -368,13 +372,12 @@ class ModelNormal(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
@@ -428,7 +431,7 @@ class ModelComposed(OpenApiModel):
     """
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
         if name in self.required_properties:
             self.__dict__[name] = value
             return
@@ -458,7 +461,7 @@ class ModelComposed(OpenApiModel):
     __unset_attribute_value__ = object()
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
+        """returns the value of an attribute or some default value if the attribute was not set"""
         if name in self.required_properties:
             return self.__dict__[name]
 
@@ -490,8 +493,9 @@ class ModelComposed(OpenApiModel):
             )
 
     def __getitem__(self, name):
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
+        value = self.get(name, self.__dict__['__unset_attribute_value__'])
+        if value is self.__dict__['__unset_attribute_value__']:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
@@ -500,7 +504,7 @@ class ModelComposed(OpenApiModel):
         return value
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 
         if name in self.required_properties:
             return name in self.__dict__
@@ -515,7 +519,6 @@ class ModelComposed(OpenApiModel):
 
         return False
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
diff --git a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
index d14e117354c..895acddab04 100644
--- a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
+++ b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
@@ -164,8 +164,13 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
-    __setattr__ = __setitem__
-    __getattr__ = __getitem__
+    def __setattr__(self, attr, value):
+        """set the value of an attribute using dot notation: `instance.attr = val`"""
+        self[attr] = value
+
+    def __getattr__(self, attr):
+        """get the value of an attribute using dot notation: `instance.attr`"""
+        return self.__getitem__(attr)
 
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
@@ -286,22 +291,22 @@ class ModelSimple(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -312,13 +317,12 @@ class ModelSimple(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_str(self):
         """Returns the string representation of the model"""
         return str(self.value)
@@ -342,22 +346,22 @@ class ModelNormal(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -368,13 +372,12 @@ class ModelNormal(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
@@ -428,7 +431,7 @@ class ModelComposed(OpenApiModel):
     """
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
         if name in self.required_properties:
             self.__dict__[name] = value
             return
@@ -458,7 +461,7 @@ class ModelComposed(OpenApiModel):
     __unset_attribute_value__ = object()
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
+        """returns the value of an attribute or some default value if the attribute was not set"""
         if name in self.required_properties:
             return self.__dict__[name]
 
@@ -490,8 +493,9 @@ class ModelComposed(OpenApiModel):
             )
 
     def __getitem__(self, name):
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
+        value = self.get(name, self.__dict__['__unset_attribute_value__'])
+        if value is self.__dict__['__unset_attribute_value__']:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
@@ -500,7 +504,7 @@ class ModelComposed(OpenApiModel):
         return value
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 
         if name in self.required_properties:
             return name in self.__dict__
@@ -515,7 +519,6 @@ class ModelComposed(OpenApiModel):
 
         return False
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
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 90d111d582f..df1f427d76c 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
@@ -164,8 +164,13 @@ class OpenApiModel(object):
         """Returns true if both objects are not equal"""
         return not self == other
 
-    __setattr__ = __setitem__
-    __getattr__ = __getitem__
+    def __setattr__(self, attr, value):
+        """set the value of an attribute using dot notation: `instance.attr = val`"""
+        self[attr] = value
+
+    def __getattr__(self, attr):
+        """get the value of an attribute using dot notation: `instance.attr`"""
+        return self.__getitem__(attr)
 
     def __new__(cls, *args, **kwargs):
         # this function uses the discriminator to
@@ -286,22 +291,22 @@ class ModelSimple(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -312,13 +317,12 @@ class ModelSimple(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_str(self):
         """Returns the string representation of the model"""
         return str(self.value)
@@ -342,22 +346,22 @@ class ModelNormal(OpenApiModel):
     swagger/openapi"""
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
-        if name in self.required_properties:
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
+        if name in self.__dict__['required_properties']:
             self.__dict__[name] = value
             return
 
         self.set_attribute(name, value)
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
-        if name in self.required_properties:
+        """returns the value of an attribute or some default value if the attribute was not set"""
+        if name in self.__dict__['required_properties']:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
 
     def __getitem__(self, name):
-        """this allows us to get a value with val = instance.field_name"""
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
         if name in self:
             return self.get(name)
 
@@ -368,13 +372,12 @@ class ModelNormal(OpenApiModel):
         )
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
-        if name in self.required_properties:
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
+        if name in self.__dict__['required_properties']:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
@@ -428,7 +431,7 @@ class ModelComposed(OpenApiModel):
     """
 
     def __setitem__(self, name, value):
-        """this allows us to set a value with instance.field_name = val"""
+        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
         if name in self.required_properties:
             self.__dict__[name] = value
             return
@@ -458,7 +461,7 @@ class ModelComposed(OpenApiModel):
     __unset_attribute_value__ = object()
 
     def get(self, name, default=None):
-        """this allows us to get a value with val = instance.field_name"""
+        """returns the value of an attribute or some default value if the attribute was not set"""
         if name in self.required_properties:
             return self.__dict__[name]
 
@@ -490,8 +493,9 @@ class ModelComposed(OpenApiModel):
             )
 
     def __getitem__(self, name):
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
+        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
+        value = self.get(name, self.__dict__['__unset_attribute_value__'])
+        if value is self.__dict__['__unset_attribute_value__']:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
@@ -500,7 +504,7 @@ class ModelComposed(OpenApiModel):
         return value
 
     def __contains__(self, name):
-        """this allows us to use `in` operator: `'attr' in instance`"""
+        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
 
         if name in self.required_properties:
             return name in self.__dict__
@@ -515,7 +519,6 @@ class ModelComposed(OpenApiModel):
 
         return False
 
-
     def to_dict(self):
         """Returns the model properties as a dict"""
         return model_to_dict(self, serialize=False)
-- 
GitLab


From fdaa38820a98db1fc480347428835a34eaf9b0d6 Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Sat, 24 Oct 2020 10:21:09 +0200
Subject: [PATCH 6/7] revert required_properties change

---
 .../methods_setattr_getattr_composed.mustache    |  4 ++--
 .../methods_setattr_getattr_normal.mustache      |  6 +++---
 .../petstore_api/model_utils.py                  | 16 ++++++++--------
 .../x_auth_id_alias/model_utils.py               | 16 ++++++++--------
 .../dynamic_servers/model_utils.py               | 16 ++++++++--------
 .../petstore_api/model_utils.py                  | 16 ++++++++--------
 6 files changed, 37 insertions(+), 37 deletions(-)

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 093528eb109..6b1013ca997 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
@@ -62,8 +62,8 @@
 
     def __getitem__(self, name):
         """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__dict__['__unset_attribute_value__'])
-        if value is self.__dict__['__unset_attribute_value__']:
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
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 0930c0f56e9..e700dad9536 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
@@ -1,6 +1,6 @@
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -8,7 +8,7 @@
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -26,7 +26,7 @@
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
\ No newline at end of file
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 df1f427d76c..e821ccb31b4 100644
--- a/samples/client/petstore/python-experimental/petstore_api/model_utils.py
+++ b/samples/client/petstore/python-experimental/petstore_api/model_utils.py
@@ -292,7 +292,7 @@ class ModelSimple(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -300,7 +300,7 @@ class ModelSimple(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -318,7 +318,7 @@ class ModelSimple(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -347,7 +347,7 @@ class ModelNormal(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -355,7 +355,7 @@ class ModelNormal(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -373,7 +373,7 @@ class ModelNormal(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -494,8 +494,8 @@ class ModelComposed(OpenApiModel):
 
     def __getitem__(self, name):
         """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__dict__['__unset_attribute_value__'])
-        if value is self.__dict__['__unset_attribute_value__']:
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
diff --git a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
index 832dd085b77..594af400e44 100644
--- a/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
+++ b/samples/openapi3/client/extensions/x-auth-id-alias/python-experimental/x_auth_id_alias/model_utils.py
@@ -292,7 +292,7 @@ class ModelSimple(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -300,7 +300,7 @@ class ModelSimple(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -318,7 +318,7 @@ class ModelSimple(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -347,7 +347,7 @@ class ModelNormal(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -355,7 +355,7 @@ class ModelNormal(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -373,7 +373,7 @@ class ModelNormal(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -494,8 +494,8 @@ class ModelComposed(OpenApiModel):
 
     def __getitem__(self, name):
         """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__dict__['__unset_attribute_value__'])
-        if value is self.__dict__['__unset_attribute_value__']:
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
diff --git a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
index 895acddab04..0963d948180 100644
--- a/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
+++ b/samples/openapi3/client/features/dynamic-servers/python-experimental/dynamic_servers/model_utils.py
@@ -292,7 +292,7 @@ class ModelSimple(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -300,7 +300,7 @@ class ModelSimple(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -318,7 +318,7 @@ class ModelSimple(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -347,7 +347,7 @@ class ModelNormal(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -355,7 +355,7 @@ class ModelNormal(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -373,7 +373,7 @@ class ModelNormal(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -494,8 +494,8 @@ class ModelComposed(OpenApiModel):
 
     def __getitem__(self, name):
         """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__dict__['__unset_attribute_value__'])
-        if value is self.__dict__['__unset_attribute_value__']:
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
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 df1f427d76c..e821ccb31b4 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
@@ -292,7 +292,7 @@ class ModelSimple(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -300,7 +300,7 @@ class ModelSimple(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -318,7 +318,7 @@ class ModelSimple(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -347,7 +347,7 @@ class ModelNormal(OpenApiModel):
 
     def __setitem__(self, name, value):
         """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             self.__dict__[name] = value
             return
 
@@ -355,7 +355,7 @@ class ModelNormal(OpenApiModel):
 
     def get(self, name, default=None):
         """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return self.__dict__[name]
 
         return self.__dict__['_data_store'].get(name, default)
@@ -373,7 +373,7 @@ class ModelNormal(OpenApiModel):
 
     def __contains__(self, name):
         """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.__dict__['required_properties']:
+        if name in self.required_properties:
             return name in self.__dict__
 
         return name in self.__dict__['_data_store']
@@ -494,8 +494,8 @@ class ModelComposed(OpenApiModel):
 
     def __getitem__(self, name):
         """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__dict__['__unset_attribute_value__'])
-        if value is self.__dict__['__unset_attribute_value__']:
+        value = self.get(name, self.__unset_attribute_value__)
+        if value is self.__unset_attribute_value__:
             raise ApiAttributeError(
                 "{0} has no attribute '{1}'".format(
                     type(self).__name__, name),
-- 
GitLab


From 83a51e820be1a2b6596003d0258e93da83fa521f Mon Sep 17 00:00:00 2001
From: Maksym Melnychok <maksym@yelp.com>
Date: Sun, 25 Oct 2020 13:17:56 +0100
Subject: [PATCH 7/7] add manual tests for .get method

---
 .../petstore/python-experimental/tests_manual/test_fruit.py    | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/samples/openapi3/client/petstore/python-experimental/tests_manual/test_fruit.py b/samples/openapi3/client/petstore/python-experimental/tests_manual/test_fruit.py
index fac0319663e..a60fdb9f6be 100644
--- a/samples/openapi3/client/petstore/python-experimental/tests_manual/test_fruit.py
+++ b/samples/openapi3/client/petstore/python-experimental/tests_manual/test_fruit.py
@@ -47,6 +47,7 @@ class TestFruit(unittest.TestCase):
         # check its properties
         self.assertEqual(fruit.length_cm, length_cm)
         self.assertEqual(fruit['length_cm'], length_cm)
+        self.assertEqual(fruit.get('length_cm'), length_cm)
         self.assertEqual(getattr(fruit, 'length_cm'), length_cm)
         self.assertEqual(fruit.color, color)
         self.assertEqual(fruit['color'], color)
@@ -85,6 +86,8 @@ class TestFruit(unittest.TestCase):
         # Per Python doc, if the named attribute does not exist,
         # default is returned if provided.
         self.assertEqual(getattr(fruit, 'cultivar', 'some value'), 'some value')
+        self.assertEqual(fruit.get('cultivar'), None)
+        self.assertEqual(fruit.get('cultivar', 'some value'), 'some value')
 
         # Per Python doc, if the named attribute does not exist,
         # default is returned if provided, otherwise AttributeError is raised.
-- 
GitLab