Avoid double init of classes with __new__

When __new__ returns an instance of the class (or a subclass), Python will
call __init__ on it afterwards. So if we return an initialised object of a
subclass, we end up calling both __new__ and __init__ twice. Avoid this by
calling object.__new__ and passing the desired subclass instead in
ResourceInfo and Parameter. Equivalent changes for Resource and Template
have been in place for some time.

Change-Id: I4c3f0bc9c1a39b9f0b964ccf1c6c638f86b3753e
This commit is contained in:
Zane Bitter 2016-10-05 13:57:56 -04:00
parent adb8629a90
commit bca740a997
2 changed files with 10 additions and 8 deletions

View File

@ -93,26 +93,28 @@ def is_valid_restricted_action(key, value):
class ResourceInfo(object):
"""Base mapping of resource type to implementation."""
def __new__(cls, registry, path, value, **kwargs):
def __new__(cls, registry, path, value):
"""Create a new ResourceInfo of the appropriate class."""
if cls != ResourceInfo:
if cls is not ResourceInfo:
# Call is already for a subclass, so pass it through
return super(ResourceInfo, cls).__new__(cls)
name = path[-1]
if name.endswith(('.yaml', '.template')):
# a template url for the resource "Type"
return TemplateResourceInfo(registry, path, value)
klass = TemplateResourceInfo
elif not isinstance(value, six.string_types):
return ClassResourceInfo(registry, path, value)
klass = ClassResourceInfo
elif value.endswith(('.yaml', '.template')):
# a registered template
return TemplateResourceInfo(registry, path, value)
klass = TemplateResourceInfo
elif name.endswith('*'):
return GlobResourceInfo(registry, path, value)
klass = GlobResourceInfo
else:
return MapResourceInfo(registry, path, value)
klass = MapResourceInfo
return super(ResourceInfo, cls).__new__(klass)
__slots__ = ('_registry', 'path', 'name', 'value', 'user_resource')

View File

@ -203,7 +203,7 @@ class Parameter(object):
else:
raise ValueError(_('Invalid Parameter type "%s"') % schema.type)
return ParamClass(name, schema, value)
return super(Parameter, cls).__new__(ParamClass)
def __init__(self, name, schema, value=None):
"""Initialise the parameter.