You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/03/20 19:25:02 UTC

[1/2] incubator-ariatosca git commit: Fixes for code review; make sure to set relationship names correctly

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-105-integrate-modeling 09f826a12 -> 7d20a8488


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index fb77bb8..5d667e3 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -35,7 +35,7 @@ from ..parser.reading import deepcopy_with_locators
 from ..utils import collections, formatting, console
 from .mixins import TemplateModelMixin
 from . import (
-    relationships,
+    relationship,
     utils,
     types as modeling_types
 )
@@ -99,74 +99,83 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     __tablename__ = 'service_template'
 
+    __private_fields__ = ['substitution_template_fk',
+                          'node_type_fk',
+                          'group_type_fk',
+                          'policy_type_fk',
+                          'relationship_type_fk',
+                          'capability_type_fk',
+                          'interface_type_fk',
+                          'artifact_type_fk']
+
     description = Column(Text)
     main_file_name = Column(Text)
 
     @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationships.many_to_many(cls, 'metadata', dict_key='name')
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def node_templates(cls):
-        return relationships.one_to_many(cls, 'node_template', dict_key='name')
+        return relationship.one_to_many(cls, 'node_template', dict_key='name')
 
     @declared_attr
     def group_templates(cls):
-        return relationships.one_to_many(cls, 'group_template', dict_key='name')
+        return relationship.one_to_many(cls, 'group_template', dict_key='name')
 
     @declared_attr
     def policy_templates(cls):
-        return relationships.one_to_many(cls, 'policy_template', dict_key='name')
+        return relationship.one_to_many(cls, 'policy_template', dict_key='name')
 
     @declared_attr
     def substitution_template(cls):
-        return relationships.one_to_one(cls, 'substitution_template')
+        return relationship.one_to_one(cls, 'substitution_template')
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def outputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
     def workflow_templates(cls):
-        return relationships.one_to_many(cls, 'operation_template', dict_key='name')
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     @declared_attr
     def plugin_specifications(cls):
-        return relationships.one_to_many(cls, 'plugin_specification', dict_key='name')
+        return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
 
     @declared_attr
     def node_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='node_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='node_type_fk', other_property=False)
 
     @declared_attr
     def group_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='group_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='group_type_fk', other_property=False)
 
     @declared_attr
     def policy_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='policy_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='policy_type_fk', other_property=False)
 
     @declared_attr
     def relationship_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='relationship_type_fk',
-                                        other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='relationship_type_fk',
+                                       other_property=False)
 
     @declared_attr
     def capability_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='capability_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='capability_type_fk', other_property=False)
 
     @declared_attr
     def interface_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='interface_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='interface_type_fk', other_property=False)
 
     @declared_attr
     def artifact_types(cls):
-        return relationships.one_to_one(cls, 'type', fk='artifact_type_fk', other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='artifact_type_fk', other_property=False)
 
     # region orchestration
 
@@ -180,42 +189,42 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     @declared_attr
     def substitution_template_fk(cls):
         """For ServiceTemplate one-to-one to SubstitutionTemplate"""
-        return relationships.fk('substitution_template', nullable=True)
+        return relationship.foreign_key('substitution_template', nullable=True)
 
     @declared_attr
     def node_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def group_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def policy_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def relationship_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def capability_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def interface_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def artifact_type_fk(cls):
         """For ServiceTemplate one-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     # endregion
 
@@ -356,15 +365,6 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
             console.puts('Interface types:')
             self.interface_types.dump()
 
-    __private_fields__ = ['substitution_template_fk',
-                          'node_type_fk',
-                          'group_type_fk',
-                          'policy_type_fk',
-                          'relationship_type_fk',
-                          'capability_type_fk',
-                          'interface_type_fk',
-                          'artifact_type_fk']
-
 
 class NodeTemplateBase(TemplateModelMixin):
     """
@@ -412,9 +412,13 @@ class NodeTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'node_template'
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk',
+                          'service_template_name']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
     default_instances = Column(Integer, default=1)
@@ -423,42 +427,42 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
+        return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
     @declared_attr
     def artifact_templates(cls):
-        return relationships.one_to_many(cls, 'artifact_template', dict_key='name')
+        return relationship.one_to_many(cls, 'artifact_template', dict_key='name')
 
     @declared_attr
     def capability_templates(cls):
-        return relationships.one_to_many(cls, 'capability_template', dict_key='name')
+        return relationship.one_to_many(cls, 'capability_template', dict_key='name')
 
     @declared_attr
     def requirement_templates(cls):
-        return relationships.one_to_many(cls, 'requirement_template', child_fk='node_template_fk',
-                                         child_property='node_template')
+        return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk',
+                                        child_property='node_template')
 
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def plugin_specifications(cls):
-        return relationships.many_to_many(cls, 'plugin_specification', dict_key='name')
+        return relationship.many_to_many(cls, 'plugin_specification', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For NodeTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to NodeTemplate"""
-        return relationships.fk('service_template')
+        return relationship.foreign_key('service_template')
 
     # endregion
 
@@ -541,10 +545,6 @@ class NodeTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.capability_templates, 'Capability templates')
             utils.dump_list_values(self.requirement_templates, 'Requirement templates')
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk',
-                          'service_template_name']
-
 
 class GroupTemplateBase(TemplateModelMixin):
     """
@@ -575,35 +575,38 @@ class GroupTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'group_template'
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return relationships.many_to_many(cls, 'node_template')
+        return relationship.many_to_many(cls, 'node_template')
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
+        return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For GroupTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to GroupTemplate"""
-        return relationships.fk('service_template')
+        return relationship.foreign_key('service_template')
 
     # endregion
 
@@ -650,9 +653,6 @@ class GroupTemplateBase(TemplateModelMixin):
                 console.puts('Member node templates: {0}'.format(', '.join(
                     (str(context.style.node(v.name)) for v in self.node_templates))))
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
-
 
 class PolicyTemplateBase(TemplateModelMixin):
     """
@@ -680,35 +680,38 @@ class PolicyTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'policy_template'
 
+    __private_fields__ = ['type_fk',
+                          'service_template_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def node_templates(cls):
-        return relationships.many_to_many(cls, 'node_template')
+        return relationship.many_to_many(cls, 'node_template')
 
     @declared_attr
     def group_templates(cls):
-        return relationships.many_to_many(cls, 'group_template')
+        return relationship.many_to_many(cls, 'group_template')
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For PolicyTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to PolicyTemplate"""
-        return relationships.fk('service_template')
+        return relationship.foreign_key('service_template')
 
     # endregion
 
@@ -756,9 +759,6 @@ class PolicyTemplateBase(TemplateModelMixin):
                 console.puts('Target group templates: {0}'.format(', '.join(
                     (str(context.style.node(v.name)) for v in self.group_templates))))
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
-
 
 class SubstitutionTemplateBase(TemplateModelMixin):
     """
@@ -777,20 +777,22 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'substitution_template'
 
+    __private_fields__ = ['node_type_fk']
+
     @declared_attr
     def node_type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     @declared_attr
     def mappings(cls):
-        return relationships.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
+        return relationship.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def node_type_fk(cls):
         """For SubstitutionTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     # endregion
 
@@ -820,8 +822,6 @@ class SubstitutionTemplateBase(TemplateModelMixin):
             console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
             utils.dump_dict_values(self.mappings, 'Mappings')
 
-    __private_fields__ = ['node_type_fk']
-
 
 class SubstitutionTemplateMappingBase(TemplateModelMixin):
     """
@@ -844,39 +844,44 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     __tablename__ = 'substitution_template_mapping'
 
+    __private_fields__ = ['substitution_template_fk',
+                          'node_template_fk',
+                          'capability_template_fk',
+                          'requirement_template_fk']
+
     @declared_attr
     def node_template(cls):
-        return relationships.one_to_one(cls, 'node_template')
+        return relationship.one_to_one(cls, 'node_template')
 
     @declared_attr
     def capability_template(cls):
-        return relationships.one_to_one(cls, 'capability_template')
+        return relationship.one_to_one(cls, 'capability_template')
 
     @declared_attr
     def requirement_template(cls):
-        return relationships.one_to_one(cls, 'requirement_template')
+        return relationship.one_to_one(cls, 'requirement_template')
 
     # region foreign keys
 
     @declared_attr
     def substitution_template_fk(cls):
         """For SubstitutionTemplate one-to-many to SubstitutionTemplateMapping"""
-        return relationships.fk('substitution_template')
+        return relationship.foreign_key('substitution_template')
 
     @declared_attr
     def node_template_fk(cls):
         """For SubstitutionTemplate one-to-one to NodeTemplate"""
-        return relationships.fk('node_template')
+        return relationship.foreign_key('node_template')
 
     @declared_attr
     def capability_template_fk(cls):
         """For SubstitutionTemplate one-to-one to CapabilityTemplate"""
-        return relationships.fk('capability_template', nullable=True)
+        return relationship.foreign_key('capability_template', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For SubstitutionTemplate one-to-one to RequirementTemplate"""
-        return relationships.fk('requirement_template', nullable=True)
+        return relationship.foreign_key('requirement_template', nullable=True)
 
     # endregion
 
@@ -885,6 +890,9 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name)))
 
+    def coerce_values(self, container, report_issues):
+        pass
+
     def instantiate(self, container):
         from . import models
         context = ConsumptionContext.get_thread_local()
@@ -926,11 +934,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
                                if self.capability_template
                                else self.requirement_template.name)))
 
-    __private_fields__ = ['substitution_template_fk',
-                          'node_template_fk',
-                          'capability_template_fk',
-                          'requirement_template_fk']
-
 
 class RequirementTemplateBase(TemplateModelMixin):
     """
@@ -965,54 +968,60 @@ class RequirementTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'requirement_template'
 
+    __private_fields__ = ['target_node_type_fk',
+                          'target_node_template_fk',
+                          'target_capability_type_fk'
+                          'node_template_fk',
+                          'relationship_template_fk']
+
     @declared_attr
     def target_node_type(cls):
-        return relationships.many_to_one(cls, 'type', fk='target_node_type_fk',
-                                         parent_property=False)
+        return relationship.many_to_one(cls, 'type', fk='target_node_type_fk',
+                                        parent_property=False)
 
     @declared_attr
     def target_node_template(cls):
-        return relationships.one_to_one(cls, 'node_template', fk='target_node_template_fk',
-                                        other_property=False)
+        return relationship.one_to_one(cls, 'node_template', fk='target_node_template_fk',
+                                       other_property=False)
 
     @declared_attr
     def target_capability_type(cls):
-        return relationships.one_to_one(cls, 'type', fk='target_capability_type_fk',
-                                        other_property=False)
+        return relationship.one_to_one(cls, 'type', fk='target_capability_type_fk',
+                                       other_property=False)
 
     target_capability_name = Column(Text)
     target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
 
     @declared_attr
     def relationship_template(cls):
-        return relationships.one_to_one(cls, 'relationship_template')
+        return relationship.one_to_one(cls, 'relationship_template')
 
     # region foreign keys
 
     @declared_attr
     def target_node_type_fk(cls):
         """For RequirementTemplate many-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def target_node_template_fk(cls):
         """For RequirementTemplate one-to-one to NodeTemplate"""
-        return relationships.fk('node_template', nullable=True)
+        return relationship.foreign_key('node_template', nullable=True)
 
     @declared_attr
     def target_capability_type_fk(cls):
         """For RequirementTemplate one-to-one to NodeTemplate"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to RequirementTemplate"""
-        return relationships.fk('node_template')
+        return relationship.foreign_key('node_template')
 
     @declared_attr
     def relationship_template_fk(cls):
         """For RequirementTemplate one-to-one to RelationshipTemplate"""
-        return relationships.fk('relationship_template', nullable=True)
+        return relationship.foreign_key('relationship_template', nullable=True)
 
     # endregion
 
@@ -1115,12 +1124,6 @@ class RequirementTemplateBase(TemplateModelMixin):
                 with context.style.indent:
                     self.relationship_template.dump()
 
-    __private_fields__ = ['target_node_type_fk',
-                          'target_node_template_fk',
-                          'target_capability_type_fk'
-                          'node_template_fk',
-                          'relationship_template_fk']
-
 
 class RelationshipTemplateBase(TemplateModelMixin):
     """
@@ -1150,26 +1153,28 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'relationship_template'
 
+    __private_fields__ = ['type_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interface_templates(cls):
-        return relationships.one_to_many(cls, 'interface_template', dict_key='name')
+        return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For RelationshipTemplate many-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     # endregion
 
@@ -1184,12 +1189,11 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     def instantiate(self, container):
         from . import models
-        relationship_model = models.Relationship(type=self.type,
+        relationship_model = models.Relationship(name=self.name,
+                                                 type=self.type,
                                                  relationship_template=self)
-        utils.instantiate_dict(container,
-                               relationship_model.properties, self.properties)
-        utils.instantiate_dict(container,
-                               relationship_model.interfaces, self.interface_templates)
+        utils.instantiate_dict(container, relationship_model.properties, self.properties)
+        utils.instantiate_dict(container, relationship_model.interfaces, self.interface_templates)
         return relationship_model
 
     def validate(self):
@@ -1214,8 +1218,6 @@ class RelationshipTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.properties, 'Properties')
             utils.dump_interfaces(self.interface_templates, 'Interface templates')
 
-    __private_fields__ = ['type_fk']
-
 
 class CapabilityTemplateBase(TemplateModelMixin):
     """
@@ -1247,9 +1249,12 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'capability_template'
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
     min_occurrences = Column(Integer, default=None)  # optional
@@ -1257,23 +1262,23 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def valid_source_node_types(cls):
-        return relationships.many_to_many(cls, 'type', prefix='valid_sources')
+        return relationship.many_to_many(cls, 'type', prefix='valid_sources')
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For CapabilityTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to CapabilityTemplate"""
-        return relationships.fk('node_template')
+        return relationship.foreign_key('node_template')
 
     # endregion
 
@@ -1347,9 +1352,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
                                for v in self.valid_source_node_types))))
             utils.dump_dict_values(self.properties, 'Properties')
 
-    __private_fields__ = ['type_fk',
-                          'node_template_fk']
-
 
 class InterfaceTemplateBase(TemplateModelMixin):
     """
@@ -1378,41 +1380,46 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'interface_template'
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk',
+                          'group_template_fk',
+                          'relationship_template_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def operation_templates(cls):
-        return relationships.one_to_many(cls, 'operation_template', dict_key='name')
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For InterfaceTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to InterfaceTemplate"""
-        return relationships.fk('node_template', nullable=True)
+        return relationship.foreign_key('node_template', nullable=True)
 
     @declared_attr
     def group_template_fk(cls):
         """For GroupTemplate one-to-many to InterfaceTemplate"""
-        return relationships.fk('group_template', nullable=True)
+        return relationship.foreign_key('group_template', nullable=True)
 
     @declared_attr
     def relationship_template_fk(cls):
         """For RelationshipTemplate one-to-many to InterfaceTemplate"""
-        return relationships.fk('relationship_template', nullable=True)
+        return relationship.foreign_key('relationship_template', nullable=True)
 
     # endregion
 
@@ -1454,11 +1461,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
             utils.dump_dict_values(self.inputs, 'Inputs')
             utils.dump_dict_values(self.operation_templates, 'Operation templates')
 
-    __private_fields__ = ['type_fk',
-                          'node_template_fk',
-                          'group_template_fk',
-                          'relationship_template_fk']
-
 
 class OperationTemplateBase(TemplateModelMixin):
     """
@@ -1495,18 +1497,22 @@ class OperationTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'operation_template'
 
+    __private_fields__ = ['service_template_fk',
+                          'interface_template_fk',
+                          'plugin_fk']
+
     description = Column(Text)
 
     @declared_attr
     def plugin_specification(cls):
-        return relationships.one_to_one(cls, 'plugin_specification')
+        return relationship.one_to_one(cls, 'plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1517,17 +1523,17 @@ class OperationTemplateBase(TemplateModelMixin):
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to OperationTemplate"""
-        return relationships.fk('service_template', nullable=True)
+        return relationship.foreign_key('service_template', nullable=True)
 
     @declared_attr
     def interface_template_fk(cls):
         """For InterfaceTemplate one-to-many to OperationTemplate"""
-        return relationships.fk('interface_template', nullable=True)
+        return relationship.foreign_key('interface_template', nullable=True)
 
     @declared_attr
     def plugin_specification_fk(cls):
         """For OperationTemplate one-to-one to PluginSpecification"""
-        return relationships.fk('plugin_specification', nullable=True)
+        return relationship.foreign_key('plugin_specification', nullable=True)
 
     # endregion
 
@@ -1584,10 +1590,6 @@ class OperationTemplateBase(TemplateModelMixin):
                     context.style.literal(self.retry_interval)))
             utils.dump_dict_values(self.inputs, 'Inputs')
 
-    __private_fields__ = ['service_template_fk',
-                          'interface_template_fk',
-                          'plugin_fk']
-
 
 class ArtifactTemplateBase(TemplateModelMixin):
     """
@@ -1618,9 +1620,12 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'artifact_template'
 
+    __private_fields__ = ['type_fk',
+                          'node_template_fk']
+
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1630,19 +1635,19 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign keys
 
     @declared_attr
     def type_fk(cls):
         """For ArtifactTemplate many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_template_fk(cls):
         """For NodeTemplate one-to-many to ArtifactTemplate"""
-        return relationships.fk('node_template')
+        return relationship.foreign_key('node_template')
 
     # endregion
 
@@ -1694,6 +1699,3 @@ class ArtifactTemplateBase(TemplateModelMixin):
                 console.puts('Repository credential: {0}'.format(
                     context.style.literal(self.repository_credential)))
             utils.dump_dict_values(self.properties, 'Properties')
-
-    __private_fields__ = ['type_fk',
-                          'node_template_fk']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py
index 762754f..0b4015c 100644
--- a/aria/modeling/utils.py
+++ b/aria/modeling/utils.py
@@ -29,7 +29,7 @@ def coerce_value(container, value, report_issues=False):
         return [coerce_value(container, v, report_issues) for v in value]
     elif isinstance(value, dict):
         return OrderedDict((k, coerce_value(container, v, report_issues))
-                           for k, v in value.items())
+                           for k, v in value.iteritems())
     elif hasattr(value, '_evaluate'):
         context = ConsumptionContext.get_thread_local()
         try:
@@ -43,30 +43,30 @@ def coerce_value(container, value, report_issues=False):
     return value
 
 
-def validate_dict_values(the_dict):
+def coerce_dict_values(container, the_dict, report_issues=False):
     if not the_dict:
         return
-    validate_list_values(the_dict.itervalues())
+    coerce_list_values(container, the_dict.itervalues(), report_issues)
 
 
-def validate_list_values(the_list):
+def coerce_list_values(container, the_list, report_issues=False):
     if not the_list:
         return
     for value in the_list:
-        value.validate()
+        value.coerce_values(container, report_issues)
 
 
-def coerce_dict_values(container, the_dict, report_issues=False):
+def validate_dict_values(the_dict):
     if not the_dict:
         return
-    coerce_list_values(container, the_dict.itervalues(), report_issues)
+    validate_list_values(the_dict.itervalues())
 
 
-def coerce_list_values(container, the_list, report_issues=False):
+def validate_list_values(the_list):
     if not the_list:
         return
     for value in the_list:
-        value.coerce_values(container, report_issues)
+        value.validate()
 
 
 def instantiate_dict(container, the_dict, from_dict):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py b/aria/orchestrator/workflows/api/task.py
index 2600aaa..98016ca 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -99,15 +99,14 @@ class OperationTask(BaseTask):
                 if not isinstance(v, models.Parameter):
                     inputs[k] = models.Parameter.wrap(k, v)
 
-        # TODO: These extra inputs should likely be stored as a separate entry in the task model,
-        # because they are different from the operation inputs. The two kinds of inputs should also
-        # not be merged.
+        # TODO: Suggestion: these extra inputs should likely be stored as a separate entry in the
+        # task model, because they are different from the operation inputs. The two kinds of inputs
+        # should also not be merged.
 
         if interface_name or operation_name:
-            operation = OperationTask._get_operation(actor.interfaces, interface_name,
-                                                     operation_name)
+            operation = self._get_operation(interface_name, operation_name)
             if operation is None:
-                raise exceptions.TaskException(
+                raise exceptions.TaskCreationException(
                     'Could not find operation "{0}" on interface "{1}" for {2} "{3}"'
                     .format(operation_name, interface_name, actor_type, actor.name))
 
@@ -115,7 +114,7 @@ class OperationTask(BaseTask):
             if operation.plugin_specification:
                 self.plugin = OperationTask._find_plugin(operation.plugin_specification)
                 if self.plugin is None:
-                    raise exceptions.TaskException(
+                    raise exceptions.TaskCreationException(
                         'Could not find plugin of operation "{0}" on interface "{1}" for {2} "{3}"'
                         .format(operation_name, interface_name, actor_type, actor.name))
 
@@ -195,9 +194,8 @@ class OperationTask(BaseTask):
             inputs=inputs,
             runs_on=runs_on)
 
-    @staticmethod
-    def _get_operation(interfaces, interface_name, operation_name):
-        interface = interfaces.get(interface_name)
+    def _get_operation(self, interface_name, operation_name):
+        interface = self.actor.interfaces.get(interface_name)
         if interface is not None:
             return interface.operations.get(operation_name)
         return None
@@ -249,5 +247,3 @@ class StubTask(BaseTask):
     """
     Enables creating empty tasks.
     """
-
-    pass

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/orchestrator/workflows/builtin/utils.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/builtin/utils.py b/aria/orchestrator/workflows/builtin/utils.py
index 84d8293..6fc1ffe 100644
--- a/aria/orchestrator/workflows/builtin/utils.py
+++ b/aria/orchestrator/workflows/builtin/utils.py
@@ -26,7 +26,7 @@ def create_node_task(interface_name, operation_name, node):
         return OperationTask.for_node(node=node,
                                       interface_name=interface_name,
                                       operation_name=operation_name)
-    except exceptions.TaskException:
+    except exceptions.TaskCreationException:
         return None
 
 
@@ -44,7 +44,7 @@ def create_relationship_tasks(interface_name, operation_name, runs_on, node):
                                                interface_name=interface_name,
                                                operation_name=operation_name,
                                                runs_on=runs_on))
-        except exceptions.TaskException:
+        except exceptions.TaskCreationException:
             pass
     return sequence
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/orchestrator/workflows/exceptions.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/exceptions.py b/aria/orchestrator/workflows/exceptions.py
index e2f5b59..f624fec 100644
--- a/aria/orchestrator/workflows/exceptions.py
+++ b/aria/orchestrator/workflows/exceptions.py
@@ -68,4 +68,9 @@ class TaskException(exceptions.AriaError):
     """
     Raised by the task
     """
-    pass
+
+
+class TaskCreationException(TaskException):
+    """
+    Raised by the task
+    """

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/docs/requirements.txt
----------------------------------------------------------------------
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 669522a..72b28f1 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -11,4 +11,4 @@
 # limitations under the License.
 
 Sphinx==1.5.3
-sphinx_rtd_theme==0.2.2
+sphinx_rtd_theme==0.2.4

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/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 ec5ba3b..4477732 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -250,7 +250,9 @@ def create_requirement_template_model(context, service_template, requirement):
     capability, capability_variant = requirement._get_capability(context)
     if capability is not None:
         if capability_variant == 'capability_type':
-            model['target_capability_type_name'] = capability._name
+            capability_type = \
+                service_template.capability_types.get_descendant(capability._name)
+            model['target_capability_type'] = capability_type
         else:
             model['target_capability_name'] = capability._name
 
@@ -265,6 +267,7 @@ def create_requirement_template_model(context, service_template, requirement):
     if relationship is not None:
         model.relationship_template = \
             create_relationship_template_model(context, service_template, relationship)
+        model.relationship_template.name = requirement._name
 
     return model
 
@@ -280,8 +283,7 @@ def create_relationship_template_model(context, service_template, relationship):
         relationship_type = relationship_template._get_type(context)
         relationship_type = service_template.relationship_types.get_descendant(
             relationship_type._name)
-        model = RelationshipTemplate(type=relationship_type,
-                                     name=relationship_template._name)
+        model = RelationshipTemplate(type=relationship_type)
         if relationship_template.description:
             model.description = relationship_template.description.value
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/tests/modeling/test_models.py
----------------------------------------------------------------------
diff --git a/tests/modeling/test_models.py b/tests/modeling/test_models.py
index 755a394..5266d79 100644
--- a/tests/modeling/test_models.py
+++ b/tests/modeling/test_models.py
@@ -177,11 +177,11 @@ class TestServiceTemplate(object):
     @pytest.mark.parametrize(
         'is_valid, description, created_at, updated_at, main_file_name',
         [
-            (True, 'description', now, now, '/path'),
             (False, {}, now, now, '/path'),
             (False, 'description', 'error', now, '/path'),
             (False, 'description', now, 'error', '/path'),
             (False, 'description', now, now, {}),
+
             (True, 'description', now, now, '/path'),
         ]
     )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/tests/orchestrator/workflows/executor/test_executor.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_executor.py b/tests/orchestrator/workflows/executor/test_executor.py
index e2602b7..0a2280d 100644
--- a/tests/orchestrator/workflows/executor/test_executor.py
+++ b/tests/orchestrator/workflows/executor/test_executor.py
@@ -43,7 +43,6 @@ def test_execute(executor):
     expected_value = 'value'
     successful_task = MockTask(mock_successful_task)
     failing_task = MockTask(mock_failing_task)
-    #task_with_inputs = MockTask(mock_task_with_input, inputs=dict(input='value'))
     task_with_inputs = MockTask(mock_task_with_input, inputs={'input': models.Parameter.wrap(
         'input', 'value')})
 



[2/2] incubator-ariatosca git commit: Fixes for code review; make sure to set relationship names correctly

Posted by em...@apache.org.
Fixes for code review; make sure to set relationship names correctly


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/7d20a848
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/7d20a848
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/7d20a848

Branch: refs/heads/ARIA-105-integrate-modeling
Commit: 7d20a84886fdd90e33b83696edf246346a1cc987
Parents: 09f826a
Author: Tal Liron <ta...@gmail.com>
Authored: Mon Mar 20 14:24:34 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Mon Mar 20 14:24:34 2017 -0500

----------------------------------------------------------------------
 aria/modeling/mixins.py                         |  12 +-
 aria/modeling/models.py                         | 101 ++---
 aria/modeling/orchestration.py                  |  65 +--
 aria/modeling/relationship.py                   | 402 +++++++++++++++++++
 aria/modeling/relationships.py                  | 402 -------------------
 aria/modeling/service_changes.py                |  41 +-
 aria/modeling/service_common.py                 |  27 +-
 aria/modeling/service_instance.py               | 355 ++++++++--------
 aria/modeling/service_template.py               | 300 +++++++-------
 aria/modeling/utils.py                          |  18 +-
 aria/orchestrator/workflows/api/task.py         |  20 +-
 aria/orchestrator/workflows/builtin/utils.py    |   4 +-
 aria/orchestrator/workflows/exceptions.py       |   7 +-
 docs/requirements.txt                           |   2 +-
 .../simple_v1_0/modeling/__init__.py            |   8 +-
 tests/modeling/test_models.py                   |   2 +-
 .../workflows/executor/test_executor.py         |   1 -
 17 files changed, 896 insertions(+), 871 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index 8eb08e8..e6db5a3 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -23,15 +23,15 @@ from sqlalchemy.ext import associationproxy
 from sqlalchemy import (
     Column,
     Integer,
-    Text,
+    Text
 )
 
-from .utils import classproperty
+from . import utils
 
 
 class ModelMixin(object):
 
-    @classproperty
+    @utils.classproperty
     def __modelname__(cls):                                                                         # pylint: disable=no-self-argument
         return getattr(cls, '__mapiname__', cls.__tablename__)
 
@@ -47,7 +47,7 @@ class ModelMixin(object):
         """
         Return a dict representation of the model
 
-        :param suppress_error: If set to True, sets `None` to attributes that it's unable to
+        :param suppress_error: If set to True, sets ``None`` to attributes that it's unable to
                                retrieve (e.g., if a relationship wasn't established yet, and so it's
                                impossible to access a property through it)
         """
@@ -77,7 +77,7 @@ class ModelMixin(object):
         """
         Return the list of field names for this table
 
-        Mostly for backwards compatibility in the code (that uses `fields`)
+        Mostly for backwards compatibility in the code (that uses ``fields``)
         """
 
         fields = set(cls._iter_association_proxies())
@@ -114,7 +114,7 @@ class InstanceModelMixin(ModelMixin):
     Mixin for :class:`ServiceInstance` models.
 
     All models support validation, diagnostic dumping, and representation as
-    raw data (which can be translated into JSON or YAML) via :code:`as_raw`.
+    raw data (which can be translated into JSON or YAML) via ``as_raw``.
     """
 
     @property

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/models.py
----------------------------------------------------------------------
diff --git a/aria/modeling/models.py b/aria/modeling/models.py
index 0e15273..a01783b 100644
--- a/aria/modeling/models.py
+++ b/aria/modeling/models.py
@@ -30,6 +30,57 @@ from . import (
 aria_declarative_base = declarative_base(cls=mixins.ModelIDMixin)
 
 
+# See also models_to_register at the bottom of this file
+__all__ = (
+    'aria_declarative_base',
+    'models_to_register',
+
+    # Service template models
+    'ServiceTemplate',
+    'NodeTemplate',
+    'GroupTemplate',
+    'PolicyTemplate',
+    'SubstitutionTemplate',
+    'SubstitutionTemplateMapping',
+    'RequirementTemplate',
+    'RelationshipTemplate',
+    'CapabilityTemplate',
+    'InterfaceTemplate',
+    'OperationTemplate',
+    'ArtifactTemplate',
+
+    # Service instance models
+    'Service',
+    'Node',
+    'Group',
+    'Policy',
+    'Substitution',
+    'SubstitutionMapping',
+    'Relationship',
+    'Capability',
+    'Interface',
+    'Operation',
+    'Artifact',
+
+    # Service changes models
+    'ServiceUpdate',
+    'ServiceUpdateStep',
+    'ServiceModification',
+
+    # Common service models
+    'Parameter',
+    'Type',
+    'Metadata',
+    'PluginSpecification',
+
+    # Orchestration models
+    'Execution',
+    'Plugin',
+    'Task',
+    'Log'
+)
+
+
 # region service template models
 
 class ServiceTemplate(aria_declarative_base, service_template.ServiceTemplateBase):
@@ -187,6 +238,7 @@ class Log(aria_declarative_base, orchestration.LogBase):
 # endregion
 
 
+# See also __all__ at the top of this file
 models_to_register = [
     # Service template models
     ServiceTemplate,
@@ -232,52 +284,3 @@ models_to_register = [
     Task,
     Log
 ]
-
-__all__ = (
-    'aria_declarative_base',
-    'models_to_register',
-
-    # Service template models
-    'ServiceTemplate',
-    'NodeTemplate',
-    'GroupTemplate',
-    'PolicyTemplate',
-    'SubstitutionTemplate',
-    'SubstitutionTemplateMapping',
-    'RequirementTemplate',
-    'RelationshipTemplate',
-    'CapabilityTemplate',
-    'InterfaceTemplate',
-    'OperationTemplate',
-    'ArtifactTemplate',
-
-    # Service instance models
-    'Service',
-    'Node',
-    'Group',
-    'Policy',
-    'Substitution',
-    'SubstitutionMapping',
-    'Relationship',
-    'Capability',
-    'Interface',
-    'Operation',
-    'Artifact',
-
-    # Service changes models
-    'ServiceUpdate',
-    'ServiceUpdateStep',
-    'ServiceModification',
-
-    # Common service models
-    'Parameter',
-    'Type',
-    'Metadata',
-    'PluginSpecification',
-
-    # Orchestration models
-    'Execution',
-    'Plugin',
-    'Task',
-    'Log'
-)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index e8a9986..0277756 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -41,7 +41,7 @@ from sqlalchemy.ext.declarative import declared_attr
 from ..orchestrator.exceptions import (TaskAbortException, TaskRetryException)
 from .types import (List, Dict)
 from .mixins import ModelMixin
-from . import relationships
+from . import relationship
 
 
 class ExecutionBase(ModelMixin):
@@ -51,6 +51,11 @@ class ExecutionBase(ModelMixin):
 
     __tablename__ = 'execution'
 
+    __private_fields__ = ['service_fk',
+                          'service_name',
+                          'service_template',
+                          'service_template_name']
+
     TERMINATED = 'terminated'
     FAILED = 'failed'
     CANCELLED = 'cancelled'
@@ -96,13 +101,13 @@ class ExecutionBase(ModelMixin):
 
     @declared_attr
     def service(cls):
-        return relationships.many_to_one(cls, 'service')
+        return relationship.many_to_one(cls, 'service')
 
     # region foreign keys
 
     @declared_attr
     def service_fk(cls):
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     # endregion
 
@@ -132,11 +137,6 @@ class ExecutionBase(ModelMixin):
             self.status
         )
 
-    __private_fields__ = ['service_fk',
-                          'service_name',
-                          'service_template',
-                          'service_template_name']
-
 
 class PluginBase(ModelMixin):
     """
@@ -165,6 +165,14 @@ class TaskBase(ModelMixin):
 
     __tablename__ = 'task'
 
+    __private_fields__ = ['node_fk',
+                          'relationship_fk',
+                          'plugin_fk',
+                          'execution_fk',
+                          'node_name',
+                          'relationship_name',
+                          'execution_name']
+
     PENDING = 'pending'
     RETRYING = 'retrying'
     SENT = 'sent'
@@ -192,23 +200,23 @@ class TaskBase(ModelMixin):
 
     @declared_attr
     def node(cls):
-        return relationships.many_to_one(cls, 'node')
+        return relationship.many_to_one(cls, 'node')
 
     @declared_attr
     def relationship(cls):
-        return relationships.many_to_one(cls, 'relationship')
+        return relationship.many_to_one(cls, 'relationship')
 
     @declared_attr
     def plugin(cls):
-        return relationships.many_to_one(cls, 'plugin')
+        return relationship.many_to_one(cls, 'plugin')
 
     @declared_attr
     def execution(cls):
-        return relationships.many_to_one(cls, 'execution')
+        return relationship.many_to_one(cls, 'execution')
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     status = Column(Enum(*STATES, name='status'), default=PENDING)
 
@@ -254,19 +262,19 @@ class TaskBase(ModelMixin):
 
     @declared_attr
     def node_fk(cls):
-        return relationships.fk('node', nullable=True)
+        return relationship.foreign_key('node', nullable=True)
 
     @declared_attr
     def relationship_fk(cls):
-        return relationships.fk('relationship', nullable=True)
+        return relationship.foreign_key('relationship', nullable=True)
 
     @declared_attr
     def plugin_fk(cls):
-        return relationships.fk('plugin', nullable=True)
+        return relationship.foreign_key('plugin', nullable=True)
 
     @declared_attr
     def execution_fk(cls):
-        return relationships.fk('execution', nullable=True)
+        return relationship.foreign_key('execution', nullable=True)
 
     # endregion
 
@@ -305,25 +313,21 @@ class TaskBase(ModelMixin):
     def retry(message=None, retry_interval=None):
         raise TaskRetryException(message, retry_interval=retry_interval)
 
-    __private_fields__ = ['node_fk',
-                          'relationship_fk',
-                          'plugin_fk',
-                          'execution_fk',
-                          'node_name',
-                          'relationship_name',
-                          'execution_name']
-
 
 class LogBase(ModelMixin):
+
     __tablename__ = 'log'
 
+    __private_fields__ = ['execution_fk',
+                          'task_fk']
+
     @declared_attr
     def execution(cls):
-        return relationships.many_to_one(cls, 'execution')
+        return relationship.many_to_one(cls, 'execution')
 
     @declared_attr
     def task(cls):
-        return relationships.many_to_one(cls, 'task')
+        return relationship.many_to_one(cls, 'task')
 
     level = Column(String)
     msg = Column(String)
@@ -334,17 +338,14 @@ class LogBase(ModelMixin):
 
     @declared_attr
     def execution_fk(cls):
-        return relationships.fk('execution')
+        return relationship.foreign_key('execution')
 
     @declared_attr
     def task_fk(cls):
-        return relationships.fk('task', nullable=True)
+        return relationship.foreign_key('task', nullable=True)
 
     # endregion
 
     def __repr__(self):
         return "<{self.created_at}: [{self.level}] @{self.actor}> {msg}".format(
             self=self, msg=self.msg[:50])
-
-    __private_fields__ = ['execution_fk',
-                          'task_fk']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
new file mode 100644
index 0000000..bed1599
--- /dev/null
+++ b/aria/modeling/relationship.py
@@ -0,0 +1,402 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# pylint: disable=invalid-name, redefined-outer-name
+
+from sqlalchemy.orm import relationship, backref
+from sqlalchemy.orm.collections import attribute_mapped_collection
+from sqlalchemy import (
+    Column,
+    ForeignKey,
+    Integer,
+    Table
+)
+
+from ..utils import formatting
+
+
+def foreign_key(other_table,
+                nullable=False):
+    """
+    Declare a foreign key property, which will also create a foreign key column in the table with
+    the name of the property. By convention the property name should end in "_fk".
+
+    You are required to explicitly create foreign keys in order to allow for one-to-one,
+    one-to-many, and many-to-one relationships (but not for many-to-many relationships). If you do
+    not do so, SQLAlchemy will fail to create the relationship property and raise an exception with
+    a clear error message.
+
+    You should normally not have to access this property directly, but instead use the associated
+    relationship properties.
+
+    *This utility method should only be used during class creation.*
+
+    :param other_table: Other table name
+    :type other_table: basestring
+    :param nullable: True to allow null values (meaning that there is no relationship)
+    :type nullable: bool
+    """
+
+    return Column(Integer,
+                  ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
+                  nullable=nullable)
+
+
+def one_to_one_self(model_class,
+                    fk,
+                    relationship_kwargs=None):
+    """
+    Declare a one-to-one relationship property. The property value would be an instance of the same
+    model.
+
+    You will need an associated foreign key to our own table.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param fk: Foreign key name
+    :type fk: basestring
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    """
+
+    relationship_kwargs = relationship_kwargs or {}
+
+    remote_side = '{model_class}.{remote_column}'.format(
+        model_class=model_class.__name__,
+        remote_column=model_class.id_column_name()
+    )
+
+    primaryjoin = '{remote_side} == {model_class}.{column}'.format(
+        remote_side=remote_side,
+        model_class=model_class.__name__,
+        column=fk
+    )
+
+    return relationship(
+        _get_class_for_table(model_class, model_class.__tablename__).__name__,
+        primaryjoin=primaryjoin,
+        remote_side=remote_side,
+        post_update=True,
+        **relationship_kwargs
+    )
+
+
+def one_to_many_self(model_class,
+                     fk,
+                     dict_key=None,
+                     relationship_kwargs=None):
+    """
+    Declare a one-to-many relationship property. The property value would be a list or dict of
+    instances of the same model.
+
+    You will need an associated foreign key to our own table.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param fk: Foreign key name
+    :type fk: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    """
+
+    relationship_kwargs = relationship_kwargs or {}
+
+    relationship_kwargs.setdefault('remote_side', '{model_class}.{remote_column}'.format(
+        model_class=model_class.__name__,
+        remote_column=fk
+    ))
+
+    return _relationship(model_class, model_class.__tablename__, None, relationship_kwargs,
+                         other_property=False, dict_key=dict_key)
+
+
+def one_to_one(model_class,
+               other_table,
+               fk=None,
+               other_fk=None,
+               other_property=None,
+               relationship_kwargs=None,
+               backref_kwargs=None):
+    """
+    Declare a one-to-one relationship property. The property value would be an instance of the other
+    table's model.
+
+    You have two options for the foreign key. Either this table can have an associated key to the
+    other table (use the ``fk`` argument) or the other table can have an associated foreign key to
+    this our table (use the ``other_fk`` argument).
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param other_table: Other table name
+    :type other_table: basestring
+    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+    :type fk: basestring
+    :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
+    :type other_fk: basestring
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
+    :type backref_kwargs: {}
+    """
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', False)
+
+    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
+                         other_property, fk=fk, other_fk=other_fk)
+
+
+def one_to_many(model_class,
+                child_table,
+                child_fk=None,
+                dict_key=None,
+                child_property=None,
+                relationship_kwargs=None,
+                backref_kwargs=None):
+    """
+    Declare a one-to-many relationship property. The property value would be a list or dict of
+    instances of the child table's model.
+
+    The child table will need an associated foreign key to our table.
+
+    The declaration will automatically create a matching many-to-one property at the child model,
+    named after our table name. Use the ``child_property`` argument to override this name.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param child_table: Child table name
+    :type child_table: basestring
+    :param child_fk: Foreign key name at the child table (no need specify if there's no ambiguity)
+    :type child_fk: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param child_property: Override name of matching many-to-one property at child table; set to
+                           false to disable
+    :type child_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
+    :type backref_kwargs: {}
+    """
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', False)
+
+    return _relationship(model_class, child_table, backref_kwargs, relationship_kwargs,
+                         child_property, other_fk=child_fk, dict_key=dict_key)
+
+
+def many_to_one(model_class,
+                parent_table,
+                fk=None,
+                parent_fk=None,
+                parent_property=None,
+                relationship_kwargs=None,
+                backref_kwargs=None):
+    """
+    Declare a many-to-one relationship property. The property value would be an instance of the
+    parent table's model.
+
+    You will need an associated foreign key to the parent table.
+
+    The declaration will automatically create a matching one-to-many property at the child model,
+    named after the plural form of our table name. Use the ``parent_property`` argument to override
+    this name. Note: the automatic property will always be a SQLAlchemy query object; if you need a
+    Python collection then use :meth:`one_to_many` at that model.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param parent_table: Parent table name
+    :type parent_table: basestring
+    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
+    :type fk: basestring
+    :param parent_property: Override name of matching one-to-many property at parent table; set to
+                            false to disable
+    :type parent_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
+    :type backref_kwargs: {}
+    """
+
+    if parent_property is None:
+        parent_property = formatting.pluralize(model_class.__tablename__)
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', True)
+    backref_kwargs.setdefault('lazy', 'dynamic')
+    backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
+
+    return _relationship(model_class, parent_table, backref_kwargs, relationship_kwargs,
+                         parent_property, fk=fk, other_fk=parent_fk)
+
+
+def many_to_many(model_class,
+                 other_table,
+                 prefix=None,
+                 dict_key=None,
+                 other_property=None,
+                 relationship_kwargs=None,
+                 backref_kwargs=None):
+    """
+    Declare a many-to-many relationship property. The property value would be a list or dict of
+    instances of the other table's model.
+
+    You do not need associated foreign keys for this relationship. Instead, an extra table will be
+    created for you.
+
+    The declaration will automatically create a matching many-to-many property at the other model,
+    named after the plural form of our table name. Use the ``other_property`` argument to override
+    this name. Note: the automatic property will always be a SQLAlchemy query object; if you need a
+    Python collection then use :meth:`many_to_many` again at that model.
+
+    *This utility method should only be used during class creation.*
+
+    :param model_class: The class in which this relationship will be declared
+    :type model_class: type
+    :param parent_table: Parent table name
+    :type parent_table: basestring
+    :param prefix: Optional prefix for extra table name as well as for ``other_property``
+    :type prefix: basestring
+    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
+                     be a list
+    :type dict_key: basestring
+    :param other_property: Override name of matching many-to-many property at other table; set to
+                           false to disable
+    :type other_property: basestring|bool
+    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
+    :type relationship_kwargs: {}
+    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
+    :type backref_kwargs: {}
+    """
+
+    this_table = model_class.__tablename__
+    this_column_name = '{0}_id'.format(this_table)
+    this_foreign_key = '{0}.id'.format(this_table)
+
+    other_column_name = '{0}_id'.format(other_table)
+    other_foreign_key = '{0}.id'.format(other_table)
+
+    secondary_table = '{0}_{1}'.format(this_table, other_table)
+
+    if other_property is None:
+        other_property = formatting.pluralize(this_table)
+        if prefix is not None:
+            secondary_table = '{0}_{1}'.format(prefix, secondary_table)
+            other_property = '{0}_{1}'.format(prefix, other_property)
+
+    backref_kwargs = backref_kwargs or {}
+    backref_kwargs.setdefault('uselist', True)
+
+    relationship_kwargs = relationship_kwargs or {}
+    relationship_kwargs.setdefault('secondary', _get_secondary_table(
+        model_class.metadata,
+        secondary_table,
+        this_column_name,
+        other_column_name,
+        this_foreign_key,
+        other_foreign_key
+    ))
+
+    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
+                         other_property, dict_key=dict_key)
+
+
+def _relationship(model_class, other_table, backref_kwargs, relationship_kwargs, other_property,
+                  fk=None, other_fk=None, dict_key=None):
+    relationship_kwargs = relationship_kwargs or {}
+
+    if fk:
+        relationship_kwargs.setdefault('foreign_keys',
+                                       lambda: getattr(
+                                           _get_class_for_table(
+                                               model_class,
+                                               model_class.__tablename__),
+                                           fk))
+
+    elif other_fk:
+        relationship_kwargs.setdefault('foreign_keys',
+                                       lambda: getattr(
+                                           _get_class_for_table(
+                                               model_class,
+                                               other_table),
+                                           other_fk))
+
+    if dict_key:
+        relationship_kwargs.setdefault('collection_class',
+                                       attribute_mapped_collection(dict_key))
+
+    if other_property is False:
+        # No backref
+        return relationship(
+            lambda: _get_class_for_table(model_class, other_table),
+            **relationship_kwargs
+        )
+    else:
+        if other_property is None:
+            other_property = model_class.__tablename__
+        backref_kwargs = backref_kwargs or {}
+        return relationship(
+            lambda: _get_class_for_table(model_class, other_table),
+            backref=backref(other_property, **backref_kwargs),
+            **relationship_kwargs
+        )
+
+
+def _get_class_for_table(model_class, tablename):
+    if tablename in (model_class.__name__, model_class.__tablename__):
+        return model_class
+
+    for table_cls in model_class._decl_class_registry.values():
+        if tablename == getattr(table_cls, '__tablename__', None):
+            return table_cls
+
+    raise ValueError('unknown table: {0}'.format(tablename))
+
+
+def _get_secondary_table(metadata,
+                         name,
+                         first_column,
+                         second_column,
+                         first_foreign_key,
+                         second_foreign_key):
+    return Table(
+        name,
+        metadata,
+        Column(
+            first_column,
+            Integer,
+            ForeignKey(first_foreign_key)
+        ),
+        Column(
+            second_column,
+            Integer,
+            ForeignKey(second_foreign_key)
+        )
+    )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/relationships.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationships.py b/aria/modeling/relationships.py
deleted file mode 100644
index 76f07f9..0000000
--- a/aria/modeling/relationships.py
+++ /dev/null
@@ -1,402 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# pylint: disable=invalid-name, redefined-outer-name
-
-from sqlalchemy.orm import relationship, backref
-from sqlalchemy.orm.collections import attribute_mapped_collection
-from sqlalchemy import (
-    Column,
-    ForeignKey,
-    Integer,
-    Table
-)
-
-from ..utils import formatting
-
-
-def fk(other_table,
-       nullable=False):
-    """
-    Declare a foreign key property, which will also create a foreign key column in the table with
-    the name of the property. By convention the property name should end in "_fk".
-
-    You are required to explicitly create foreign keys in order to allow for one-to-one,
-    one-to-many, and many-to-one relationships (but not for many-to-many relationships). If you do
-    not do so, SQLAlchemy will fail to create the relationship property and raise an exception with
-    a clear error message.
-
-    You should normally not have to access this property directly, but instead use the associated
-    relationship properties.
-
-    *This utility method should only be used during class creation.*
-
-    :param other_table: Other table name
-    :type other_table: basestring
-    :param nullable: True to allow null values (meaning that there is no relationship)
-    :type nullable: bool
-    """
-
-    return Column(Integer,
-                  ForeignKey('{table}.id'.format(table=other_table), ondelete='CASCADE'),
-                  nullable=nullable)
-
-
-def one_to_one_self(model_class,
-                    fk,
-                    relationship_kwargs=None):
-    """
-    Declare a one-to-one relationship property. The property value would be an instance of the same
-    model.
-
-    You will need an associated foreign key to our own table.
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param fk: Foreign key name
-    :type fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    """
-
-    relationship_kwargs = relationship_kwargs or {}
-
-    remote_side = '{model_class}.{remote_column}'.format(
-        model_class=model_class.__name__,
-        remote_column=model_class.id_column_name()
-    )
-
-    primaryjoin = '{remote_side} == {model_class}.{column}'.format(
-        remote_side=remote_side,
-        model_class=model_class.__name__,
-        column=fk
-    )
-
-    return relationship(
-        _get_class_for_table(model_class, model_class.__tablename__).__name__,
-        primaryjoin=primaryjoin,
-        remote_side=remote_side,
-        post_update=True,
-        **relationship_kwargs
-    )
-
-
-def one_to_many_self(model_class,
-                     fk,
-                     dict_key=None,
-                     relationship_kwargs=None):
-    """
-    Declare a one-to-many relationship property. The property value would be a list or dict of
-    instances of the same model.
-
-    You will need an associated foreign key to our own table.
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param fk: Foreign key name
-    :type fk: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    """
-
-    relationship_kwargs = relationship_kwargs or {}
-
-    relationship_kwargs.setdefault('remote_side', '{model_class}.{remote_column}'.format(
-        model_class=model_class.__name__,
-        remote_column=fk
-    ))
-
-    return _relationship(model_class, model_class.__tablename__, None, relationship_kwargs,
-                         other_property=False, dict_key=dict_key)
-
-
-def one_to_one(model_class,
-               other_table,
-               fk=None,
-               other_fk=None,
-               other_property=None,
-               relationship_kwargs=None,
-               backref_kwargs=None):
-    """
-    Declare a one-to-one relationship property. The property value would be an instance of the other
-    table's model.
-
-    You have two options for the foreign key. Either this table can have an associated key to the
-    other table (use the `fk` argument) or the other table can have an associated foreign key to
-    this our table (use the `other_fk` argument).
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param other_table: Other table name
-    :type other_table: basestring
-    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-    :type fk: basestring
-    :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
-    :type other_fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, fk=fk, other_fk=other_fk)
-
-
-def one_to_many(model_class,
-                child_table,
-                child_fk=None,
-                dict_key=None,
-                child_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
-    """
-    Declare a one-to-many relationship property. The property value would be a list or dict of
-    instances of the child table's model.
-
-    The child table will need an associated foreign key to our table.
-
-    The declaration will automatically create a matching many-to-one property at the child model,
-    named after our table name. Use the `child_property` argument to override this name.
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param child_table: Child table name
-    :type child_table: basestring
-    :param child_fk: Foreign key name at the child table (no need specify if there's no ambiguity)
-    :type child_fk: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param child_property: Override name of matching many-to-one property at child table; set to
-                           false to disable
-    :type child_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, child_table, backref_kwargs, relationship_kwargs,
-                         child_property, other_fk=child_fk, dict_key=dict_key)
-
-
-def many_to_one(model_class,
-                parent_table,
-                fk=None,
-                parent_fk=None,
-                parent_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
-    """
-    Declare a many-to-one relationship property. The property value would be an instance of the
-    parent table's model.
-
-    You will need an associated foreign key to the parent table.
-
-    The declaration will automatically create a matching one-to-many property at the child model,
-    named after the plural form of our table name. Use the `parent_property` argument to override
-    this name. Note: the automatic property will always be a SQLAlchemy query object; if you need a
-    Python collection then use :meth:`one_to_many` at that model.
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param parent_table: Parent table name
-    :type parent_table: basestring
-    :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
-    :type fk: basestring
-    :param parent_property: Override name of matching one-to-many property at parent table; set to
-                            false to disable
-    :type parent_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    if parent_property is None:
-        parent_property = formatting.pluralize(model_class.__tablename__)
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-    backref_kwargs.setdefault('lazy', 'dynamic')
-    backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
-
-    return _relationship(model_class, parent_table, backref_kwargs, relationship_kwargs,
-                         parent_property, fk=fk, other_fk=parent_fk)
-
-
-def many_to_many(model_class,
-                 other_table,
-                 prefix=None,
-                 dict_key=None,
-                 other_property=None,
-                 relationship_kwargs=None,
-                 backref_kwargs=None):
-    """
-    Declare a many-to-many relationship property. The property value would be a list or dict of
-    instances of the other table's model.
-
-    You do not need associated foreign keys for this relationship. Instead, an extra table will be
-    created for you.
-
-    The declaration will automatically create a matching many-to-many property at the other model,
-    named after the plural form of our table name. Use the `other_property` argument to override
-    this name. Note: the automatic property will always be a SQLAlchemy query object; if you need a
-    Python collection then use :meth:`many_to_many` again at that model.
-
-    *This utility method should only be used during class creation.*
-
-    :param model_class: The class in which this relationship will be declared
-    :type model_class: type
-    :param parent_table: Parent table name
-    :type parent_table: basestring
-    :param prefix: Optional prefix for extra table name as well as for `other_property`
-    :type prefix: basestring
-    :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
-                     be a list
-    :type dict_key: basestring
-    :param other_property: Override name of matching many-to-many property at other table; set to
-                           false to disable
-    :type other_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy `relationship`
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy `backref`
-    :type backref_kwargs: {}
-    """
-
-    this_table = model_class.__tablename__
-    this_column_name = '{0}_id'.format(this_table)
-    this_foreign_key = '{0}.id'.format(this_table)
-
-    other_column_name = '{0}_id'.format(other_table)
-    other_foreign_key = '{0}.id'.format(other_table)
-
-    secondary_table = '{0}_{1}'.format(this_table, other_table)
-
-    if other_property is None:
-        other_property = formatting.pluralize(this_table)
-        if prefix is not None:
-            secondary_table = '{0}_{1}'.format(prefix, secondary_table)
-            other_property = '{0}_{1}'.format(prefix, other_property)
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-
-    relationship_kwargs = relationship_kwargs or {}
-    relationship_kwargs.setdefault('secondary', _get_secondary_table(
-        model_class.metadata,
-        secondary_table,
-        this_column_name,
-        other_column_name,
-        this_foreign_key,
-        other_foreign_key
-    ))
-
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, dict_key=dict_key)
-
-
-def _relationship(model_class, other_table, backref_kwargs, relationship_kwargs, other_property,
-                  fk=None, other_fk=None, dict_key=None):
-    relationship_kwargs = relationship_kwargs or {}
-
-    if fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               model_class.__tablename__),
-                                           fk))
-
-    elif other_fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               other_table),
-                                           other_fk))
-
-    if dict_key:
-        relationship_kwargs.setdefault('collection_class',
-                                       attribute_mapped_collection(dict_key))
-
-    if other_property is False:
-        # No backref
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            **relationship_kwargs
-        )
-    else:
-        if other_property is None:
-            other_property = model_class.__tablename__
-        backref_kwargs = backref_kwargs or {}
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            backref=backref(other_property, **backref_kwargs),
-            **relationship_kwargs
-        )
-
-
-def _get_class_for_table(model_class, tablename):
-    if tablename in (model_class.__name__, model_class.__tablename__):
-        return model_class
-
-    for table_cls in model_class._decl_class_registry.values():
-        if tablename == getattr(table_cls, '__tablename__', None):
-            return table_cls
-
-    raise ValueError('unknown table: {0}'.format(tablename))
-
-
-def _get_secondary_table(metadata,
-                         name,
-                         first_column,
-                         second_column,
-                         first_foreign_key,
-                         second_foreign_key):
-    return Table(
-        name,
-        metadata,
-        Column(
-            first_column,
-            Integer,
-            ForeignKey(first_foreign_key)
-        ),
-        Column(
-            second_column,
-            Integer,
-            ForeignKey(second_foreign_key)
-        )
-    )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index bd59b35..a33e6ae 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -35,7 +35,7 @@ from sqlalchemy.ext.declarative import declared_attr
 
 from .types import (List, Dict)
 from .mixins import ModelMixin
-from . import relationships
+from . import relationship
 
 
 class ServiceUpdateBase(ModelMixin):
@@ -47,8 +47,10 @@ class ServiceUpdateBase(ModelMixin):
 
     __tablename__ = 'service_update'
 
-    _private_fields = ['execution_fk',
-                       'service_fk']
+    __private_fields__ = ['service_fk',
+                          'execution_fk',
+                          'execution_name',
+                          'service_name']
 
     created_at = Column(DateTime, nullable=False, index=True)
     service_plan = Column(Dict, nullable=False)
@@ -60,21 +62,21 @@ class ServiceUpdateBase(ModelMixin):
 
     @declared_attr
     def execution(cls):
-        return relationships.many_to_one(cls, 'execution')
+        return relationship.many_to_one(cls, 'execution')
 
     @declared_attr
     def service(cls):
-        return relationships.many_to_one(cls, 'service', parent_property='updates')
+        return relationship.many_to_one(cls, 'service', parent_property='updates')
 
     # region foreign keys
 
     @declared_attr
     def execution_fk(cls):
-        return relationships.fk('execution', nullable=True)
+        return relationship.foreign_key('execution', nullable=True)
 
     @declared_attr
     def service_fk(cls):
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     # endregion
 
@@ -98,11 +100,6 @@ class ServiceUpdateBase(ModelMixin):
         dep_update_dict['steps'] = [step.to_dict() for step in self.steps]
         return dep_update_dict
 
-    __private_fields__ = ['service_fk',
-                          'execution_fk',
-                          'execution_name',
-                          'service_name']
-
 
 class ServiceUpdateStepBase(ModelMixin):
     """
@@ -111,6 +108,9 @@ class ServiceUpdateStepBase(ModelMixin):
 
     __tablename__ = 'service_update_step'
 
+    __private_fields__ = ['service_update_fk',
+                          'service_update_name']
+
     _action_types = namedtuple('ACTION_TYPES', 'ADD, REMOVE, MODIFY')
     ACTION_TYPES = _action_types(ADD='add', REMOVE='remove', MODIFY='modify')
 
@@ -135,13 +135,13 @@ class ServiceUpdateStepBase(ModelMixin):
 
     @declared_attr
     def service_update(cls):
-        return relationships.many_to_one(cls, 'service_update', parent_property='steps')
+        return relationship.many_to_one(cls, 'service_update', parent_property='steps')
 
     # region foreign keys
 
     @declared_attr
     def service_update_fk(cls):
-        return relationships.fk('service_update')
+        return relationship.foreign_key('service_update')
 
     # endregion
 
@@ -181,9 +181,6 @@ class ServiceUpdateStepBase(ModelMixin):
             return self.entity_type == 'relationship' and other.entity_type == 'node'
         return False
 
-    __private_fields__ = ['service_update_fk',
-                          'service_update_name']
-
 
 class ServiceModificationBase(ModelMixin):
     """
@@ -192,6 +189,9 @@ class ServiceModificationBase(ModelMixin):
 
     __tablename__ = 'service_modification'
 
+    __private_fields__ = ['service_fk',
+                          'service_name']
+
     STARTED = 'started'
     FINISHED = 'finished'
     ROLLEDBACK = 'rolledback'
@@ -208,13 +208,13 @@ class ServiceModificationBase(ModelMixin):
 
     @declared_attr
     def service(cls):
-        return relationships.many_to_one(cls, 'service', parent_property='modifications')
+        return relationship.many_to_one(cls, 'service', parent_property='modifications')
 
     # region foreign keys
 
     @declared_attr
     def service_fk(cls):
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     # endregion
 
@@ -226,6 +226,3 @@ class ServiceModificationBase(ModelMixin):
         return association_proxy('service', cls.name_column_name())
 
     # endregion
-
-    __private_fields__ = ['service_fk',
-                          'service_name']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 3ff0555..dfe4674 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -27,7 +27,7 @@ from ..utils import collections, formatting, console
 from .mixins import InstanceModelMixin, TemplateModelMixin
 from .types import List
 from . import (
-    relationships,
+    relationship,
     utils
 )
 
@@ -111,24 +111,26 @@ class TypeBase(InstanceModelMixin):
 
     __tablename__ = 'type'
 
+    __private_fields__ = ['parent_type_fk']
+
     variant = Column(Text, nullable=False)
     description = Column(Text)
     _role = Column(Text, name='role')
 
     @declared_attr
     def parent(cls):
-        return relationships.one_to_one_self(cls, 'parent_type_fk')
+        return relationship.one_to_one_self(cls, 'parent_type_fk')
 
     @declared_attr
     def children(cls):
-        return relationships.one_to_many_self(cls, 'parent_type_fk')
+        return relationship.one_to_many_self(cls, 'parent_type_fk')
 
     # region foreign keys
 
     @declared_attr
     def parent_type_fk(cls):
         """For Type one-to-many to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     # endregion
 
@@ -182,6 +184,9 @@ class TypeBase(InstanceModelMixin):
         self._append_raw_children(types)
         return types
 
+    def coerce_values(self, container, report_issues):
+        pass
+
     def dump(self):
         context = ConsumptionContext.get_thread_local()
         if self.name:
@@ -197,8 +202,6 @@ class TypeBase(InstanceModelMixin):
             types.append(raw_child)
             child._append_raw_children(types)
 
-    __private_fields__ = ['parent_type_fk']
-
 
 class MetadataBase(TemplateModelMixin):
     """
@@ -220,6 +223,9 @@ class MetadataBase(TemplateModelMixin):
             ('name', self.name),
             ('value', self.value)))
 
+    def coerce_values(self, container, report_issues):
+        pass
+
     def instantiate(self, container):
         from . import models
         return models.Metadata(name=self.name,
@@ -239,6 +245,8 @@ class PluginSpecificationBase(InstanceModelMixin):
 
     __tablename__ = 'plugin_specification'
 
+    __private_fields__ = ['service_template_fk']
+
     archive_name = Column(Text, nullable=False, index=True)
     distribution = Column(Text)
     distribution_release = Column(Text)
@@ -254,15 +262,16 @@ class PluginSpecificationBase(InstanceModelMixin):
     @declared_attr
     def service_template_fk(cls):
         """For ServiceTemplate one-to-many to PluginSpecification"""
-        return relationships.fk('service_template', nullable=True)
+        return relationship.foreign_key('service_template', nullable=True)
 
     # endregion
 
+    def coerce_values(self, container, report_issues):
+        pass
+
     def find_plugin(self, plugins):
         # TODO: this should check versions/distribution and other specification
         for plugin in plugins:
             if plugin.name == self.name:
                 return plugin
         return None
-
-    __private_fields__ = ['service_template_fk']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7d20a848/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 5c2cf54..b97c148 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -29,7 +29,7 @@ from ..parser import validation
 from ..parser.consumption import ConsumptionContext
 from ..utils import collections, formatting, console
 from . import (
-    relationships,
+    relationship,
     utils,
     types as modeling_types
 )
@@ -86,48 +86,52 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     __tablename__ = 'service'
 
+    __private_fields__ = ['substitution_fk',
+                          'service_template_fk',
+                          'service_template_name']
+
     @declared_attr
     def service_template(cls):
-        return relationships.many_to_one(cls, 'service_template')
+        return relationship.many_to_one(cls, 'service_template')
 
     description = Column(Text)
 
     @declared_attr
     def meta_data(cls):
         # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationships.many_to_many(cls, 'metadata', dict_key='name')
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return relationships.one_to_many(cls, 'node', dict_key='name')
+        return relationship.one_to_many(cls, 'node', dict_key='name')
 
     @declared_attr
     def groups(cls):
-        return relationships.one_to_many(cls, 'group', dict_key='name')
+        return relationship.one_to_many(cls, 'group', dict_key='name')
 
     @declared_attr
     def policies(cls):
-        return relationships.one_to_many(cls, 'policy', dict_key='name')
+        return relationship.one_to_many(cls, 'policy', dict_key='name')
 
     @declared_attr
     def substitution(cls):
-        return relationships.one_to_one(cls, 'substitution')
+        return relationship.one_to_one(cls, 'substitution')
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def outputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
     def workflows(cls):
-        return relationships.one_to_many(cls, 'operation', dict_key='name')
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
 
     @declared_attr
     def plugin_specifications(cls):
-        return relationships.many_to_many(cls, 'plugin_specification')
+        return relationship.many_to_many(cls, 'plugin_specification')
 
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
@@ -144,12 +148,12 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     @declared_attr
     def substitution_fk(cls):
         """Service one-to-one to Substitution"""
-        return relationships.fk('substitution', nullable=True)
+        return relationship.foreign_key('substitution', nullable=True)
 
     @declared_attr
     def service_template_fk(cls):
         """For Service many-to-one to ServiceTemplate"""
-        return relationships.fk('service_template', nullable=True)
+        return relationship.foreign_key('service_template', nullable=True)
 
     # endregion
 
@@ -184,11 +188,11 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     def _is_node_a_target(self, source_node, target_node):
         if source_node.outbound_relationships:
-            for relationship in source_node.outbound_relationships:
-                if relationship.target_node.name == target_node.name:
+            for the_relationship in source_node.outbound_relationships:
+                if the_relationship.target_node.name == target_node.name:
                     return True
                 else:
-                    node = relationship.target_node
+                    node = the_relationship.target_node
                     if node is not None:
                         if self._is_node_a_target(node, target_node):
                             return True
@@ -256,30 +260,34 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         console.puts(context.style.node(node.name))
         if node.outbound_relationships:
             with context.style.indent:
-                for relationship in node.outbound_relationships:
-                    if relationship.relationship_template is not None:
-                        relationship_name = context.style.node(
-                            relationship.relationship_template.name)
-                    elif relationship.type is not None:
-                        relationship_name = context.style.type(relationship.type.name)
+                for the_relationship in node.outbound_relationships:
+                    relationship_name = context.style.property(the_relationship.name)
+                    if the_relationship.type is not None:
+                        relationship_type = context.style.type(the_relationship.type.name)
                     else:
-                        relationship_name = '?'
-                    if relationship.target_capability is not None:
-                        capability_name = context.style.node(relationship.target_capability.name)
+                        relationship_type = None
+                    if the_relationship.target_capability is not None:
+                        capability_name = \
+                            context.style.node(the_relationship.target_capability.name)
                     else:
                         capability_name = None
                     if capability_name is not None:
-                        console.puts('-> {0} {1}'.format(relationship_name, capability_name))
+                        if relationship_type is not None:
+                            console.puts('-> {0} ({1}) {2}'.format(relationship_name,
+                                                                   relationship_type,
+                                                                   capability_name))
+                        else:
+                            console.puts('-> {0} {1}'.format(relationship_name, capability_name))
                     else:
-                        console.puts('-> {0}'.format(relationship_name))
-                    target_node = relationship.target_node
+                        if relationship_type is not None:
+                            console.puts('-> {0} ({1})'.format(relationship_name,
+                                                               relationship_type))
+                        else:
+                            console.puts('-> {0}'.format(relationship_name))
+                    target_node = the_relationship.target_node
                     with console.indent(3):
                         self._dump_graph_node(target_node)
 
-    __private_fields__ = ['substitution_fk',
-                          'service_template_fk',
-                          'service_template_name']
-
 
 class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     """
@@ -335,49 +343,55 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     __tablename__ = 'node'
 
+    __private_fields__ = ['type_fk',
+                          'host_fk',
+                          'service_fk',
+                          'node_template_fk',
+                          'service_name']
+
     @declared_attr
     def node_template(cls):
-        return relationships.many_to_one(cls, 'node_template')
+        return relationship.many_to_one(cls, 'node_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return relationships.one_to_many(cls, 'interface', dict_key='name')
+        return relationship.one_to_many(cls, 'interface', dict_key='name')
 
     @declared_attr
     def artifacts(cls):
-        return relationships.one_to_many(cls, 'artifact', dict_key='name')
+        return relationship.one_to_many(cls, 'artifact', dict_key='name')
 
     @declared_attr
     def capabilities(cls):
-        return relationships.one_to_many(cls, 'capability', dict_key='name')
+        return relationship.one_to_many(cls, 'capability', dict_key='name')
 
     @declared_attr
     def outbound_relationships(cls):
-        return relationships.one_to_many(cls, 'relationship', child_fk='source_node_fk',
-                                         child_property='source_node')
+        return relationship.one_to_many(cls, 'relationship', child_fk='source_node_fk',
+                                        child_property='source_node')
 
     @declared_attr
     def inbound_relationships(cls):
-        return relationships.one_to_many(cls, 'relationship', child_fk='target_node_fk',
-                                         child_property='target_node')
+        return relationship.one_to_many(cls, 'relationship', child_fk='target_node_fk',
+                                        child_property='target_node')
 
     @declared_attr
     def plugin_specifications(cls):
-        return relationships.many_to_many(cls, 'plugin_specification', dict_key='name')
+        return relationship.many_to_many(cls, 'plugin_specification', dict_key='name')
 
     @declared_attr
     def host(cls):
-        return relationships.one_to_one_self(cls, 'host_fk')
+        return relationship.one_to_one_self(cls, 'host_fk')
 
     # region orchestration
 
@@ -409,22 +423,22 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     @declared_attr
     def type_fk(cls):
         """For Node many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def host_fk(cls):
         """For Node one-to-one to Node"""
-        return relationships.fk('node', nullable=True)
+        return relationship.foreign_key('node', nullable=True)
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Node"""
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     @declared_attr
     def node_template_fk(cls):
         """For Node many-to-one to NodeTemplate"""
-        return relationships.fk('node_template', nullable=True)
+        return relationship.foreign_key('node_template', nullable=True)
 
     # endregion
 
@@ -479,14 +493,14 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
             if target_node is not None:
                 if requirement_template.relationship_template is not None:
-                    relationship = \
+                    the_relationship = \
                         requirement_template.relationship_template.instantiate(self)
                 else:
-                    relationship = models.Relationship(target_capability=target_capability)
-                relationship.name = requirement_template.name
-                relationship.requirement_template = requirement_template
-                relationship.target_node = target_node
-                self.outbound_relationships.append(relationship)
+                    the_relationship = models.Relationship(target_capability=target_capability)
+                the_relationship.name = requirement_template.name
+                the_relationship.requirement_template = requirement_template
+                the_relationship.target_node = target_node
+                self.outbound_relationships.append(the_relationship)
                 return True
             else:
                 context.validation.report('requirement "{0}" of node "{1}" targets node '
@@ -569,12 +583,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             utils.dump_dict_values(self.capabilities, 'Capabilities')
             utils.dump_list_values(self.outbound_relationships, 'Relationships')
 
-    __private_fields__ = ['type_fk',
-                          'host_fk',
-                          'service_fk',
-                          'node_template_fk',
-                          'service_name']
-
 class GroupBase(InstanceModelMixin):
     """
     Usually an instance of a :class:`GroupTemplate`.
@@ -602,44 +610,48 @@ class GroupBase(InstanceModelMixin):
 
     __tablename__ = 'group'
 
+    __private_fields__ = ['type_fk',
+                          'service_fk',
+                          'group_template_fk']
+
     @declared_attr
     def group_template(cls):
-        return relationships.many_to_one(cls, 'group_template')
+        return relationship.many_to_one(cls, 'group_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def nodes(cls):
-        return relationships.many_to_many(cls, 'node')
+        return relationship.many_to_many(cls, 'node')
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return relationships.one_to_many(cls, 'interface', dict_key='name')
+        return relationship.one_to_many(cls, 'interface', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Group many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Group"""
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     @declared_attr
     def group_template_fk(cls):
         """For Group many-to-one to GroupTemplate"""
-        return relationships.fk('group_template', nullable=True)
+        return relationship.foreign_key('group_template', nullable=True)
 
     # endregion
 
@@ -671,10 +683,6 @@ class GroupBase(InstanceModelMixin):
                     for node in self.nodes:
                         console.puts(context.style.node(node.name))
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'group_template_fk']
-
 
 class PolicyBase(InstanceModelMixin):
     """
@@ -701,44 +709,48 @@ class PolicyBase(InstanceModelMixin):
 
     __tablename__ = 'policy'
 
+    __private_fields__ = ['type_fk',
+                          'service_fk',
+                          'policy_template_fk']
+
     @declared_attr
     def policy_template(cls):
-        return relationships.many_to_one(cls, 'policy_template')
+        return relationship.many_to_one(cls, 'policy_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def nodes(cls):
-        return relationships.many_to_many(cls, 'node')
+        return relationship.many_to_many(cls, 'node')
 
     @declared_attr
     def groups(cls):
-        return relationships.many_to_many(cls, 'group')
+        return relationship.many_to_many(cls, 'group')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Policy many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Policy"""
-        return relationships.fk('service')
+        return relationship.foreign_key('service')
 
     @declared_attr
     def policy_template_fk(cls):
         """For Policy many-to-one to PolicyTemplate"""
-        return relationships.fk('policy_template', nullable=True)
+        return relationship.foreign_key('policy_template', nullable=True)
 
     # endregion
 
@@ -772,10 +784,6 @@ class PolicyBase(InstanceModelMixin):
                     for group in self.groups:
                         console.puts(context.style.node(group.name))
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'policy_template_fk']
-
 
 class SubstitutionBase(InstanceModelMixin):
     """
@@ -796,29 +804,32 @@ class SubstitutionBase(InstanceModelMixin):
 
     __tablename__ = 'substitution'
 
+    __private_fields__ = ['node_type_fk',
+                          'substitution_template_fk']
+
     @declared_attr
     def substitution_template(cls):
-        return relationships.many_to_one(cls, 'substitution_template')
+        return relationship.many_to_one(cls, 'substitution_template')
 
     @declared_attr
     def node_type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     @declared_attr
     def mappings(cls):
-        return relationships.one_to_many(cls, 'substitution_mapping', dict_key='name')
+        return relationship.one_to_many(cls, 'substitution_mapping', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def node_type_fk(cls):
         """For Substitution many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def substitution_template_fk(cls):
         """For Substitution many-to-one to SubstitutionTemplate"""
-        return relationships.fk('substitution_template', nullable=True)
+        return relationship.foreign_key('substitution_template', nullable=True)
 
     # endregion
 
@@ -841,9 +852,6 @@ class SubstitutionBase(InstanceModelMixin):
             console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
             utils.dump_dict_values(self.mappings, 'Mappings')
 
-    __private_fields__ = ['node_type_fk',
-                          'substitution_template_fk']
-
 
 class SubstitutionMappingBase(InstanceModelMixin):
     """
@@ -868,39 +876,44 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     __tablename__ = 'substitution_mapping'
 
+    __private_fields__ = ['substitution_fk',
+                          'node_fk',
+                          'capability_fk',
+                          'requirement_template_fk']
+
     @declared_attr
     def node(cls):
-        return relationships.one_to_one(cls, 'node')
+        return relationship.one_to_one(cls, 'node')
 
     @declared_attr
     def capability(cls):
-        return relationships.one_to_one(cls, 'capability')
+        return relationship.one_to_one(cls, 'capability')
 
     @declared_attr
     def requirement_template(cls):
-        return relationships.one_to_one(cls, 'requirement_template')
+        return relationship.one_to_one(cls, 'requirement_template')
 
     # region foreign keys
 
     @declared_attr
     def substitution_fk(cls):
         """For Substitution one-to-many to SubstitutionMapping"""
-        return relationships.fk('substitution')
+        return relationship.foreign_key('substitution')
 
     @declared_attr
     def node_fk(cls):
         """For Substitution one-to-one to NodeTemplate"""
-        return relationships.fk('node')
+        return relationship.foreign_key('node')
 
     @declared_attr
     def capability_fk(cls):
         """For Substitution one-to-one to Capability"""
-        return relationships.fk('capability', nullable=True)
+        return relationship.foreign_key('capability', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For Substitution one-to-one to RequirementTemplate"""
-        return relationships.fk('requirement_template', nullable=True)
+        return relationship.foreign_key('requirement_template', nullable=True)
 
     # endregion
 
@@ -909,6 +922,9 @@ class SubstitutionMappingBase(InstanceModelMixin):
         return collections.OrderedDict((
             ('name', self.name)))
 
+    def coerce_values(self, container, report_issues):
+        pass
+
     def validate(self):
         context = ConsumptionContext.get_thread_local()
         if (self.capability is None) and (self.requirement_template is None):
@@ -927,11 +943,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
                                if self.capability
                                else self.requirement_template.name)))
 
-    __private_fields__ = ['substitution_fk',
-                          'node_fk',
-                          'capability_fk',
-                          'requirement_template_fk']
-
 
 class RelationshipBase(InstanceModelMixin):
     """
@@ -969,29 +980,38 @@ class RelationshipBase(InstanceModelMixin):
 
     __tablename__ = 'relationship'
 
+    __private_fields__ = ['type_fk',
+                          'source_node_fk',
+                          'target_node_fk',
+                          'target_capability_fk',
+                          'requirement_template_fk',
+                          'relationship_template_fk',
+                          'source_node_name',
+                          'target_node_name']
+
     @declared_attr
     def relationship_template(cls):
-        return relationships.many_to_one(cls, 'relationship_template')
+        return relationship.many_to_one(cls, 'relationship_template')
 
     @declared_attr
     def requirement_template(cls):
-        return relationships.many_to_one(cls, 'requirement_template')
+        return relationship.many_to_one(cls, 'requirement_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     @declared_attr
     def target_capability(cls):
-        return relationships.one_to_one(cls, 'capability')
+        return relationship.one_to_one(cls, 'capability')
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
     def interfaces(cls):
-        return relationships.one_to_many(cls, 'interface', dict_key='name')
+        return relationship.one_to_many(cls, 'interface', dict_key='name')
 
     # region orchestration
 
@@ -1005,32 +1025,32 @@ class RelationshipBase(InstanceModelMixin):
     @declared_attr
     def type_fk(cls):
         """For Relationship many-to-one to Type"""
-        return relationships.fk('type', nullable=True)
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
     def source_node_fk(cls):
         """For Node one-to-many to Relationship"""
-        return relationships.fk('node')
+        return relationship.foreign_key('node')
 
     @declared_attr
     def target_node_fk(cls):
         """For Node one-to-many to Relationship"""
-        return relationships.fk('node')
+        return relationship.foreign_key('node')
 
     @declared_attr
     def target_capability_fk(cls):
         """For Relationship one-to-one to Capability"""
-        return relationships.fk('capability', nullable=True)
+        return relationship.foreign_key('capability', nullable=True)
 
     @declared_attr
     def requirement_template_fk(cls):
         """For Relationship many-to-one to RequirementTemplate"""
-        return relationships.fk('requirement_template', nullable=True)
+        return relationship.foreign_key('requirement_template', nullable=True)
 
     @declared_attr
     def relationship_template_fk(cls):
         """For Relationship many-to-one to RelationshipTemplate"""
-        return relationships.fk('relationship_template', nullable=True)
+        return relationship.foreign_key('relationship_template', nullable=True)
 
     # endregion
 
@@ -1087,15 +1107,6 @@ class RelationshipBase(InstanceModelMixin):
             utils.dump_dict_values(self.properties, 'Properties')
             utils.dump_interfaces(self.interfaces, 'Interfaces')
 
-    __private_fields__ = ['type_fk',
-                          'source_node_fk',
-                          'target_node_fk',
-                          'target_capability_fk',
-                          'requirement_template_fk',
-                          'relationship_template_fk',
-                          'source_node_name',
-                          'target_node_name']
-
 
 class CapabilityBase(InstanceModelMixin):
     """
@@ -1128,13 +1139,17 @@ class CapabilityBase(InstanceModelMixin):
 
     __tablename__ = 'capability'
 
+    __private_fields__ = ['capability_fk',
+                          'node_fk',
+                          'capability_template_fk']
+
     @declared_attr
     def capability_template(cls):
-        return relationships.many_to_one(cls, 'capability_template')
+        return relationship.many_to_one(cls, 'capability_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     min_occurrences = Column(Integer, default=None)
     max_occurrences = Column(Integer, default=None)
@@ -1142,24 +1157,24 @@ class CapabilityBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Capability many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Capability"""
-        return relationships.fk('node')
+        return relationship.foreign_key('node')
 
     @declared_attr
     def capability_template_fk(cls):
         """For Capability many-to-one to CapabilityTemplate"""
-        return relationships.fk('capability_template', nullable=True)
+        return relationship.foreign_key('capability_template', nullable=True)
 
     # endregion
 
@@ -1202,10 +1217,6 @@ class CapabilityBase(InstanceModelMixin):
                 else ' or more'))
             utils.dump_dict_values(self.properties, 'Properties')
 
-    __private_fields__ = ['capability_fk',
-                          'node_fk',
-                          'capability_template_fk']
-
 
 class InterfaceBase(InstanceModelMixin):
     """
@@ -1236,50 +1247,56 @@ class InterfaceBase(InstanceModelMixin):
 
     __tablename__ = 'interface'
 
+    __private_fields__ = ['type_fk',
+                          'node_fk',
+                          'group_fk',
+                          'relationship_fk',
+                          'interface_template_fk']
+
     @declared_attr
     def interface_template(cls):
-        return relationships.many_to_one(cls, 'interface_template')
+        return relationship.many_to_one(cls, 'interface_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
     def operations(cls):
-        return relationships.one_to_many(cls, 'operation', dict_key='name')
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Interface many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Interface"""
-        return relationships.fk('node', nullable=True)
+        return relationship.foreign_key('node', nullable=True)
 
     @declared_attr
     def group_fk(cls):
         """For Group one-to-many to Interface"""
-        return relationships.fk('group', nullable=True)
+        return relationship.foreign_key('group', nullable=True)
 
     @declared_attr
     def relationship_fk(cls):
         """For Relationship one-to-many to Interface"""
-        return relationships.fk('relationship', nullable=True)
+        return relationship.foreign_key('relationship', nullable=True)
 
     @declared_attr
     def interface_template_fk(cls):
         """For Interface many-to-one to InterfaceTemplate"""
-        return relationships.fk('interface_template', nullable=True)
+        return relationship.foreign_key('interface_template', nullable=True)
 
     # endregion
 
@@ -1310,12 +1327,6 @@ class InterfaceBase(InstanceModelMixin):
             utils.dump_dict_values(self.inputs, 'Inputs')
             utils.dump_dict_values(self.operations, 'Operations')
 
-    __private_fields__ = ['type_fk',
-                          'node_fk',
-                          'group_fk',
-                          'relationship_fk',
-                          'interface_template_fk']
-
 
 class OperationBase(InstanceModelMixin):
     """
@@ -1352,22 +1363,27 @@ class OperationBase(InstanceModelMixin):
 
     __tablename__ = 'operation'
 
+    __private_fields__ = ['service_fk',
+                          'interface_fk',
+                          'plugin_fk',
+                          'operation_template_fk']
+
     @declared_attr
     def operation_template(cls):
-        return relationships.many_to_one(cls, 'operation_template')
+        return relationship.many_to_one(cls, 'operation_template')
 
     description = Column(Text)
 
     @declared_attr
     def plugin_specification(cls):
-        return relationships.one_to_one(cls, 'plugin_specification')
+        return relationship.one_to_one(cls, 'plugin_specification')
 
     implementation = Column(Text)
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
 
     @declared_attr
     def inputs(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     executor = Column(Text)
     max_retries = Column(Integer)
@@ -1378,22 +1394,22 @@ class OperationBase(InstanceModelMixin):
     @declared_attr
     def service_fk(cls):
         """For Service one-to-many to Operation"""
-        return relationships.fk('service', nullable=True)
+        return relationship.foreign_key('service', nullable=True)
 
     @declared_attr
     def interface_fk(cls):
         """For Interface one-to-many to Operation"""
-        return relationships.fk('interface', nullable=True)
+        return relationship.foreign_key('interface', nullable=True)
 
     @declared_attr
     def plugin_specification_fk(cls):
         """For Operation one-to-one to PluginSpecification"""
-        return relationships.fk('plugin_specification', nullable=True)
+        return relationship.foreign_key('plugin_specification', nullable=True)
 
     @declared_attr
     def operation_template_fk(cls):
         """For Operation many-to-one to OperationTemplate"""
-        return relationships.fk('operation_template', nullable=True)
+        return relationship.foreign_key('operation_template', nullable=True)
 
     # endregion
 
@@ -1438,11 +1454,6 @@ class OperationBase(InstanceModelMixin):
                     context.style.literal(self.retry_interval)))
             utils.dump_dict_values(self.inputs, 'Inputs')
 
-    __private_fields__ = ['service_fk',
-                          'interface_fk',
-                          'plugin_fk',
-                          'operation_template_fk']
-
 
 class ArtifactBase(InstanceModelMixin):
     """
@@ -1475,13 +1486,17 @@ class ArtifactBase(InstanceModelMixin):
 
     __tablename__ = 'artifact'
 
+    __private_fields__ = ['type_fk',
+                          'node_fk',
+                          'artifact_template_fk']
+
     @declared_attr
     def artifact_template(cls):
-        return relationships.many_to_one(cls, 'artifact_template')
+        return relationship.many_to_one(cls, 'artifact_template')
 
     @declared_attr
     def type(cls):
-        return relationships.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type')
 
     description = Column(Text)
     source_path = Column(Text)
@@ -1491,24 +1506,24 @@ class ArtifactBase(InstanceModelMixin):
 
     @declared_attr
     def properties(cls):
-        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # region foreign_keys
 
     @declared_attr
     def type_fk(cls):
         """For Artifact many-to-one to Type"""
-        return relationships.fk('type')
+        return relationship.foreign_key('type')
 
     @declared_attr
     def node_fk(cls):
         """For Node one-to-many to Artifact"""
-        return relationships.fk('node')
+        return relationship.foreign_key('node')
 
     @declared_attr
     def artifact_template_fk(cls):
         """For Artifact many-to-one to ArtifactTemplate"""
-        return relationships.fk('artifact_template', nullable=True)
+        return relationship.foreign_key('artifact_template', nullable=True)
 
     # endregion
 
@@ -1547,7 +1562,3 @@ class ArtifactBase(InstanceModelMixin):
                 console.puts('Repository credential: {0}'.format(
                     context.style.literal(self.repository_credential)))
             utils.dump_dict_values(self.properties, 'Properties')
-
-    __private_fields__ = ['type_fk',
-                          'node_fk',
-                          'artifact_template_fk']