Skip to content

Commit

Permalink
[python] readonly constructors (#9409)
Browse files Browse the repository at this point in the history
* readonly

* other tests

* doc

* python samples

* model utils
  • Loading branch information
gbmarc1 authored May 11, 2021
1 parent 686b211 commit c966b5f
Show file tree
Hide file tree
Showing 244 changed files with 20,890 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ from {{packageName}}.model_utils import ( # noqa: F401
none_type,
validate_get_composed_info,
)
from ..model_utils import OpenApiModel
from {{packageName}}.exceptions import ApiAttributeError

{{#models}}
{{#model}}
{{#imports}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
args,
self.__class__.__name__,
),
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@classmethod
@convert_js_args_to_python_args
def _from_openapi_data(cls, *args, **kwargs): # noqa: E501
"""{{classname}} - a model defined in OpenAPI

Keyword Args:
{{#requiredVars}}
{{#defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} defaults to {{{defaultValue}}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501
{{/defaultValue}}
{{^defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}{{/description}}
{{/defaultValue}}
{{/requiredVars}}
{{> model_templates/docstring_init_required_kwargs }}
{{#optionalVars}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} [optional]{{#defaultValue}} if omitted the server will use the default value of {{{defaultValue}}}{{/defaultValue}} # noqa: E501
{{/optionalVars}}
"""

{{#requiredVars}}
{{#defaultValue}}
{{name}} = kwargs.get('{{name}}', {{{defaultValue}}})
{{/defaultValue}}
{{/requiredVars}}
_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

self = super(OpenApiModel, cls).__new__(cls)

{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
self._spec_property_naming = _spec_property_naming
self._path_to_item = _path_to_item
self._configuration = _configuration
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)

constant_args = {
'_check_type': _check_type,
'_path_to_item': _path_to_item,
'_spec_property_naming': _spec_property_naming,
'_configuration': _configuration,
'_visited_composed_classes': self._visited_composed_classes,
}
composed_info = validate_get_composed_info(
constant_args, kwargs, self)
self._composed_instances = composed_info[0]
self._var_name_to_model_instances = composed_info[1]
self._additional_properties_model_instances = composed_info[2]
discarded_args = composed_info[3]

for var_name, var_value in kwargs.items():
if var_name in discarded_args and \
self._configuration is not None and \
self._configuration.discard_unknown_keys and \
self._additional_properties_model_instances:
# discard variable.
continue
setattr(self, var_name, var_value)

return self
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{> model_templates/method_from_openapi_data_shared }}

{{#isEnum}}
self.value = value
{{/isEnum}}
{{#requiredVars}}
self.{{name}} = {{name}}
{{/requiredVars}}
for var_name, var_value in kwargs.items():
if var_name not in self.attribute_map and \
self._configuration is not None and \
self._configuration.discard_unknown_keys and \
self.additional_properties_type is None:
# discard variable.
continue
setattr(self, var_name, var_value)
return self
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
@classmethod
@convert_js_args_to_python_args
def _from_openapi_data(cls{{#requiredVars}}{{^defaultValue}}, {{name}}{{/defaultValue}}{{/requiredVars}}, *args, **kwargs): # noqa: E501
"""{{classname}} - a model defined in OpenAPI

{{#requiredVars}}
{{#-first}}
Args:
{{/-first}}
{{^defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}{{/description}}
{{/defaultValue}}
{{#-last}}

{{/-last}}
{{/requiredVars}}
Keyword Args:
{{#requiredVars}}
{{#defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} defaults to {{{defaultValue}}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501
{{/defaultValue}}
{{/requiredVars}}
{{> model_templates/docstring_init_required_kwargs }}
{{#optionalVars}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} [optional]{{#defaultValue}} if omitted the server will use the default value of {{{defaultValue}}}{{/defaultValue}} # noqa: E501
{{/optionalVars}}
"""

{{#requiredVars}}
{{#defaultValue}}
{{name}} = kwargs.get('{{name}}', {{{defaultValue}}})
{{/defaultValue}}
{{/requiredVars}}
_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

self = super(OpenApiModel, cls).__new__(cls)

{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
self._spec_property_naming = _spec_property_naming
self._path_to_item = _path_to_item
self._configuration = _configuration
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@classmethod
@convert_js_args_to_python_args
def _from_openapi_data(cls, *args, **kwargs):
"""{{classname}} - a model defined in OpenAPI

Note that value can be passed either in args or in kwargs, but not in both.

Args:
args[0] ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}}{{#defaultValue}} if omitted defaults to {{{defaultValue}}}{{/defaultValue}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501

Keyword Args:
value ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}}{{#defaultValue}} if omitted defaults to {{{defaultValue}}}{{/defaultValue}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501
{{> model_templates/docstring_init_required_kwargs }}
"""
# required up here when default value is not given
_path_to_item = kwargs.pop('_path_to_item', ())

self = super(OpenApiModel, cls).__new__(cls)

if 'value' in kwargs:
value = kwargs.pop('value')
elif args:
args = list(args)
value = args.pop(0)
{{#defaultValue}}
else:
value = {{{defaultValue}}}
{{/defaultValue}}
{{^defaultValue}}
else:
raise ApiTypeError(
"value is required, but not passed in args or kwargs and doesn't have default",
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)
{{/defaultValue}}

_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
self._spec_property_naming = _spec_property_naming
self._path_to_item = _path_to_item
self._configuration = _configuration
self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
self.value = value
if kwargs:
raise ApiTypeError(
"Invalid named arguments=%s passed to %s. Remove those invalid named arguments." % (
kwargs,
self.__class__.__name__,
),
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)

return self
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

Keyword Args:
{{#requiredVars}}
{{^isReadOnly}}
{{#defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} defaults to {{{defaultValue}}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501
{{/defaultValue}}
{{^defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}{{/description}}
{{/defaultValue}}
{{/isReadOnly}}
{{/requiredVars}}
{{> model_templates/docstring_init_required_kwargs }}
{{#optionalVars}}
Expand All @@ -30,25 +32,19 @@
"""

{{#requiredVars}}
{{^isReadOnly}}
{{#defaultValue}}
{{name}} = kwargs.get('{{name}}', {{{defaultValue}}})
{{/defaultValue}}
{{/isReadOnly}}
{{/requiredVars}}
_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
args,
self.__class__.__name__,
),
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)
{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
Expand Down Expand Up @@ -78,4 +74,7 @@
self._additional_properties_model_instances:
# discard variable.
continue
setattr(self, var_name, var_value)
setattr(self, var_name, var_value)
if var_name in self.read_only_vars:
raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
f"class with read only attributes.")
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
self.value = value
{{/isEnum}}
{{#requiredVars}}
{{^isReadOnly}}
self.{{name}} = {{name}}
{{/isReadOnly}}
{{/requiredVars}}
for var_name, var_value in kwargs.items():
if var_name not in self.attribute_map and \
Expand All @@ -22,4 +24,7 @@
self.additional_properties_type is None:
# discard variable.
continue
setattr(self, var_name, var_value)
setattr(self, var_name, var_value)
if var_name in self.read_only_vars:
raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate "
f"class with read only attributes.")
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
@convert_js_args_to_python_args
def __init__(self{{#requiredVars}}{{^defaultValue}}, {{name}}{{/defaultValue}}{{/requiredVars}}, *args, **kwargs): # noqa: E501
def __init__(self{{#requiredVars}}{{^isReadOnly}}{{^defaultValue}}, {{name}}{{/defaultValue}}{{/isReadOnly}}{{/requiredVars}}, *args, **kwargs): # noqa: E501
"""{{classname}} - a model defined in OpenAPI

{{#requiredVars}}
{{^isReadOnly}}
{{#-first}}
Args:
{{/-first}}
Expand All @@ -12,12 +13,15 @@
{{#-last}}

{{/-last}}
{{/isReadOnly}}
{{/requiredVars}}
Keyword Args:
{{#requiredVars}}
{{^isReadOnly}}
{{#defaultValue}}
{{name}} ({{{dataType}}}):{{#description}} {{{description}}}.{{/description}} defaults to {{{defaultValue}}}{{#allowableValues}}, must be one of [{{#enumVars}}{{{value}}}, {{/enumVars}}]{{/allowableValues}} # noqa: E501
{{/defaultValue}}
{{/isReadOnly}}
{{/requiredVars}}
{{> model_templates/docstring_init_required_kwargs }}
{{#optionalVars}}
Expand All @@ -26,25 +30,19 @@
"""

{{#requiredVars}}
{{^isReadOnly}}
{{#defaultValue}}
{{name}} = kwargs.get('{{name}}', {{{defaultValue}}})
{{/defaultValue}}
{{/isReadOnly}}
{{/requiredVars}}
_check_type = kwargs.pop('_check_type', True)
_spec_property_naming = kwargs.pop('_spec_property_naming', False)
_path_to_item = kwargs.pop('_path_to_item', ())
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
args,
self.__class__.__name__,
),
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)
{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,7 @@
_configuration = kwargs.pop('_configuration', None)
_visited_composed_classes = kwargs.pop('_visited_composed_classes', ())

if args:
raise ApiTypeError(
"Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
args,
self.__class__.__name__,
),
path_to_item=_path_to_item,
valid_classes=(self.__class__,),
)
{{> model_templates/invalid_pos_args }}

self._data_store = {}
self._check_type = _check_type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ class {{classname}}(ModelComposed):
{{/optionalVars}}
}

read_only_vars = {
{{#requiredVars}}
{{#isReadOnly}}
'{{name}}', # noqa: E501
{{/isReadOnly}}
{{/requiredVars}}
{{#optionalVars}}
{{#isReadOnly}}
'{{name}}', # noqa: E501
{{/isReadOnly}}
{{/optionalVars}}
}

{{> model_templates/method_from_openapi_data_composed }}

{{> model_templates/method_init_composed }}

@cached_property
Expand Down
Loading

0 comments on commit c966b5f

Please sign in to comment.