[python] Add option to return None instead of raising exception when accessing unset attribute (#7784)

* add option to return None instead of raising exception when accessing unset attribute

* update python samples

* reimplement getattr using getitem or get depending on attrNoneIfUnset

* move getattr and setattr to respective templates

* update docstrings, def get/setattr methods to have docstrings in them, use __dict__ to avoid recursion issues

* revert required_properties change

* add manual tests for .get method
This commit is contained in:
Maksym Melnychok
2020-10-25 17:13:22 +01:00
committed by GitHub
parent 07c23f4d1a
commit b70edd7f1b
11 changed files with 272 additions and 263 deletions

View File

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

View File

@@ -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";

View File

@@ -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);
}
/**

View File

@@ -1,5 +1,5 @@
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
@@ -20,28 +20,22 @@
)
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):
"""this allows us to get a value with val = instance.field_name"""
__unset_attribute_value__ = object()
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.required_properties:
return self.__dict__[name]
# 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,11 +49,7 @@
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:
@@ -67,11 +57,22 @@
"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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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`"""
"""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,4 +85,4 @@
if name in model_instance._data_store:
return True
return False
return False

View File

@@ -1,32 +1,32 @@
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
return name in self.__dict__['_data_store']
return name in self.__dict__['_data_store']

View File

@@ -1,15 +1,15 @@
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
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)

View File

@@ -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,14 @@ class OpenApiModel(object):
"""Returns true if both objects are not equal"""
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.__getitem__(attr)
def __new__(cls, *args, **kwargs):
# this function uses the discriminator to
# pick a new schema/class to instantiate because a discriminator
@@ -290,40 +290,39 @@ class ModelSimple(OpenApiModel):
"""the parent class of models whose type != object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
return name in self.__dict__['_data_store']
def to_str(self):
"""Returns the string representation of the model"""
return str(self.value)
@@ -346,40 +345,39 @@ class ModelNormal(OpenApiModel):
"""the parent class of models whose type == object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
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)
@@ -432,8 +430,8 @@ class ModelComposed(OpenApiModel):
which contain the value that the key is referring to.
"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
@@ -454,28 +452,22 @@ 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):
"""this allows us to get a value with val = instance.field_name"""
__unset_attribute_value__ = object()
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.required_properties:
return self.__dict__[name]
# 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 +481,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,11 +489,22 @@ 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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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`"""
"""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__
@@ -520,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)

View File

@@ -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,14 @@ class OpenApiModel(object):
"""Returns true if both objects are not equal"""
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.__getitem__(attr)
def __new__(cls, *args, **kwargs):
# this function uses the discriminator to
# pick a new schema/class to instantiate because a discriminator
@@ -290,40 +290,39 @@ class ModelSimple(OpenApiModel):
"""the parent class of models whose type != object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
return name in self.__dict__['_data_store']
def to_str(self):
"""Returns the string representation of the model"""
return str(self.value)
@@ -346,40 +345,39 @@ class ModelNormal(OpenApiModel):
"""the parent class of models whose type == object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
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)
@@ -432,8 +430,8 @@ class ModelComposed(OpenApiModel):
which contain the value that the key is referring to.
"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
@@ -454,28 +452,22 @@ 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):
"""this allows us to get a value with val = instance.field_name"""
__unset_attribute_value__ = object()
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.required_properties:
return self.__dict__[name]
# 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 +481,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,11 +489,22 @@ 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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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`"""
"""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__
@@ -520,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)

View File

@@ -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,14 @@ class OpenApiModel(object):
"""Returns true if both objects are not equal"""
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.__getitem__(attr)
def __new__(cls, *args, **kwargs):
# this function uses the discriminator to
# pick a new schema/class to instantiate because a discriminator
@@ -290,40 +290,39 @@ class ModelSimple(OpenApiModel):
"""the parent class of models whose type != object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
return name in self.__dict__['_data_store']
def to_str(self):
"""Returns the string representation of the model"""
return str(self.value)
@@ -346,40 +345,39 @@ class ModelNormal(OpenApiModel):
"""the parent class of models whose type == object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
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)
@@ -432,8 +430,8 @@ class ModelComposed(OpenApiModel):
which contain the value that the key is referring to.
"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
@@ -454,28 +452,22 @@ 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):
"""this allows us to get a value with val = instance.field_name"""
__unset_attribute_value__ = object()
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.required_properties:
return self.__dict__[name]
# 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 +481,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,11 +489,22 @@ 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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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`"""
"""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__
@@ -520,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)

View File

@@ -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,14 @@ class OpenApiModel(object):
"""Returns true if both objects are not equal"""
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.__getitem__(attr)
def __new__(cls, *args, **kwargs):
# this function uses the discriminator to
# pick a new schema/class to instantiate because a discriminator
@@ -290,40 +290,39 @@ class ModelSimple(OpenApiModel):
"""the parent class of models whose type != object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
return name in self.__dict__['_data_store']
def to_str(self):
"""Returns the string representation of the model"""
return str(self.value)
@@ -346,40 +345,39 @@ class ModelNormal(OpenApiModel):
"""the parent class of models whose type == object in their
swagger/openapi"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
self.set_attribute(name, value)
def __getattr__(self, name):
"""this allows us to get a value with val = instance.field_name"""
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.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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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):
"""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__
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)
@@ -432,8 +430,8 @@ class ModelComposed(OpenApiModel):
which contain the value that the key is referring to.
"""
def __setattr__(self, name, value):
"""this allows us to set a value with instance.field_name = val"""
def __setitem__(self, name, value):
"""set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
if name in self.required_properties:
self.__dict__[name] = value
return
@@ -454,28 +452,22 @@ 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):
"""this allows us to get a value with val = instance.field_name"""
__unset_attribute_value__ = object()
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.required_properties:
return self.__dict__[name]
# 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 +481,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,11 +489,22 @@ 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):
"""get the value of an attribute using square-bracket notation: `instance[attr]`"""
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`"""
"""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__
@@ -520,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)

View File

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