Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-180-convert-parameter-to-one-to-many 515c5886c -> 42f924f58
Clean up the code Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/42f924f5 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/42f924f5 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/42f924f5 Branch: refs/heads/ARIA-180-convert-parameter-to-one-to-many Commit: 42f924f586cffca7463499c92f36500904de9a0c Parents: 515c588 Author: Avia Efrat <a...@gigaspaces.com> Authored: Thu May 25 19:40:35 2017 +0300 Committer: Avia Efrat <a...@gigaspaces.com> Committed: Thu May 25 19:40:35 2017 +0300 ---------------------------------------------------------------------- aria/modeling/models.py | 5 - aria/modeling/relationship.py | 2 - aria/modeling/service_common.py | 1209 +++--------------- .../simple_v1_0/modeling/__init__.py | 2 +- tests/mock/models.py | 13 +- tests/storage/test_model_storage.py | 6 +- 6 files changed, 224 insertions(+), 1013 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/aria/modeling/models.py ---------------------------------------------------------------------- diff --git a/aria/modeling/models.py b/aria/modeling/models.py index 9b7e776..bfa0ece 100644 --- a/aria/modeling/models.py +++ b/aria/modeling/models.py @@ -72,7 +72,6 @@ __all__ = ( 'ServiceModification', # Common service models - 'Parameter', 'Input', 'Output', 'Property', @@ -210,9 +209,6 @@ class ServiceModification(aria_declarative_base, service_changes.ServiceModifica # region common service models -class Parameter(aria_declarative_base, service_common.ParameterBase): - pass - class Input(aria_declarative_base, service_common.InputBase): pass @@ -296,7 +292,6 @@ models_to_register = [ ServiceModification, # Common service models - Parameter, Input, Output, Property, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/aria/modeling/relationship.py ---------------------------------------------------------------------- diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py index 8644d42..40be5b2 100644 --- a/aria/modeling/relationship.py +++ b/aria/modeling/relationship.py @@ -289,8 +289,6 @@ def many_to_many(model_class, secondary_table_name = '{0}_{1}'.format(prefix, secondary_table_name) if other_property is None: other_property = '{0}_{1}'.format(prefix, formatting.pluralize(this_table)) - elif other_property is None: - other_property = '{0}_{1}'.format(other_table, formatting.pluralize(this_table)) secondary_table = _get_secondary_table( model_class.metadata, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/aria/modeling/service_common.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py index 0542e00..227d4ea 100644 --- a/aria/modeling/service_common.py +++ b/aria/modeling/service_common.py @@ -32,7 +32,7 @@ from . import ( ) -class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): +class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods): """ Represents a typed value. The value can contain nested intrinsic functions. @@ -81,9 +81,10 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): for the_relationship in self.__mapper__.relationships: v = getattr(self, the_relationship.key) if v: - return v[0] # because we are many-to-many, the back reference will be a list + return v - raise ValueError('orphaned parameter: does not have an owner: {0}'.format(self.name)) + raise ValueError('orphaned {class_name}: does not have an owner: {name}'.format( + class_name=type(self).__name__, name=self.name)) @property @caching.cachedmethod @@ -118,7 +119,7 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): elif isinstance(container, models.Capability) or isinstance(container, models.Artifact): container = container.node elif isinstance(container, models.CapabilityTemplate) \ - or isinstance(container, models.ArtifactTemplate): + or isinstance(container, models.ArtifactTemplate): container = container.node_template elif isinstance(container, models.Task): container = container.actor @@ -174,11 +175,10 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): ('description', self.description))) def instantiate(self, container): - from . import models - return models.Parameter(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) + return self.__class__(name=self.name, # pylint: disable=unexpected-keyword-arg + type_name=self.type_name, + _value=self._value, + description=self.description) def coerce_values(self, report_issues): value = self._value @@ -217,162 +217,81 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): :type description: basestring """ - from . import models type_name = canonical_type_name(value) if type_name is None: type_name = full_type_name(value) - return models.Parameter(name=name, # pylint: disable=unexpected-keyword-arg - type_name=type_name, - value=value, - description=description) - - -# TODO dry this code. currently it is almost a copy of ParameterBase -class OutputBase(TemplateModelMixin, caching.HasCachedMethods): - """ - Represents a typed value. The value can contain nested intrinsic functions. + return cls(name=name, # pylint: disable=unexpected-keyword-arg + type_name=type_name, + value=value, + description=description) - This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`. - :ivar name: Name - :vartype name: basestring - :ivar type_name: Type name - :vartype type_name: basestring - :ivar value: Value - :ivar description: Description - :vartype description: basestring - """ +class OutputBase(ParameterMixin, TemplateModelMixin, caching.HasCachedMethods): __tablename__ = 'output' - name = Column(Text) - type_name = Column(Text) - description = Column(Text) - _value = Column(PickleType) - - @property - def value(self): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self) - if evaluation is not None: - value = evaluation.value - return value + # region foreign keys - @value.setter - def value(self, value): - self._value = value + @declared_attr + def service_template_fk(cls): + return relationship.foreign_key('service_template', nullable=True) - @property - @caching.cachedmethod - def owner(self): - """ - The sole owner of this parameter, which is another model that relates to it. + @declared_attr + def service_fk(cls): + return relationship.foreign_key('service', nullable=True) - *All* parameters should have an owner model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ + # endregion - # Find first non-null relationship - for the_relationship in self.__mapper__.relationships: - v = getattr(self, the_relationship.key) - if v: - return v[0] # because we are many-to-many, the back reference will be a list + # region many_to_one relationships - raise ValueError('orphaned output: does not have an owner: {0}'.format(self.name)) + @declared_attr + def service_template(cls): + return relationship.many_to_one(cls, 'service_template') + @declared_attr + def service(cls): + return relationship.many_to_one(cls, 'service') - @property - @caching.cachedmethod - def container(self): # pylint: disable=too-many-return-statements,too-many-branches - """ - The logical container for this parameter, which would be another model: service, node, - group, or policy (or their templates). + # endregion - The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in - TOSCA. - *All* parameters should have a container model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ +class InputBase(ParameterMixin, TemplateModelMixin, caching.HasCachedMethods): - from . import models + __tablename__ = 'input' - container = self.owner + # region foreign keys - # Extract interface from operation - if isinstance(container, models.Operation): - container = container.interface - elif isinstance(container, models.OperationTemplate): - container = container.interface_template + @declared_attr + def service_template_fk(cls): + return relationship.foreign_key('service_template', nullable=True) - # Extract from other models - if isinstance(container, models.Interface): - container = container.node or container.group or container.relationship - elif isinstance(container, models.InterfaceTemplate): - container = container.node_template or container.group_template \ - or container.relationship_template - elif isinstance(container, models.Capability) or isinstance(container, models.Artifact): - container = container.node - elif isinstance(container, models.CapabilityTemplate) \ - or isinstance(container, models.ArtifactTemplate): - container = container.node_template - elif isinstance(container, models.Task): - container = container.actor + @declared_attr + def service_fk(cls): + return relationship.foreign_key('service', nullable=True) - # Extract node from relationship - if isinstance(container, models.Relationship): - container = container.source_node - elif isinstance(container, models.RelationshipTemplate): - container = container.requirement_template.node_template + @declared_attr + def interface_fk(cls): + return relationship.foreign_key('interface', nullable=True) - if container is not None: - return container + @declared_attr + def operation_fk(cls): + return relationship.foreign_key('operation', nullable=True) - raise ValueError('orphaned output: does not have a container: {0}'.format(self.name)) - - # @property - # @caching.cachedmethod - # def service(self): - # """ - # The :class:`Service` containing this parameter, or None if not contained in a service. - # """ - # - # from . import models - # container = self.container - # if isinstance(container, models.Service): - # return container - # elif hasattr(container, 'service'): - # return container.service - # return None - - # @property - # @caching.cachedmethod - # def service_template(self): - # """ - # The :class:`ServiceTemplate` containing this parameter, or None if not contained in a - # service template. - # """ - # - # from . import models - # container = self.container - # if isinstance(container, models.ServiceTemplate): - # return container - # elif hasattr(container, 'service_template'): - # return container.service_template - # return None + @declared_attr + def interface_template_fk(cls): + return relationship.foreign_key('interface_template', nullable=True) - # region foreign keys + @declared_attr + def operation_template_fk(cls): + return relationship.foreign_key('operation_template', nullable=True) @declared_attr - def service_template_fk(cls): - """For Output many-to-one to ServiceTemplate""" - return relationship.foreign_key('service_template', nullable=True) + def execution_fk(cls): + return relationship.foreign_key('execution', nullable=True) @declared_attr - def service_fk(cls): - """For Output many-to-one to Service""" - return relationship.foreign_key('service', nullable=True) + def task_fk(cls): + return relationship.foreign_key('task', nullable=True) # endregion @@ -386,550 +305,85 @@ class OutputBase(TemplateModelMixin, caching.HasCachedMethods): def service(cls): return relationship.many_to_one(cls, 'service') - # endregion + @declared_attr + def interface(cls): + return relationship.many_to_one(cls, 'interface') - @property - def as_raw(self): - return collections.OrderedDict(( - ('name', self.name), - ('type_name', self.type_name), - ('value', self.value), - ('description', self.description))) + @declared_attr + def operation(cls): + return relationship.many_to_one(cls, 'operation') - def instantiate(self, container): - from . import models - return models.Output(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) + @declared_attr + def interface_template(cls): + return relationship.many_to_one(cls, 'interface_template') - def coerce_values(self, report_issues): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self, report_issues) - if (evaluation is not None) and evaluation.final: - # A final evaluation can safely replace the existing value - self._value = evaluation.value + @declared_attr + def operation_template(cls): + return relationship.many_to_one(cls, 'operation_template') - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.type_name is not None: - console.puts('{0}: {1} ({2})'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)), - context.style.type(self.type_name))) - else: - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)))) - if self.description: - console.puts(context.style.meta(self.description)) + @declared_attr + def execution(cls): + return relationship.many_to_one(cls, 'execution') - def unwrap(self): - return self.name, self.value + @declared_attr + def task(cls): + return relationship.many_to_one(cls, 'task') - @classmethod - def wrap(cls, name, value, description=None): - """ - Wraps an arbitrary value as a parameter. The type will be guessed via introspection. + # endregion - :param name: Output name - :type name: basestring - :param value: Output value - :param description: Description (optional) - :type description: basestring - """ - from . import models - type_name = canonical_type_name(value) - if type_name is None: - type_name = full_type_name(value) - return models.Output(name=name, # pylint: disable=unexpected-keyword-arg - type_name=type_name, - value=value, - description=description) +class PropertyBase(ParameterMixin, TemplateModelMixin, caching.HasCachedMethods): + __tablename__ = 'property' -class TypeBase(InstanceModelMixin): - """ - Represents a type and its children. - """ + # region foreign keys - __tablename__ = 'type' + @declared_attr + def node_template_fk(cls): + return relationship.foreign_key('node_template', nullable=True) - __private_fields__ = ['parent_type_fk'] + @declared_attr + def group_template_fk(cls): + return relationship.foreign_key('group_template', nullable=True) - variant = Column(Text, nullable=False) - description = Column(Text) - _role = Column(Text, name='role') + @declared_attr + def policy_template_fk(cls): + return relationship.foreign_key('policy_template', nullable=True) @declared_attr - def parent(cls): - return relationship.one_to_one_self(cls, 'parent_type_fk') + def relationship_template_fk(cls): + return relationship.foreign_key('relationship_template', nullable=True) @declared_attr - def children(cls): - return relationship.one_to_many_self(cls, 'parent_type_fk') + def capability_template_fk(cls): + return relationship.foreign_key('capability_template', nullable=True) - # region foreign keys + @declared_attr + def artifact_template_fk(cls): + return relationship.foreign_key('artifact_template', nullable=True) @declared_attr - def parent_type_fk(cls): - """For Type one-to-many to Type""" - return relationship.foreign_key('type', nullable=True) + def node_fk(cls): + return relationship.foreign_key('node', nullable=True) - # endregion + @declared_attr + def group_fk(cls): + return relationship.foreign_key('group', nullable=True) - @property - def role(self): - def get_role(the_type): - if the_type is None: - return None - elif the_type._role is None: - return get_role(the_type.parent) - return the_type._role + @declared_attr + def policy_fk(cls): + return relationship.foreign_key('policy', nullable=True) - return get_role(self) + @declared_attr + def relationship_fk(cls): + return relationship.foreign_key('relationship', nullable=True) - @role.setter - def role(self, value): - self._role = value - - def is_descendant(self, base_name, name): - base = self.get_descendant(base_name) - if base is not None: - if base.get_descendant(name) is not None: - return True - return False - - def get_descendant(self, name): - if self.name == name: - return self - for child in self.children: - found = child.get_descendant(name) - if found is not None: - return found - return None - - def iter_descendants(self): - for child in self.children: - yield child - for descendant in child.iter_descendants(): - yield descendant - - @property - def as_raw(self): - return collections.OrderedDict(( - ('name', self.name), - ('description', self.description), - ('role', self.role))) - - @property - def as_raw_all(self): - types = [] - self._append_raw_children(types) - return types - - def coerce_values(self, report_issues): - pass - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.name: - console.puts(context.style.type(self.name)) - with context.style.indent: - for child in self.children: - child.dump() - - def _append_raw_children(self, types): - for child in self.children: - raw_child = formatting.as_raw(child) - raw_child['parent'] = self.name - types.append(raw_child) - child._append_raw_children(types) - - @property - def hierarchy(self): - """ - Return the type hierarchy. - :return: - """ - return [self] + (self.parent.hierarchy if self.parent else []) - - -# TODO dry this code. currently it is almost a copy of ParameterBase -class InputBase(TemplateModelMixin, caching.HasCachedMethods): - """ - Represents a typed value. The value can contain nested intrinsic functions. - - This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`. - - :ivar name: Name - :vartype name: basestring - :ivar type_name: Type name - :vartype type_name: basestring - :ivar value: Value - :ivar description: Description - :vartype description: basestring - """ - - __tablename__ = 'input' - - name = Column(Text) - type_name = Column(Text) - description = Column(Text) - _value = Column(PickleType) - - @property - def value(self): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self) - if evaluation is not None: - value = evaluation.value - return value - - @value.setter - def value(self, value): - self._value = value - - # region foreign keys - - @declared_attr - def service_template_fk(cls): - """For Input many-to-one to ServiceTemplate""" - return relationship.foreign_key('service_template', nullable=True) - - @declared_attr - def service_fk(cls): - """For Input many-to-one to Service""" - return relationship.foreign_key('service', nullable=True) - - @declared_attr - def interface_fk(cls): - """For Input many-to-one to Interface""" - return relationship.foreign_key('interface', nullable=True) - - @declared_attr - def operation_fk(cls): - """For Input many-to-one to Operation""" - return relationship.foreign_key('operation', nullable=True) - - @declared_attr - def interface_template_fk(cls): - """For Input many-to-one to InterfaceTemplate""" - return relationship.foreign_key('interface_template', nullable=True) - - @declared_attr - def operation_template_fk(cls): - """For Input many-to-one to OperationTemplate""" - return relationship.foreign_key('operation_template', nullable=True) - - @declared_attr - def execution_fk(cls): - """For Input many-to-one to Execution""" - return relationship.foreign_key('execution', nullable=True) - - @declared_attr - def task_fk(cls): - """For Input many-to-one to Task""" - return relationship.foreign_key('task', nullable=True) - - # endregion - - # region many_to_one relationships - - @declared_attr - def service_template(cls): - return relationship.many_to_one(cls, 'service_template') - - @declared_attr - def service(cls): - return relationship.many_to_one(cls, 'service') - - @declared_attr - def interface(cls): - return relationship.many_to_one(cls, 'interface') - - @declared_attr - def operation(cls): - return relationship.many_to_one(cls, 'operation') - - @declared_attr - def interface_template(cls): - return relationship.many_to_one(cls, 'interface_template') - - @declared_attr - def operation_template(cls): - return relationship.many_to_one(cls, 'operation_template') - - @declared_attr - def execution(cls): - return relationship.many_to_one(cls, 'execution') - - @declared_attr - def task(cls): - return relationship.many_to_one(cls, 'task') - - # endregion - - @property - @caching.cachedmethod - def owner(self): - """ - The sole owner of this parameter, which is another model that relates to it. - - *All* parameters should have an owner model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ - - # Find first non-null relationship - for the_relationship in self.__mapper__.relationships: - v = getattr(self, the_relationship.key) - if v: - return v # because we are many-to-many, the back reference will be a list - - raise ValueError('orphaned input: does not have an owner: {0}'.format(self.name)) - - - @property - @caching.cachedmethod - def container(self): # pylint: disable=too-many-return-statements,too-many-branches - """ - The logical container for this parameter, which would be another model: service, node, - group, or policy (or their templates). - - The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in - TOSCA. - - *All* parameters should have a container model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ - - from . import models - - container = self.owner - - # Extract interface from operation - if isinstance(container, models.Operation): - container = container.interface - elif isinstance(container, models.OperationTemplate): - container = container.interface_template - - # Extract from other models - if isinstance(container, models.Interface): - container = container.node or container.group or container.relationship - elif isinstance(container, models.InterfaceTemplate): - container = container.node_template or container.group_template \ - or container.relationship_template - elif isinstance(container, models.Capability) or isinstance(container, models.Artifact): - container = container.node - elif isinstance(container, models.CapabilityTemplate) \ - or isinstance(container, models.ArtifactTemplate): - container = container.node_template - elif isinstance(container, models.Task): - container = container.actor - - # Extract node from relationship - if isinstance(container, models.Relationship): - container = container.source_node - elif isinstance(container, models.RelationshipTemplate): - container = container.requirement_template.node_template - - if container is not None: - return container - - raise ValueError('orphaned input: does not have a container: {0}'.format(self.name)) - - # @property - # @caching.cachedmethod - # def service(self): - # """ - # The :class:`Service` containing this parameter, or None if not contained in a service. - # """ - # - # from . import models - # container = self.container - # if isinstance(container, models.Service): - # return container - # elif hasattr(container, 'service'): - # return container.service - # return None - # - # @property - # @caching.cachedmethod - # def service_template(self): - # """ - # The :class:`ServiceTemplate` containing this parameter, or None if not contained in a - # service template. - # """ - # - # from . import models - # container = self.container - # if isinstance(container, models.ServiceTemplate): - # return container - # elif hasattr(container, 'service_template'): - # return container.service_template - # return None - - @property - def as_raw(self): - return collections.OrderedDict(( - ('name', self.name), - ('type_name', self.type_name), - ('value', self.value), - ('description', self.description))) - - def instantiate(self, container): - from . import models - return models.Input(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) - - def coerce_values(self, report_issues): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self, report_issues) - if (evaluation is not None) and evaluation.final: - # A final evaluation can safely replace the existing value - self._value = evaluation.value - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.type_name is not None: - console.puts('{0}: {1} ({2})'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)), - context.style.type(self.type_name))) - else: - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)))) - if self.description: - console.puts(context.style.meta(self.description)) - - def unwrap(self): - return self.name, self.value - - @classmethod - def wrap(cls, name, value, description=None): - """ - Wraps an arbitrary value as a parameter. The type will be guessed via introspection. - - :param name: Input name - :type name: basestring - :param value: Input value - :param description: Description (optional) - :type description: basestring - """ - - from . import models - type_name = canonical_type_name(value) - if type_name is None: - type_name = full_type_name(value) - return models.Input(name=name, # pylint: disable=unexpected-keyword-arg - type_name=type_name, - value=value, - description=description) - - -# TODO dry this code. currently it is almost a copy of ParameterBase -class PropertyBase(TemplateModelMixin, caching.HasCachedMethods): - """ - Represents a typed value. The value can contain nested intrinsic functions. - - This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`. - - :ivar name: Name - :vartype name: basestring - :ivar type_name: Type name - :vartype type_name: basestring - :ivar value: Value - :ivar description: Description - :vartype description: basestring - """ - - __tablename__ = 'property' - - name = Column(Text) - type_name = Column(Text) - description = Column(Text) - _value = Column(PickleType) - - @property - def value(self): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self) - if evaluation is not None: - value = evaluation.value - return value - - @value.setter - def value(self, value): - self._value = value - - # region foreign keys - - @declared_attr - def node_template_fk(cls): - """For Property many-to-one to NodeTemplate""" - return relationship.foreign_key('node_template', nullable=True) - - @declared_attr - def group_template_fk(cls): - """For Property many-to-one to GroupTemplate""" - return relationship.foreign_key('group_template', nullable=True) - - @declared_attr - def policy_template_fk(cls): - """For Property many-to-one to PolicyTemplate""" - return relationship.foreign_key('policy_template', nullable=True) - - @declared_attr - def relationship_template_fk(cls): - """For Property many-to-one to RelationshipTemplate""" - return relationship.foreign_key('relationship_template', nullable=True) - - @declared_attr - def capability_template_fk(cls): - """For Property many-to-one to CapabilityTemplate""" - return relationship.foreign_key('capability_template', nullable=True) - - @declared_attr - def artifact_template_fk(cls): - """For Property many-to-one to ArtifactTemplate""" - return relationship.foreign_key('artifact_template', nullable=True) - - @declared_attr - def node_fk(cls): - """For Property many-to-one to Node""" - return relationship.foreign_key('node', nullable=True) - - @declared_attr - def group_fk(cls): - """For Property many-to-one to Group""" - return relationship.foreign_key('group', nullable=True) - - @declared_attr - def policy_fk(cls): - """For Property many-to-one to Policy""" - return relationship.foreign_key('policy', nullable=True) - - @declared_attr - def relationship_fk(cls): - """For Property many-to-one to Relationship""" - return relationship.foreign_key('relationship', nullable=True) - - @declared_attr - def capability_fk(cls): - """For Property many-to-one to Capability""" - return relationship.foreign_key('capability', nullable=True) + @declared_attr + def capability_fk(cls): + return relationship.foreign_key('capability', nullable=True) @declared_attr def artifact_fk(cls): - """For Property many-to-one to Artifact""" return relationship.foreign_key('artifact', nullable=True) # endregion @@ -949,237 +403,46 @@ class PropertyBase(TemplateModelMixin, caching.HasCachedMethods): @declared_attr def relationship_template(cls): - return relationship.many_to_one(cls, 'relationship_template') - - @declared_attr - def capability_template(cls): - return relationship.many_to_one(cls, 'capability_template') - - @declared_attr - def artifact_template(cls): - return relationship.many_to_one(cls, 'artifact_template') - - @declared_attr - def node(cls): - return relationship.many_to_one(cls, 'node') - - @declared_attr - def group(cls): - return relationship.many_to_one(cls, 'group') - - @declared_attr - def policy(cls): - return relationship.many_to_one(cls, 'policy') - - @declared_attr - def relationship(cls): - return relationship.many_to_one(cls, 'relationship') - - @declared_attr - def capability(cls): - return relationship.many_to_one(cls, 'capability') - - @declared_attr - def artifact(cls): - return relationship.many_to_one(cls, 'artifact') - - # endregion - - @property - @caching.cachedmethod - def owner(self): - """ - The sole owner of this parameter, which is another model that relates to it. - - *All* parameters should have an owner model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ - - # Find first non-null relationship - for the_relationship in self.__mapper__.relationships: - v = getattr(self, the_relationship.key) - if v: - return v - - raise ValueError('orphaned property: does not have an owner: {0}'.format(self.name)) - - - @property - @caching.cachedmethod - def container(self): # pylint: disable=too-many-return-statements,too-many-branches - """ - The logical container for this parameter, which would be another model: service, node, - group, or policy (or their templates). - - The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in - TOSCA. - - *All* parameters should have a container model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ - - from . import models - - container = self.owner - - # Extract interface from operation - if isinstance(container, models.Operation): - container = container.interface - elif isinstance(container, models.OperationTemplate): - container = container.interface_template - - # Extract from other models - if isinstance(container, models.Interface): - container = container.node or container.group or container.relationship - elif isinstance(container, models.InterfaceTemplate): - container = container.node_template or container.group_template \ - or container.relationship_template - elif isinstance(container, models.Capability) or isinstance(container, models.Artifact): - container = container.node - elif isinstance(container, models.CapabilityTemplate) \ - or isinstance(container, models.ArtifactTemplate): - container = container.node_template - elif isinstance(container, models.Task): - container = container.actor - - # Extract node from relationship - if isinstance(container, models.Relationship): - container = container.source_node - elif isinstance(container, models.RelationshipTemplate): - container = container.requirement_template.node_template - - if container is not None: - return container - - raise ValueError('orphaned property: does not have a container: {0}'.format(self.name)) - - @property - @caching.cachedmethod - def service(self): - """ - The :class:`Service` containing this parameter, or None if not contained in a service. - """ - - from . import models - container = self.container - if isinstance(container, models.Service): - return container - elif hasattr(container, 'service'): - return container.service - return None - - @property - @caching.cachedmethod - def service_template(self): - """ - The :class:`ServiceTemplate` containing this parameter, or None if not contained in a - service template. - """ - - from . import models - container = self.container - if isinstance(container, models.ServiceTemplate): - return container - elif hasattr(container, 'service_template'): - return container.service_template - return None - - @property - def as_raw(self): - return collections.OrderedDict(( - ('name', self.name), - ('type_name', self.type_name), - ('value', self.value), - ('description', self.description))) - - def instantiate(self, container): - from . import models - return models.Property(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) - - def coerce_values(self, report_issues): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self, report_issues) - if (evaluation is not None) and evaluation.final: - # A final evaluation can safely replace the existing value - self._value = evaluation.value - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.type_name is not None: - console.puts('{0}: {1} ({2})'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)), - context.style.type(self.type_name))) - else: - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)))) - if self.description: - console.puts(context.style.meta(self.description)) + return relationship.many_to_one(cls, 'relationship_template') - def unwrap(self): - return self.name, self.value + @declared_attr + def capability_template(cls): + return relationship.many_to_one(cls, 'capability_template') - @classmethod - def wrap(cls, name, value, description=None): - """ - Wraps an arbitrary value as a parameter. The type will be guessed via introspection. + @declared_attr + def artifact_template(cls): + return relationship.many_to_one(cls, 'artifact_template') - :param name: Input name - :type name: basestring - :param value: Input value - :param description: Description (optional) - :type description: basestring - """ + @declared_attr + def node(cls): + return relationship.many_to_one(cls, 'node') - from . import models - type_name = canonical_type_name(value) - if type_name is None: - type_name = full_type_name(value) - return models.Property(name=name, # pylint: disable=unexpected-keyword-arg - type_name=type_name, - value=value, - description=description) + @declared_attr + def group(cls): + return relationship.many_to_one(cls, 'group') + @declared_attr + def policy(cls): + return relationship.many_to_one(cls, 'policy') -class AttributeBase(TemplateModelMixin, caching.HasCachedMethods): - """ - Represents a typed value. The value can contain nested intrinsic functions. + @declared_attr + def relationship(cls): + return relationship.many_to_one(cls, 'relationship') - This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`. + @declared_attr + def capability(cls): + return relationship.many_to_one(cls, 'capability') - :ivar name: Name - :vartype name: basestring - :ivar type_name: Type name - :vartype type_name: basestring - :ivar value: Value - :ivar description: Description - :vartype description: basestring - """ + @declared_attr + def artifact(cls): + return relationship.many_to_one(cls, 'artifact') - __tablename__ = 'attribute' + # endregion - name = Column(Text) - type_name = Column(Text) - description = Column(Text) - _value = Column(PickleType) - @property - def value(self): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self) - if evaluation is not None: - value = evaluation.value - return value +class AttributeBase(ParameterMixin, TemplateModelMixin, caching.HasCachedMethods): - @value.setter - def value(self, value): - self._value = value + __tablename__ = 'attribute' # region foreign keys @@ -1207,164 +470,112 @@ class AttributeBase(TemplateModelMixin, caching.HasCachedMethods): # endregion - @property - @caching.cachedmethod - def owner(self): - """ - The sole owner of this attribute, which is another model that relates to it. - - *All* parameters should have an owner model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ - # Find first non-null relationship - for the_relationship in self.__mapper__.relationships: - v = getattr(self, the_relationship.key) - if v: - return v # because we are many-to-many, the back reference will be a list +class TypeBase(InstanceModelMixin): + """ + Represents a type and its children. + """ - raise ValueError('orphaned attribute: does not have an owner: {0}'.format(self.name)) + __tablename__ = 'type' - @property - @caching.cachedmethod - def container(self): # pylint: disable=too-many-return-statements,too-many-branches - """ - The logical container for this attribute, which would be another model: service, node, - group, or policy (or their templates). + __private_fields__ = ['parent_type_fk'] - The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in - TOSCA. + variant = Column(Text, nullable=False) + description = Column(Text) + _role = Column(Text, name='role') - *All* parameters should have a container model. In case this property method fails to find - it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. - """ + @declared_attr + def parent(cls): + return relationship.one_to_one_self(cls, 'parent_type_fk') - from . import models + @declared_attr + def children(cls): + return relationship.one_to_many_self(cls, 'parent_type_fk') - container = self.owner + # region foreign keys - # Extract interface from operation - if isinstance(container, models.Operation): - container = container.interface - elif isinstance(container, models.OperationTemplate): - container = container.interface_template + @declared_attr + def parent_type_fk(cls): + """For Type one-to-many to Type""" + return relationship.foreign_key('type', nullable=True) - # Extract from other models - if isinstance(container, models.Interface): - container = container.node or container.group or container.relationship - elif isinstance(container, models.InterfaceTemplate): - container = container.node_template or container.group_template \ - or container.relationship_template - elif isinstance(container, models.Capability) or isinstance(container, models.Artifact): - container = container.node - elif isinstance(container, models.CapabilityTemplate) \ - or isinstance(container, models.ArtifactTemplate): - container = container.node_template - elif isinstance(container, models.Task): - container = container.actor + # endregion - # Extract node from relationship - if isinstance(container, models.Relationship): - container = container.source_node - elif isinstance(container, models.RelationshipTemplate): - container = container.requirement_template.node_template + @property + def role(self): + def get_role(the_type): + if the_type is None: + return None + elif the_type._role is None: + return get_role(the_type.parent) + return the_type._role - if container is not None: - return container + return get_role(self) - raise ValueError('orphaned attribute: does not have a container: {0}'.format(self.name)) + @role.setter + def role(self, value): + self._role = value - @property - @caching.cachedmethod - def service(self): - """ - The :class:`Service` containing this parameter, or None if not contained in a service. - """ + def is_descendant(self, base_name, name): + base = self.get_descendant(base_name) + if base is not None: + if base.get_descendant(name) is not None: + return True + return False - from . import models - container = self.container - if isinstance(container, models.Service): - return container - elif hasattr(container, 'service'): - return container.service + def get_descendant(self, name): + if self.name == name: + return self + for child in self.children: + found = child.get_descendant(name) + if found is not None: + return found return None - @property - @caching.cachedmethod - def service_template(self): - """ - The :class:`ServiceTemplate` containing this parameter, or None if not contained in a - service template. - """ - - from . import models - container = self.container - if isinstance(container, models.ServiceTemplate): - return container - elif hasattr(container, 'service_template'): - return container.service_template - return None + def iter_descendants(self): + for child in self.children: + yield child + for descendant in child.iter_descendants(): + yield descendant @property def as_raw(self): return collections.OrderedDict(( ('name', self.name), - ('type_name', self.type_name), - ('value', self.value), - ('description', self.description))) + ('description', self.description), + ('role', self.role))) - def instantiate(self, container): - from . import models - return models.Attribute(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) + @property + def as_raw_all(self): + types = [] + self._append_raw_children(types) + return types def coerce_values(self, report_issues): - value = self._value - if value is not None: - evaluation = functions.evaluate(value, self, report_issues) - if (evaluation is not None) and evaluation.final: - # A final evaluation can safely replace the existing value - self._value = evaluation.value + pass def dump(self): context = ConsumptionContext.get_thread_local() - if self.type_name is not None: - console.puts('{0}: {1} ({2})'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)), - context.style.type(self.type_name))) - else: - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)))) - if self.description: - console.puts(context.style.meta(self.description)) + if self.name: + console.puts(context.style.type(self.name)) + with context.style.indent: + for child in self.children: + child.dump() - def unwrap(self): - return self.name, self.value + def _append_raw_children(self, types): + for child in self.children: + raw_child = formatting.as_raw(child) + raw_child['parent'] = self.name + types.append(raw_child) + child._append_raw_children(types) - @classmethod - def wrap(cls, name, value, description=None): + @property + def hierarchy(self): """ - Wraps an arbitrary value as a parameter. The type will be guessed via introspection. - - :param name: Parameter name - :type name: basestring - :param value: Parameter value - :param description: Description (optional) - :type description: basestring + Return the type hierarchy. + :return: """ - - from . import models - type_name = canonical_type_name(value) - if type_name is None: - type_name = full_type_name(value) - return models.Attribute(name=name, # pylint: disable=unexpected-keyword-arg - type_name=type_name, - value=value, - description=description) + return [self] + (self.parent.hierarchy if self.parent else []) class MetadataBase(TemplateModelMixin): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py index d89fc90..ba6eb16 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -32,7 +32,7 @@ from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate, RequirementTemplate, RelationshipTemplate, CapabilityTemplate, GroupTemplate, PolicyTemplate, SubstitutionTemplate, SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate, - ArtifactTemplate, Metadata, Parameter, Input, Output, Property, + ArtifactTemplate, Metadata, Input, Output, Property, Attribute, PluginSpecification) from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/tests/mock/models.py ---------------------------------------------------------------------- diff --git a/tests/mock/models.py b/tests/mock/models.py index 1935051..745ef71 100644 --- a/tests/mock/models.py +++ b/tests/mock/models.py @@ -94,7 +94,7 @@ def create_service_with_dependencies(include_execution=False, service.executions = [execution] execution.id = '1' if include_input: - input = create_parameter(name='input1', value='value1', model_class=models.Input) + input = create_input(name='input1', value='value1') service.inputs = {'input1': input} if include_node: node_template = create_node_template(service_template=service_template) @@ -110,8 +110,7 @@ def create_node_template_with_dependencies(include_node=False, include_property= service = create_service(service_template=service_template) create_node(dependency_node_template=node_template, service=service) if include_property: - node_template.properties = {'prop1': create_parameter(name='prop1', value='value1', - model_class=models.Property)} + node_template.properties = {'prop1': create_property(name='prop1', value='value1')} return node_template @@ -282,13 +281,17 @@ def create_plugin_specification(name='test_plugin', version='0.1'): ) -def create_parameter(name, value, model_class=models.Parameter): +def _create_parameter(name, value, model_class): p = model_class() return p.wrap(name, value) +def create_property(name, value): + return _create_parameter(name, value, model_class=models.Property) + + def create_input(name, value): - return create_parameter(name, value, model_class=models.Input) + return _create_parameter(name, value, model_class=models.Input) def _dictify(item): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/42f924f5/tests/storage/test_model_storage.py ---------------------------------------------------------------------- diff --git a/tests/storage/test_model_storage.py b/tests/storage/test_model_storage.py index 4dabfaf..518d624 100644 --- a/tests/storage/test_model_storage.py +++ b/tests/storage/test_model_storage.py @@ -107,7 +107,11 @@ def test_application_storage_factory(): assert storage.plugin assert storage.task - assert storage.parameter + assert storage.input + assert storage.output + assert storage.property + assert storage.attribute + assert storage.type assert storage.metadata