You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ariatosca.apache.org by mx...@apache.org on 2017/07/02 18:44:29 UTC

[08/12] incubator-ariatosca git commit: ARIA-286 Sphinx documentation for code and CLI

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index c98a866..883ff4a 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -14,9 +14,7 @@
 # limitations under the License.
 
 """
-classes:
-    * ModelMixin - abstract model implementation.
-    * ModelIDMixin - abstract model implementation with IDs.
+ARIA modeling mix-ins module
 """
 
 from sqlalchemy.ext import associationproxy
@@ -49,11 +47,11 @@ class ModelMixin(object):
 
     def to_dict(self, fields=None, suppress_error=False):
         """
-        Return a dict representation of the model
+        Create a dict representation of the model.
 
-        :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)
+        :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)
         """
 
         res = dict()
@@ -79,14 +77,14 @@ class ModelMixin(object):
     @classmethod
     def fields(cls):
         """
-        Return the list of field names for this table
+        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())
         fields.update(cls.__table__.columns.keys())
-        return fields - set(getattr(cls, '__private_fields__', []))
+        return fields - set(getattr(cls, '__private_fields__', ()))
 
     @classmethod
     def _iter_association_proxies(cls):
@@ -101,8 +99,17 @@ class ModelMixin(object):
 
 
 class ModelIDMixin(object):
-    id = Column(Integer, primary_key=True, autoincrement=True)
-    name = Column(Text, index=True)
+    id = Column(Integer, primary_key=True, autoincrement=True, doc="""
+    Unique ID.
+    
+    :type: :obj:`int`
+    """)
+
+    name = Column(Text, index=True, doc="""
+    Model name.
+    
+    :type: :obj:`basestring`
+    """)
 
     @classmethod
     def id_column_name(cls):
@@ -115,10 +122,10 @@ class ModelIDMixin(object):
 
 class InstanceModelMixin(ModelMixin):
     """
-    Mixin for :class:`ServiceInstance` models.
+    Mix-in for service instance models.
 
-    All models support validation, diagnostic dumping, and representation as
-    raw data (which can be translated into JSON or YAML) via ``as_raw``.
+    All models support validation, diagnostic dumping, and representation as raw data (which can be
+    translated into JSON or YAML) via :meth:`as_raw`.
     """
 
     @property
@@ -137,9 +144,9 @@ class InstanceModelMixin(ModelMixin):
 
 class TemplateModelMixin(InstanceModelMixin):
     """
-    Mixin for :class:`ServiceTemplate` models.
+    Mix-in for service template models.
 
-    All model models can be instantiated into :class:`ServiceInstance` models.
+    All model models can be instantiated into service instance models.
     """
 
     def instantiate(self, container):
@@ -148,24 +155,26 @@ class TemplateModelMixin(InstanceModelMixin):
 
 class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):                                 #pylint: disable=abstract-method
     """
-    Represents a typed value. The value can contain nested intrinsic functions.
+    Mix-in for typed values. The value can contain nested intrinsic functions.
 
-    This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.
-
-    :ivar name: Name
-    :vartype name: basestring
-    :ivar type_name: Type name
-    :vartype type_name: basestring
-    :ivar value: Value
-    :ivar description: Description
-    :vartype description: basestring
+    This model can be used as the ``container_holder`` argument for
+    :func:`~aria.modeling.functions.evaluate`.
     """
 
     __tablename__ = 'parameter'
 
-    name = Column(Text)
-    type_name = Column(Text)
-    description = Column(Text)
+    type_name = Column(Text, doc="""
+    Type name.
+    
+    :type: :obj:`basestring`
+    """)
+
+    description = Column(Text, doc="""
+    Human-readable description.
+    
+    :type: :obj:`basestring`
+    """)
+
     _value = Column(PickleType)
 
     @property
@@ -187,8 +196,10 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
         """
         The sole owner of this parameter, which is another model that relates to it.
 
-        *All* parameters should have an owner model. In case this property method fails to find
-        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
+        *All* parameters should have an owner model.
+
+        :raises ~exceptions.ValueError: if failed to find an owner, which signifies an abnormal,
+         orphaned parameter
         """
 
         # Find first non-null relationship
@@ -210,8 +221,10 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
         The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in
         TOSCA.
 
-        *All* parameters should have a container model. In case this property method fails to find
-        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
+        *All* parameters should have a container model.
+
+        :raises ~exceptions.ValueError: if failed to find a container model, which signifies an
+         abnormal, orphaned parameter
         """
 
         from . import models
@@ -253,7 +266,11 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
     @caching.cachedmethod
     def service(self):
         """
-        The :class:`Service` containing this parameter, or None if not contained in a service.
+        The :class:`~aria.modeling.models.Service` model containing this parameter, or ``None`` if
+        not contained in a service.
+
+        :raises ~exceptions.ValueError: if failed to find a container model, which signifies an
+         abnormal, orphaned parameter
         """
 
         from . import models
@@ -268,8 +285,11 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
     @caching.cachedmethod
     def service_template(self):
         """
-        The :class:`ServiceTemplate` containing this parameter, or None if not contained in a
-        service template.
+        The :class:`~aria.modeling.models.ServiceTemplate` model containing this parameter, or
+        ``None`` if not contained in a service template.
+
+        :raises ~exceptions.ValueError: if failed to find a container model, which signifies an
+         abnormal, orphaned parameter
         """
 
         from . import models
@@ -329,10 +349,10 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
         cos01 specification <http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01
         /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__
 
-        :param name: Parameter name
+        :param name: parameter name
         :type name: basestring
-        :param value: Parameter value
-        :param description: Description (optional)
+        :param value: parameter value
+        :param description: human-readable description (optional)
         :type description: basestring
         """
 
@@ -345,7 +365,6 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):
                    description=description)
 
     def as_other_parameter_model(self, other_model_cls):
-
         name, value = self.unwrapped
         return other_model_cls.wrap(name, value)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/models.py
----------------------------------------------------------------------
diff --git a/aria/modeling/models.py b/aria/modeling/models.py
index f30b86f..cf84fdb 100644
--- a/aria/modeling/models.py
+++ b/aria/modeling/models.py
@@ -13,6 +13,74 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""
+Data models.
+
+Service template models
+-----------------------
+
+.. autosummary::
+   :nosignatures:
+
+   aria.modeling.models.ServiceTemplate
+   aria.modeling.models.NodeTemplate
+   aria.modeling.models.GroupTemplate
+   aria.modeling.models.PolicyTemplate
+   aria.modeling.models.SubstitutionTemplate
+   aria.modeling.models.SubstitutionTemplateMapping
+   aria.modeling.models.RequirementTemplate
+   aria.modeling.models.RelationshipTemplate
+   aria.modeling.models.CapabilityTemplate
+   aria.modeling.models.InterfaceTemplate
+   aria.modeling.models.OperationTemplate
+   aria.modeling.models.ArtifactTemplate
+   aria.modeling.models.PluginSpecification
+
+Service instance models
+-----------------------
+
+.. autosummary::
+   :nosignatures:
+
+   aria.modeling.models.Service
+   aria.modeling.models.Node
+   aria.modeling.models.Group
+   aria.modeling.models.Policy
+   aria.modeling.models.Substitution
+   aria.modeling.models.SubstitutionMapping
+   aria.modeling.models.Relationship
+   aria.modeling.models.Capability
+   aria.modeling.models.Interface
+   aria.modeling.models.Operation
+   aria.modeling.models.Artifact
+
+Common models
+-------------
+
+.. autosummary::
+   :nosignatures:
+
+   aria.modeling.models.Output
+   aria.modeling.models.Input
+   aria.modeling.models.Configuration
+   aria.modeling.models.Property
+   aria.modeling.models.Attribute
+   aria.modeling.models.Type
+   aria.modeling.models.Metadata
+
+Orchestration models
+--------------------
+
+.. autosummary::
+   :nosignatures:
+
+   aria.modeling.models.Execution
+   aria.modeling.models.Task
+   aria.modeling.models.Log
+   aria.modeling.models.Plugin
+   aria.modeling.models.Argument
+"""
+
 # pylint: disable=abstract-method
 
 from sqlalchemy.ext.declarative import declarative_base
@@ -28,14 +96,15 @@ from . import (
     service_common,
     orchestration,
     mixins,
+    utils
 )
 
+
 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
@@ -91,54 +160,68 @@ __all__ = (
 
 # region service template models
 
+@utils.fix_doc
 class ServiceTemplate(aria_declarative_base, service_template.ServiceTemplateBase):
     name = Column(Text, index=True, unique=True)
 
 
+@utils.fix_doc
 class NodeTemplate(aria_declarative_base, service_template.NodeTemplateBase):
     pass
 
 
+@utils.fix_doc
 class GroupTemplate(aria_declarative_base, service_template.GroupTemplateBase):
     pass
 
 
+@utils.fix_doc
 class PolicyTemplate(aria_declarative_base, service_template.PolicyTemplateBase):
     pass
 
 
+@utils.fix_doc
 class SubstitutionTemplate(aria_declarative_base, service_template.SubstitutionTemplateBase):
     pass
 
 
+@utils.fix_doc
 class SubstitutionTemplateMapping(aria_declarative_base,
                                   service_template.SubstitutionTemplateMappingBase):
     pass
 
 
+@utils.fix_doc
 class RequirementTemplate(aria_declarative_base, service_template.RequirementTemplateBase):
     pass
 
 
+@utils.fix_doc
 class RelationshipTemplate(aria_declarative_base, service_template.RelationshipTemplateBase):
     pass
 
 
+@utils.fix_doc
 class CapabilityTemplate(aria_declarative_base, service_template.CapabilityTemplateBase):
     pass
 
 
+@utils.fix_doc
 class InterfaceTemplate(aria_declarative_base, service_template.InterfaceTemplateBase):
     pass
 
 
+@utils.fix_doc
 class OperationTemplate(aria_declarative_base, service_template.OperationTemplateBase):
     pass
 
 
+@utils.fix_doc
 class ArtifactTemplate(aria_declarative_base, service_template.ArtifactTemplateBase):
     pass
 
+
+@utils.fix_doc
 class PluginSpecification(aria_declarative_base, service_template.PluginSpecificationBase):
     pass
 
@@ -147,46 +230,57 @@ class PluginSpecification(aria_declarative_base, service_template.PluginSpecific
 
 # region service instance models
 
+@utils.fix_doc
 class Service(aria_declarative_base, service_instance.ServiceBase):
     name = Column(Text, index=True, unique=True)
 
 
+@utils.fix_doc
 class Node(aria_declarative_base, service_instance.NodeBase):
     pass
 
 
+@utils.fix_doc
 class Group(aria_declarative_base, service_instance.GroupBase):
     pass
 
 
+@utils.fix_doc
 class Policy(aria_declarative_base, service_instance.PolicyBase):
     pass
 
 
+@utils.fix_doc
 class Substitution(aria_declarative_base, service_instance.SubstitutionBase):
     pass
 
 
+@utils.fix_doc
 class SubstitutionMapping(aria_declarative_base, service_instance.SubstitutionMappingBase):
     pass
 
 
+@utils.fix_doc
 class Relationship(aria_declarative_base, service_instance.RelationshipBase):
     pass
 
 
+@utils.fix_doc
 class Capability(aria_declarative_base, service_instance.CapabilityBase):
     pass
 
 
+@utils.fix_doc
 class Interface(aria_declarative_base, service_instance.InterfaceBase):
     pass
 
 
+@utils.fix_doc
 class Operation(aria_declarative_base, service_instance.OperationBase):
     pass
 
 
+@utils.fix_doc
 class Artifact(aria_declarative_base, service_instance.ArtifactBase):
     pass
 
@@ -195,14 +289,17 @@ class Artifact(aria_declarative_base, service_instance.ArtifactBase):
 
 # region service changes models
 
+@utils.fix_doc
 class ServiceUpdate(aria_declarative_base, service_changes.ServiceUpdateBase):
     pass
 
 
+@utils.fix_doc
 class ServiceUpdateStep(aria_declarative_base, service_changes.ServiceUpdateStepBase):
     pass
 
 
+@utils.fix_doc
 class ServiceModification(aria_declarative_base, service_changes.ServiceModificationBase):
     pass
 
@@ -211,31 +308,37 @@ class ServiceModification(aria_declarative_base, service_changes.ServiceModifica
 
 # region common service models
 
-
+@utils.fix_doc
 class Input(aria_declarative_base, service_common.InputBase):
     pass
 
 
+@utils.fix_doc
 class Configuration(aria_declarative_base, service_common.ConfigurationBase):
     pass
 
 
+@utils.fix_doc
 class Output(aria_declarative_base, service_common.OutputBase):
     pass
 
 
+@utils.fix_doc
 class Property(aria_declarative_base, service_common.PropertyBase):
     pass
 
 
+@utils.fix_doc
 class Attribute(aria_declarative_base, service_common.AttributeBase):
     pass
 
 
+@utils.fix_doc
 class Type(aria_declarative_base, service_common.TypeBase):
     pass
 
 
+@utils.fix_doc
 class Metadata(aria_declarative_base, service_common.MetadataBase):
     pass
 
@@ -244,26 +347,30 @@ class Metadata(aria_declarative_base, service_common.MetadataBase):
 
 # region orchestration models
 
+@utils.fix_doc
 class Execution(aria_declarative_base, orchestration.ExecutionBase):
     pass
 
 
+@utils.fix_doc
 class Plugin(aria_declarative_base, orchestration.PluginBase):
     pass
 
 
+@utils.fix_doc
 class Task(aria_declarative_base, orchestration.TaskBase):
     pass
 
 
+@utils.fix_doc
 class Log(aria_declarative_base, orchestration.LogBase):
     pass
 
 
+@utils.fix_doc
 class Argument(aria_declarative_base, orchestration.ArgumentBase):
     pass
 
-
 # endregion
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index 829c305..7068557 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -14,10 +14,7 @@
 # limitations under the License.
 
 """
-classes:
-    * Execution - execution implementation model.
-    * Plugin - plugin implementation model.
-    * Task - a task
+ARIA modeling orchestration module
 """
 
 # pylint: disable=no-self-argument, no-member, abstract-method
@@ -34,7 +31,6 @@ from sqlalchemy import (
     Float,
     orm,
     PickleType)
-from sqlalchemy.ext.associationproxy import association_proxy
 from sqlalchemy.ext.declarative import declared_attr
 
 from ..orchestrator.exceptions import (TaskAbortException, TaskRetryException)
@@ -47,13 +43,13 @@ from . import (
 
 class ExecutionBase(mixins.ModelMixin):
     """
-    Execution model representation.
+    Workflow execution.
     """
 
     __tablename__ = 'execution'
 
-    __private_fields__ = ['service_fk',
-                          'service_template']
+    __private_fields__ = ('service_fk',
+                          'service_template')
 
     SUCCEEDED = 'succeeded'
     FAILED = 'failed'
@@ -72,50 +68,65 @@ class ExecutionBase(mixins.ModelMixin):
         CANCELLED: PENDING
     }
 
-    @orm.validates('status')
-    def validate_status(self, key, value):
-        """Validation function that verifies execution status transitions are OK"""
-        try:
-            current_status = getattr(self, key)
-        except AttributeError:
-            return
-        valid_transitions = self.VALID_TRANSITIONS.get(current_status, [])
-        if all([current_status is not None,
-                current_status != value,
-                value not in valid_transitions]):
-            raise ValueError('Cannot change execution status from {current} to {new}'.format(
-                current=current_status,
-                new=value))
-        return value
+    # region one_to_many relationships
 
-    created_at = Column(DateTime, index=True)
-    started_at = Column(DateTime, nullable=True, index=True)
-    ended_at = Column(DateTime, nullable=True, index=True)
-    error = Column(Text, nullable=True)
-    status = Column(Enum(*STATES, name='execution_status'), default=PENDING)
-    workflow_name = Column(Text)
+    @declared_attr
+    def inputs(cls):
+        """
+        Execution parameters.
 
-    def has_ended(self):
-        return self.status in self.END_STATES
+        :type: {:obj:`basestring`: :class:`Input`}
+        """
+        return relationship.one_to_many(cls, 'input', dict_key='name')
 
-    def is_active(self):
-        return not self.has_ended() and self.status != self.PENDING
+    @declared_attr
+    def tasks(cls):
+        """
+        Tasks.
+
+        :type: [:class:`Task`]
+        """
+        return relationship.one_to_many(cls, 'task')
 
     @declared_attr
     def logs(cls):
+        """
+        Log messages for the execution (including log messages for its tasks).
+
+        :type: [:class:`Log`]
+        """
         return relationship.one_to_many(cls, 'log')
 
+    # endregion
+
+    # region many_to_one relationships
+
     @declared_attr
     def service(cls):
+        """
+        Associated service.
+
+        :type: :class:`Service`
+        """
         return relationship.many_to_one(cls, 'service')
 
+    # endregion
+
+    # region association proxies
+
     @declared_attr
-    def tasks(cls):
-        return relationship.one_to_many(cls, 'task')
+    def service_name(cls):
+        return relationship.association_proxy('service', cls.name_column_name())
 
     @declared_attr
-    def inputs(cls):
-        return relationship.one_to_many(cls, 'input', dict_key='name')
+    def service_template(cls):
+        return relationship.association_proxy('service', 'service_template')
+
+    @declared_attr
+    def service_template_name(cls):
+        return relationship.association_proxy('service', 'service_template_name')
+
+    # endregion
 
     # region foreign keys
 
@@ -125,92 +136,70 @@ class ExecutionBase(mixins.ModelMixin):
 
     # endregion
 
-    # region association proxies
+    created_at = Column(DateTime, index=True, doc="""
+    Creation timestamp.
 
-    @declared_attr
-    def service_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', cls.name_column_name())
+    :type: :class:`~datetime.datetime`
+    """)
 
-    @declared_attr
-    def service_template(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', 'service_template')
+    started_at = Column(DateTime, nullable=True, index=True, doc="""
+    Started timestamp.
 
-    @declared_attr
-    def service_template_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', 'service_template_name')
+    :type: :class:`~datetime.datetime`
+    """)
 
-    # endregion
+    ended_at = Column(DateTime, nullable=True, index=True, doc="""
+    Ended timestamp.
 
-    def __str__(self):
-        return '<{0} id=`{1}` (status={2})>'.format(
-            self.__class__.__name__,
-            getattr(self, self.name_column_name()),
-            self.status
-        )
+    :type: :class:`~datetime.datetime`
+    """)
 
+    error = Column(Text, nullable=True, doc="""
+    Error message.
 
-class PluginBase(mixins.ModelMixin):
-    """
-    An installed plugin.
+    :type: :obj:`basestring`
+    """)
 
-    Plugins are usually packaged as `wagons <https://github.com/cloudify-cosmo/wagon>`__, which
-    are archives of one or more `wheels <https://packaging.python.org/distributing/#wheels>`__.
-    Most of these fields are indeed extracted from the installed wagon's metadata.
+    status = Column(Enum(*STATES, name='execution_status'), default=PENDING, doc="""
+    Status.
 
-    :ivar archive_name: Filename (not the full path) of the wagon's archive, often with a ".wgn"
-                        extension
-    :vartype archive_name: basestring
-    :ivar distribution: The name of the operating system on which the wagon was installed (e.g.
-                        "ubuntu")
-    :vartype distribution: basestring
-    :ivar distribution_release: The release of the operating system on which the wagon was installed
-                                (e.g. "trusty")
-    :vartype distribution_release: basestring
-    :ivar distribution_version: The version of the operating system on which the wagon was installed
-                                (e.g. "14.04")
-    :vartype distribution_version: basestring
-    :ivar package_name: The primary Python package name used when the wagon was installed, which is
-                        one of the wheels in the wagon (e.g. "cloudify-script-plugin")
-    :vartype package_name: basestring
-    :ivar package_source: The full install string for the primary Python package name used when the
-                          wagon was installed (e.g. "cloudify-script-plugin==1.2")
-    :vartype package_source: basestring
-    :ivar package_version: The version for the primary Python package name used when the wagon was
-                           installed (e.g. "1.2")
-    :vartype package_version: basestring
-    :ivar supported_platform: If the wheels are *all* pure Python then this would be "any",
-                              otherwise it would be the installed platform name (e.g.
-                              "linux_x86_64")
-    :vartype supported_platform: basestring
-    :ivar supported_py_versions: The Python versions supported by all the wheels (e.g. ["py26",
-                                 "py27"])
-    :vartype supported_py_versions: [basestring]
-    :ivar wheels: The filenames of the wheels archived in the wagon, often with a ".whl" extension
-    :vartype wheels: [basestring]
-    :ivar uploaded_at: Timestamp for when the wagon was installed
-    :vartype uploaded_at: basestring
-    """
+    :type: :obj:`basestring`
+    """)
 
-    __tablename__ = 'plugin'
+    workflow_name = Column(Text, doc="""
+    Workflow name.
 
-    @declared_attr
-    def tasks(cls):
-        return relationship.one_to_many(cls, 'task')
+    :type: :obj:`basestring`
+    """)
+
+    @orm.validates('status')
+    def validate_status(self, key, value):
+        """Validation function that verifies execution status transitions are OK"""
+        try:
+            current_status = getattr(self, key)
+        except AttributeError:
+            return
+        valid_transitions = self.VALID_TRANSITIONS.get(current_status, [])
+        if all([current_status is not None,
+                current_status != value,
+                value not in valid_transitions]):
+            raise ValueError('Cannot change execution status from {current} to {new}'.format(
+                current=current_status,
+                new=value))
+        return value
 
-    archive_name = Column(Text, nullable=False, index=True)
-    distribution = Column(Text)
-    distribution_release = Column(Text)
-    distribution_version = Column(Text)
-    package_name = Column(Text, nullable=False, index=True)
-    package_source = Column(Text)
-    package_version = Column(Text)
-    supported_platform = Column(Text)
-    supported_py_versions = Column(modeling_types.StrictList(basestring))
-    wheels = Column(modeling_types.StrictList(basestring), nullable=False)
-    uploaded_at = Column(DateTime, nullable=False, index=True)
+    def has_ended(self):
+        return self.status in self.END_STATES
+
+    def is_active(self):
+        return not self.has_ended() and self.status != self.PENDING
+
+    def __str__(self):
+        return '<{0} id=`{1}` (status={2})>'.format(
+            self.__class__.__name__,
+            getattr(self, self.name_column_name()),
+            self.status
+        )
 
 
 class TaskBase(mixins.ModelMixin):
@@ -219,46 +208,20 @@ class TaskBase(mixins.ModelMixin):
     outputs, as well as an atomic status, ensuring that the task can only be running once at any
     given time.
 
+    The Python :attr:`function` is usually provided by an associated :class:`Plugin`. The
+    :attr:`arguments` of the function should be set according to the specific signature of the
+    function.
+
     Tasks may be "one shot" or may be configured to run repeatedly in the case of failure.
 
     Tasks are often based on :class:`Operation`, and thus act on either a :class:`Node` or a
     :class:`Relationship`, however this is not required.
-
-    :ivar node: The node actor (optional)
-    :vartype node: :class:`Node`
-    :ivar relationship: The relationship actor (optional)
-    :vartype relationship: :class:`Relationship`
-    :ivar plugin: The implementing plugin (set to None for default execution plugin)
-    :vartype plugin: :class:`Plugin`
-    :ivar function: Python path to an ``@operation`` function
-    :vartype function: basestring
-    :ivar arguments: Arguments that can be used by this task
-    :vartype arguments: {basestring: :class:`Argument`}
-    :ivar max_attempts: Maximum number of retries allowed in case of failure
-    :vartype max_attempts: int
-    :ivar retry_interval: Interval between retries (in seconds)
-    :vartype retry_interval: int
-    :ivar ignore_failure: Set to True to ignore failures
-    :vartype ignore_failure: bool
-    :ivar due_at: Timestamp to start the task
-    :vartype due_at: datetime
-    :ivar execution: Assigned execution
-    :vartype execution: :class:`Execution`
-    :ivar status: Current atomic status ('pending', 'retrying', 'sent', 'started', 'success',
-                  'failed')
-    :vartype status: basestring
-    :ivar started_at: Timestamp for when task started
-    :vartype started_at: datetime
-    :ivar ended_at: Timestamp for when task ended
-    :vartype ended_at: datetime
-    :ivar attempts_count: How many attempts occurred
-    :vartype attempts_count: int
     """
 
     __tablename__ = 'task'
 
-    __private_fields__ = ['dependency_operation_task_fk', 'dependency_stub_task_fk', 'node_fk',
-                          'relationship_fk', 'plugin_fk', 'execution_fk']
+    __private_fields__ = ('dependency_operation_task_fk', 'dependency_stub_task_fk', 'node_fk',
+                          'relationship_fk', 'plugin_fk', 'execution_fk')
 
     START_WORKFLOW = 'start_workflow'
     END_WORKFLOW = 'end_workflow'
@@ -292,70 +255,91 @@ class TaskBase(mixins.ModelMixin):
     )
     INFINITE_RETRIES = -1
 
+    # region one_to_many relationships
+
     @declared_attr
-    def execution(cls):
-        return relationship.many_to_one(cls, 'execution')
+    def logs(cls):
+        """
+        Log messages.
+
+        :type: [:class:`Log`]
+        """
+        return relationship.one_to_many(cls, 'log')
 
     @declared_attr
-    def execution_fk(cls):
-        return relationship.foreign_key('execution', nullable=True)
+    def arguments(cls):
+        """
+        Arguments sent to the Python :attr:`function``.
 
-    status = Column(Enum(*STATES, name='status'), default=PENDING)
-    due_at = Column(DateTime, nullable=False, index=True, default=datetime.utcnow())
-    started_at = Column(DateTime, default=None)
-    ended_at = Column(DateTime, default=None)
-    attempts_count = Column(Integer, default=1)
+        :type: {:obj:`basestring`: :class:`Argument`}
+        """
+        return relationship.one_to_many(cls, 'argument', dict_key='name')
 
-    _executor = Column(PickleType)
-    _context_cls = Column(PickleType)
-    _stub_type = Column(Enum(*STUB_TYPES))
+    # endregion
+
+    # region many_one relationships
 
     @declared_attr
-    def logs(cls):
-        return relationship.one_to_many(cls, 'log')
+    def execution(cls):
+        """
+        Containing execution.
+
+        :type: :class:`Execution`
+        """
+        return relationship.many_to_one(cls, 'execution')
 
     @declared_attr
     def node(cls):
+        """
+        Node actor (can be ``None``).
+
+        :type: :class:`Node`
+        """
         return relationship.many_to_one(cls, 'node')
 
     @declared_attr
     def relationship(cls):
+        """
+        Relationship actor (can be ``None``).
+
+        :type: :class:`Relationship`
+        """
         return relationship.many_to_one(cls, 'relationship')
 
     @declared_attr
     def plugin(cls):
+        """
+        Associated plugin.
+
+        :type: :class:`Plugin`
+        """
         return relationship.many_to_one(cls, 'plugin')
 
+    # endregion
+
+    # region association proxies
+
     @declared_attr
-    def arguments(cls):
-        return relationship.one_to_many(cls, 'argument', dict_key='name')
+    def node_name(cls):
+        return relationship.association_proxy('node', cls.name_column_name())
 
-    function = Column(String)
-    max_attempts = Column(Integer, default=1)
-    retry_interval = Column(Float, default=0)
-    ignore_failure = Column(Boolean, default=False)
-    interface_name = Column(String)
-    operation_name = Column(String)
+    @declared_attr
+    def relationship_name(cls):
+        return relationship.association_proxy('relationship', cls.name_column_name())
 
-    @property
-    def actor(self):
-        """
-        Return the actor of the task
-        :return:
-        """
-        return self.node or self.relationship
+    @declared_attr
+    def execution_name(cls):
+        return relationship.association_proxy('execution', cls.name_column_name())
 
-    @orm.validates('max_attempts')
-    def validate_max_attempts(self, _, value):                                  # pylint: disable=no-self-use
-        """Validates that max attempts is either -1 or a positive number"""
-        if value < 1 and value != TaskBase.INFINITE_RETRIES:
-            raise ValueError('Max attempts can be either -1 (infinite) or any positive number. '
-                             'Got {value}'.format(value=value))
-        return value
+    # endregion
 
     # region foreign keys
 
     @declared_attr
+    def execution_fk(cls):
+        return relationship.foreign_key('execution', nullable=True)
+
+    @declared_attr
     def node_fk(cls):
         return relationship.foreign_key('node', nullable=True)
 
@@ -369,24 +353,93 @@ class TaskBase(mixins.ModelMixin):
 
     # endregion
 
-    # region association proxies
+    status = Column(Enum(*STATES, name='status'), default=PENDING, doc="""
+    Current atomic status ('pending', 'retrying', 'sent', 'started', 'success', 'failed').
 
-    @declared_attr
-    def node_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('node', cls.name_column_name())
+    :type: :obj:`basestring`
+    """)
 
-    @declared_attr
-    def relationship_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('relationship', cls.name_column_name())
+    due_at = Column(DateTime, nullable=False, index=True, default=datetime.utcnow(), doc="""
+    Timestamp to start the task.
 
-    @declared_attr
-    def execution_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('execution', cls.name_column_name())
+    :type: :class:`~datetime.datetime`
+    """)
 
-    # endregion
+    started_at = Column(DateTime, default=None, doc="""
+    Started timestamp.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
+    ended_at = Column(DateTime, default=None, doc="""
+    Ended timestamp.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
+    attempts_count = Column(Integer, default=1, doc="""
+    How many attempts occurred.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
+    function = Column(String, doc="""
+    Full path to Python function.
+
+    :type: :obj:`basestring`
+    """)
+
+    max_attempts = Column(Integer, default=1, doc="""
+    Maximum number of attempts allowed in case of task failure.
+
+    :type: :obj:`int`
+    """)
+
+    retry_interval = Column(Float, default=0, doc="""
+    Interval between task retry attemps (in seconds).
+
+    :type: :obj:`float`
+    """)
+
+    ignore_failure = Column(Boolean, default=False, doc="""
+    Set to ``True`` to ignore failures.
+
+    :type: :obj:`bool`
+    """)
+
+    interface_name = Column(String, doc="""
+    Name of interface on node or relationship.
+
+    :type: :obj:`basestring`
+    """)
+
+    operation_name = Column(String, doc="""
+    Name of operation in interface on node or relationship.
+
+    :type: :obj:`basestring`
+    """)
+
+    _api_id = Column(String)
+    _executor = Column(PickleType)
+    _context_cls = Column(PickleType)
+    _stub_type = Column(Enum(*STUB_TYPES))
+
+    @property
+    def actor(self):
+        """
+        Actor of the task (node or relationship).
+        """
+        return self.node or self.relationship
+
+    @orm.validates('max_attempts')
+    def validate_max_attempts(self, _, value):                                  # pylint: disable=no-self-use
+        """
+        Validates that max attempts is either -1 or a positive number.
+        """
+        if value < 1 and value != TaskBase.INFINITE_RETRIES:
+            raise ValueError('Max attempts can be either -1 (infinite) or any positive number. '
+                             'Got {value}'.format(value=value))
+        return value
 
     @staticmethod
     def abort(message=None):
@@ -447,26 +500,36 @@ class TaskBase(mixins.ModelMixin):
 
 
 class LogBase(mixins.ModelMixin):
+    """
+    Single log message.
+    """
 
     __tablename__ = 'log'
 
-    __private_fields__ = ['execution_fk',
-                          'task_fk']
+    __private_fields__ = ('execution_fk',
+                          'task_fk')
+
+    # region many_to_one relationships
 
     @declared_attr
     def execution(cls):
+        """
+        Containing execution.
+
+        :type: :class:`Execution`
+        """
         return relationship.many_to_one(cls, 'execution')
 
     @declared_attr
     def task(cls):
-        return relationship.many_to_one(cls, 'task')
+        """
+        Containing task (can be ``None``).
 
-    level = Column(String)
-    msg = Column(String)
-    created_at = Column(DateTime, index=True)
+        :type: :class:`Task`
+        """
+        return relationship.many_to_one(cls, 'task')
 
-    # In case of failed execution
-    traceback = Column(Text)
+    # endregion
 
     # region foreign keys
 
@@ -480,6 +543,30 @@ class LogBase(mixins.ModelMixin):
 
     # endregion
 
+    level = Column(String, doc="""
+    Log level.
+
+    :type: :obj:`basestring`
+    """)
+
+    msg = Column(String, doc="""
+    Log message.
+
+    :type: :obj:`basestring`
+    """)
+
+    created_at = Column(DateTime, index=True, doc="""
+    Creation timestamp.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
+    traceback = Column(Text, doc="""
+    Error traceback in case of failure.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
     def __str__(self):
         return self.msg
 
@@ -488,30 +575,137 @@ class LogBase(mixins.ModelMixin):
         return '{name}: {self.msg}'.format(name=name, self=self)
 
 
-class ArgumentBase(mixins.ParameterMixin):
+class PluginBase(mixins.ModelMixin):
+    """
+    Installed plugin.
 
-    __tablename__ = 'argument'
+    Plugins are usually packaged as `wagons <https://github.com/cloudify-cosmo/wagon>`__, which
+    are archives of one or more `wheels <https://packaging.python.org/distributing/#wheels>`__.
+    Most of these fields are indeed extracted from the installed wagon's metadata.
+    """
 
-    # region foreign keys
+    __tablename__ = 'plugin'
 
-    @declared_attr
-    def task_fk(cls):
-        return relationship.foreign_key('task', nullable=True)
+    # region one_to_many relationships
 
     @declared_attr
-    def operation_fk(cls):
-        return relationship.foreign_key('operation', nullable=True)
+    def tasks(cls):
+        """
+        Associated Tasks.
+
+        :type: [:class:`Task`]
+        """
+        return relationship.one_to_many(cls, 'task')
 
     # endregion
 
+    archive_name = Column(Text, nullable=False, index=True, doc="""
+    Filename (not the full path) of the wagon's archive, often with a ``.wgn`` extension.
+
+    :type: :obj:`basestring`
+    """)
+
+    distribution = Column(Text, doc="""
+    Name of the operating system on which the wagon was installed (e.g. ``ubuntu``).
+
+    :type: :obj:`basestring`
+    """)
+
+    distribution_release = Column(Text, doc="""
+    Release of the operating system on which the wagon was installed (e.g. ``trusty``).
+
+    :type: :obj:`basestring`
+    """)
+
+    distribution_version = Column(Text, doc="""
+    Version of the operating system on which the wagon was installed (e.g. ``14.04``).
+
+    :type: :obj:`basestring`
+    """)
+
+    package_name = Column(Text, nullable=False, index=True, doc="""
+    Primary Python package name used when the wagon was installed, which is one of the wheels in the
+    wagon (e.g. ``cloudify-script-plugin``).
+
+    :type: :obj:`basestring`
+    """)
+
+    package_source = Column(Text, doc="""
+    Full install string for the primary Python package name used when the wagon was installed (e.g.
+    ``cloudify-script-plugin==1.2``).
+
+    :type: :obj:`basestring`
+    """)
+
+    package_version = Column(Text, doc="""
+    Version for the primary Python package name used when the wagon was installed (e.g. ``1.2``).
+
+    :type: :obj:`basestring`
+    """)
+
+    supported_platform = Column(Text, doc="""
+    If the wheels are *all* pure Python then this would be "any", otherwise it would be the
+    installed platform name (e.g. ``linux_x86_64``).
+
+    :type: :obj:`basestring`
+    """)
+
+    supported_py_versions = Column(modeling_types.StrictList(basestring), doc="""
+    Python versions supported by all the wheels (e.g. ``["py26", "py27"]``)
+
+    :type: [:obj:`basestring`]
+    """)
+
+    wheels = Column(modeling_types.StrictList(basestring), nullable=False, doc="""
+    Filenames of the wheels archived in the wagon, often with a ``.whl`` extension.
+
+    :type: [:obj:`basestring`]
+    """)
+
+    uploaded_at = Column(DateTime, nullable=False, index=True, doc="""
+    Timestamp for when the wagon was installed.
+
+    :type: :class:`~datetime.datetime`
+    """)
+
+
+class ArgumentBase(mixins.ParameterMixin):
+    """
+    Python function argument parameter.
+    """
+
+    __tablename__ = 'argument'
+
     # region many_to_one relationships
 
     @declared_attr
     def task(cls):
+        """
+        Containing task (can be ``None``);
+
+        :type: :class:`Task`
+        """
         return relationship.many_to_one(cls, 'task')
 
     @declared_attr
     def operation(cls):
+        """
+        Containing operation (can be ``None``);
+
+        :type: :class:`Operation`
+        """
         return relationship.many_to_one(cls, 'operation')
 
     # endregion
+
+    # region foreign keys
+
+    @declared_attr
+    def task_fk(cls):
+        return relationship.foreign_key('task', nullable=True)
+
+    @declared_attr
+    def operation_fk(cls):
+        return relationship.foreign_key('operation', nullable=True)
+
+    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
index 76ac316..8b6028f 100644
--- a/aria/modeling/relationship.py
+++ b/aria/modeling/relationship.py
@@ -13,9 +13,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""
+ARIA modeling relationship module
+"""
+
 # pylint: disable=invalid-name, redefined-outer-name
+
 from sqlalchemy.orm import relationship, backref
 from sqlalchemy.orm.collections import attribute_mapped_collection
+from sqlalchemy.ext.associationproxy import association_proxy as original_association_proxy
 from sqlalchemy import (
     Column,
     ForeignKey,
@@ -43,9 +49,9 @@ def foreign_key(other_table, nullable=False):
 
     *This utility method should only be used during class creation.*
 
-    :param other_table: Other table name
+    :param other_table: other table name
     :type other_table: basestring
-    :param nullable: True to allow null values (meaning that there is no relationship)
+    :param nullable: ``True`` to allow null values (meaning that there is no relationship)
     :type nullable: bool
     """
 
@@ -63,9 +69,9 @@ def one_to_one_self(model_class, fk):
 
     *This utility method should only be used during class creation.*
 
-    :param model_class: The class in which this relationship will be declared
+    :param model_class: class in which this relationship will be declared
     :type model_class: type
-    :param fk: Foreign key name
+    :param fk: foreign key name
     :type fk: basestring
     """
 
@@ -105,17 +111,17 @@ def one_to_one(model_class,
 
     *This utility method should only be used during class creation.*
 
-    :param model_class: The class in which this relationship will be declared
+    :param model_class: class in which this relationship will be declared
     :type model_class: type
-    :param other_table: Other table name
+    :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)
+    :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)
+    :param other_fk: foreign key name at the other table (no need specify if there's no ambiguity)
     :type other_fk: basestring
-    :param back_populates: Override name of matching many-to-many property at other table; set to
-                       false to disable
-    :type back_populates: basestring|bool
+    :param back_populates: override name of matching many-to-many property at other table; set to
+     ``False`` to disable
+    :type back_populates: basestring or bool
     """
     backref_kwargs = None
     if back_populates is not NO_BACK_POP:
@@ -150,18 +156,23 @@ def one_to_many(model_class,
 
     *This utility method should only be used during class creation.*
 
-    :param model_class: The class in which this relationship will be declared
+    :param model_class: class in which this relationship will be declared
     :type model_class: type
-    :param child_table: Child table name
+    :param other_table: other table name
     :type other_table: basestring
-    :param other_fk: Foreign key name at the child table (no need specify if there's no ambiguity)
+    :param other_fk: foreign key name at the other table (no need specify if there's no ambiguity)
     :type other_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
+    :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 back_populates: Override name of matching many-to-one property at child table; set to
-                           false to disable
-    :type back_populates: basestring|bool
+    :param back_populates: override name of matching many-to-one property at other table; set to
+     ``False`` to disable
+    :type back_populates: basestring or bool
+    :param rel_kwargs: additional relationship kwargs to be used by SQLAlchemy
+    :type rel_kwargs: dict
+    :param self: used for relationships between a table and itself. if set, other_table will
+     become the same as the source table.
+    :type self: bool
     """
     relationship_kwargs = rel_kwargs or {}
     if self:
@@ -201,19 +212,19 @@ def many_to_one(model_class,
     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.
+    Python collection then use :func:`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
+    :param model_class: class in which this relationship will be declared
     :type model_class: type
-    :param parent_table: Parent table name
+    :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)
+    :param fk: foreign key name at our table (no need specify if there's no ambiguity)
     :type fk: basestring
-    :param back_populates: Override name of matching one-to-many property at parent table; set to
-                            false to disable
-    :type back_populates: basestring|bool
+    :param back_populates: override name of matching one-to-many property at parent table; set to
+     ``False`` to disable
+    :type back_populates: basestring or bool
     """
     if back_populates is None:
         back_populates = formatting.pluralize(model_class.__tablename__)
@@ -241,22 +252,25 @@ def many_to_many(model_class,
     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.
+    Python collection then use :func:`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
+    :param model_class: class in which this relationship will be declared
     :type model_class: type
-    :param other_table: Parent table name
+    :param other_table: parent table name
     :type other_table: basestring
-    :param prefix: Optional prefix for extra table name as well as for ``other_property``
+    :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
+    :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 other_property: override name of matching many-to-many property at other table; set to
+     ``False`` to disable
+    :type other_property: basestring or bool
+    :param self: used for relationships between a table and itself. if set, other_table will
+     become the same as the source table.
+    :type self: bool
     """
 
     this_table = model_class.__tablename__
@@ -301,6 +315,21 @@ def many_to_many(model_class,
     return _relationship(model_class, other_table, **kwargs)
 
 
+def association_proxy(*args, **kwargs):
+    if 'type' in kwargs:
+        type_ = kwargs.get('type')
+        del kwargs['type']
+    else:
+        type_ = ':obj:`basestring`'
+    proxy = original_association_proxy(*args, **kwargs)
+    proxy.__doc__ = """
+    Internal. For use in SQLAlchemy queries.
+
+    :type: {0}
+    """.format(type_)
+    return proxy
+
+
 def _relationship(model_class,
                   other_table_name,
                   back_populates=None,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index f632fef..061262a 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -14,10 +14,7 @@
 # limitations under the License.
 
 """
-classes:
-    * ServiceUpdate - service update implementation model.
-    * ServiceUpdateStep - service update step implementation model.
-    * ServiceModification - service modification implementation model.
+ARIA modeling service changes module
 """
 
 # pylint: disable=no-self-argument, no-member, abstract-method
@@ -30,7 +27,6 @@ from sqlalchemy import (
     DateTime,
     Enum,
 )
-from sqlalchemy.ext.associationproxy import association_proxy
 from sqlalchemy.ext.declarative import declared_attr
 
 from .types import (List, Dict)
@@ -44,8 +40,8 @@ class ServiceUpdateBase(ModelMixin):
     """
     __tablename__ = 'service_update'
 
-    __private_fields__ = ['service_fk',
-                          'execution_fk']
+    __private_fields__ = ('service_fk',
+                          'execution_fk')
 
     created_at = Column(DateTime, nullable=False, index=True)
     service_plan = Column(Dict, nullable=False)
@@ -55,29 +51,15 @@ class ServiceUpdateBase(ModelMixin):
     modified_entity_ids = Column(Dict)
     state = Column(Text)
 
-    # region foreign keys
-
-    @declared_attr
-    def execution_fk(cls):
-        return relationship.foreign_key('execution', nullable=True)
-
-    @declared_attr
-    def service_fk(cls):
-        return relationship.foreign_key('service')
-
-    # endregion
-
     # region association proxies
 
     @declared_attr
     def execution_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('execution', cls.name_column_name())
+        return relationship.association_proxy('execution', cls.name_column_name())
 
     @declared_attr
     def service_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', cls.name_column_name())
+        return relationship.association_proxy('service', cls.name_column_name())
 
     # endregion
 
@@ -105,6 +87,18 @@ class ServiceUpdateBase(ModelMixin):
 
     # endregion
 
+    # region foreign keys
+
+    @declared_attr
+    def execution_fk(cls):
+        return relationship.foreign_key('execution', nullable=True)
+
+    @declared_attr
+    def service_fk(cls):
+        return relationship.foreign_key('service')
+
+    # endregion
+
     def to_dict(self, suppress_error=False, **kwargs):
         dep_update_dict = super(ServiceUpdateBase, self).to_dict(suppress_error)     #pylint: disable=no-member
         # Taking care of the fact the DeploymentSteps are _BaseModels
@@ -119,7 +113,7 @@ class ServiceUpdateStepBase(ModelMixin):
 
     __tablename__ = 'service_update_step'
 
-    __private_fields__ = ['service_update_fk']
+    __private_fields__ = ('service_update_fk',)
 
     _action_types = namedtuple('ACTION_TYPES', 'ADD, REMOVE, MODIFY')
     ACTION_TYPES = _action_types(ADD='add', REMOVE='remove', MODIFY='modify')
@@ -143,20 +137,11 @@ class ServiceUpdateStepBase(ModelMixin):
     entity_id = Column(Text, nullable=False)
     entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), nullable=False)
 
-    # region foreign keys
-
-    @declared_attr
-    def service_update_fk(cls):
-        return relationship.foreign_key('service_update')
-
-    # endregion
-
     # region association proxies
 
     @declared_attr
     def service_update_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service_update', cls.name_column_name())
+        return relationship.association_proxy('service_update', cls.name_column_name())
 
     # endregion
 
@@ -176,6 +161,14 @@ class ServiceUpdateStepBase(ModelMixin):
 
     # endregion
 
+    # region foreign keys
+
+    @declared_attr
+    def service_update_fk(cls):
+        return relationship.foreign_key('service_update')
+
+    # endregion
+
     def __hash__(self):
         return hash((getattr(self, self.id_column_name()), self.entity_id))
 
@@ -211,7 +204,7 @@ class ServiceModificationBase(ModelMixin):
 
     __tablename__ = 'service_modification'
 
-    __private_fields__ = ['service_fk']
+    __private_fields__ = ('service_fk',)
 
     STARTED = 'started'
     FINISHED = 'finished'
@@ -227,20 +220,11 @@ class ServiceModificationBase(ModelMixin):
     nodes = Column(Dict)
     status = Column(Enum(*STATES, name='service_modification_status'))
 
-    # region foreign keys
-
-    @declared_attr
-    def service_fk(cls):
-        return relationship.foreign_key('service')
-
-    # endregion
-
     # region association proxies
 
     @declared_attr
     def service_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', cls.name_column_name())
+        return relationship.association_proxy('service', cls.name_column_name())
 
     # endregion
 
@@ -253,8 +237,17 @@ class ServiceModificationBase(ModelMixin):
     # endregion
 
     # region many_to_one relationships
+
     @declared_attr
     def service(cls):
         return relationship.many_to_one(cls, 'service', back_populates='modifications')
 
     # endregion
+
+    # region foreign keys
+
+    @declared_attr
+    def service_fk(cls):
+        return relationship.foreign_key('service')
+
+    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2ed2e1c2/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 0bb861f..b533a88 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -13,6 +13,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""
+ARIA modeling service common module
+"""
+
 # pylint: disable=no-self-argument, no-member, abstract-method
 
 from sqlalchemy import (
@@ -32,9 +36,34 @@ from . import relationship
 
 
 class OutputBase(ParameterMixin):
+    """
+    Output parameter or declaration for an output parameter.
+    """
 
     __tablename__ = 'output'
 
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        """
+        Containing service template (can be ``None``).
+
+        :type: :class:`ServiceTemplate`
+        """
+        return relationship.many_to_one(cls, 'service_template')
+
+    @declared_attr
+    def service(cls):
+        """
+        Containing service (can be ``None``).
+
+        :type: :class:`ServiceTemplate`
+        """
+        return relationship.many_to_one(cls, 'service')
+
+    # endregion
+
     # region foreign keys
 
     @declared_attr
@@ -47,22 +76,80 @@ class OutputBase(ParameterMixin):
 
     # endregion
 
+
+class InputBase(ParameterMixin):
+    """
+    Input parameter or declaration for an input parameter.
+    """
+
+    __tablename__ = 'input'
+
     # region many_to_one relationships
 
     @declared_attr
     def service_template(cls):
+        """
+        Containing service template (can be ``None``).
+
+        :type: :class:`ServiceTemplate`
+        """
         return relationship.many_to_one(cls, 'service_template')
 
     @declared_attr
     def service(cls):
+        """
+        Containing service (can be ``None``).
+
+        :type: :class:`Service`
+        """
         return relationship.many_to_one(cls, 'service')
 
-    # endregion
+    @declared_attr
+    def interface(cls):
+        """
+        Containing interface (can be ``None``).
 
+        :type: :class:`Interface`
+        """
+        return relationship.many_to_one(cls, 'interface')
 
-class InputBase(ParameterMixin):
+    @declared_attr
+    def operation(cls):
+        """
+        Containing operation (can be ``None``).
 
-    __tablename__ = 'input'
+        :type: :class:`Operation`
+        """
+        return relationship.many_to_one(cls, 'operation')
+
+    @declared_attr
+    def interface_template(cls):
+        """
+        Containing interface template (can be ``None``).
+
+        :type: :class:`InterfaceTemplate`
+        """
+        return relationship.many_to_one(cls, 'interface_template')
+
+    @declared_attr
+    def operation_template(cls):
+        """
+        Containing operation template (can be ``None``).
+
+        :type: :class:`OperationTemplate`
+        """
+        return relationship.many_to_one(cls, 'operation_template')
+
+    @declared_attr
+    def execution(cls):
+        """
+        Containing execution (can be ``None``).
+
+        :type: :class:`Execution`
+        """
+        return relationship.many_to_one(cls, 'execution')
+
+    # endregion
 
     # region foreign keys
 
@@ -100,71 +187,167 @@ class InputBase(ParameterMixin):
 
     # endregion
 
+
+class ConfigurationBase(ParameterMixin):
+    """
+    Configuration parameter.
+    """
+
+    __tablename__ = 'configuration'
+
     # region many_to_one relationships
 
     @declared_attr
-    def service_template(cls):
-        return relationship.many_to_one(cls, 'service_template')
+    def operation_template(cls):
+        """
+        Containing operation template (can be ``None``).
+
+        :type: :class:`OperationTemplate`
+        """
+        return relationship.many_to_one(cls, 'operation_template')
 
     @declared_attr
-    def service(cls):
-        return relationship.many_to_one(cls, 'service')
+    def operation(cls):
+        """
+        Containing operation (can be ``None``).
+
+        :type: :class:`Operation`
+        """
+        return relationship.many_to_one(cls, 'operation')
+
+    # endregion
+
+    # region foreign keys
 
     @declared_attr
-    def interface(cls):
-        return relationship.many_to_one(cls, 'interface')
+    def operation_template_fk(cls):
+        return relationship.foreign_key('operation_template', nullable=True)
 
     @declared_attr
-    def operation(cls):
-        return relationship.many_to_one(cls, 'operation')
+    def operation_fk(cls):
+        return relationship.foreign_key('operation', nullable=True)
+
+    # endregion
+
+
+class PropertyBase(ParameterMixin):
+    """
+    Property parameter or declaration for a property parameter.
+    """
+
+    __tablename__ = 'property'
+
+    # region many_to_one relationships
 
     @declared_attr
-    def interface_template(cls):
-        return relationship.many_to_one(cls, 'interface_template')
+    def node_template(cls):
+        """
+        Containing node template (can be ``None``).
+
+        :type: :class:`NodeTemplate`
+        """
+        return relationship.many_to_one(cls, 'node_template')
 
     @declared_attr
-    def operation_template(cls):
-        return relationship.many_to_one(cls, 'operation_template')
+    def group_template(cls):
+        """
+        Containing group template (can be ``None``).
+
+        :type: :class:`GroupTemplate`
+        """
+        return relationship.many_to_one(cls, 'group_template')
 
     @declared_attr
-    def execution(cls):
-        return relationship.many_to_one(cls, 'execution')
+    def policy_template(cls):
+        """
+        Containing policy template (can be ``None``).
 
-    # endregion
+        :type: :class:`PolicyTemplate`
+        """
+        return relationship.many_to_one(cls, 'policy_template')
 
+    @declared_attr
+    def relationship_template(cls):
+        """
+        Containing relationship template (can be ``None``).
 
-class ConfigurationBase(ParameterMixin):
+        :type: :class:`RelationshipTemplate`
+        """
+        return relationship.many_to_one(cls, 'relationship_template')
 
-    __tablename__ = 'configuration'
+    @declared_attr
+    def capability_template(cls):
+        """
+        Containing capability template (can be ``None``).
 
-    # region foreign keys
+        :type: :class:`CapabilityTemplate`
+        """
+        return relationship.many_to_one(cls, 'capability_template')
 
     @declared_attr
-    def operation_template_fk(cls):
-        return relationship.foreign_key('operation_template', nullable=True)
+    def artifact_template(cls):
+        """
+        Containing artifact template (can be ``None``).
+
+        :type: :class:`ArtifactTemplate`
+        """
+        return relationship.many_to_one(cls, 'artifact_template')
 
     @declared_attr
-    def operation_fk(cls):
-        return relationship.foreign_key('operation', nullable=True)
+    def node(cls):
+        """
+        Containing node (can be ``None``).
 
-    # endregion
+        :type: :class:`Node`
+        """
+        return relationship.many_to_one(cls, 'node')
 
-    # region many_to_one relationships
+    @declared_attr
+    def group(cls):
+        """
+        Containing group (can be ``None``).
+
+        :type: :class:`Group`
+        """
+        return relationship.many_to_one(cls, 'group')
 
     @declared_attr
-    def operation_template(cls):
-        return relationship.many_to_one(cls, 'operation_template')
+    def policy(cls):
+        """
+        Containing policy (can be ``None``).
+
+        :type: :class:`Policy`
+        """
+        return relationship.many_to_one(cls, 'policy')
 
     @declared_attr
-    def operation(cls):
-        return relationship.many_to_one(cls, 'operation')
+    def relationship(cls):
+        """
+        Containing relationship (can be ``None``).
 
-    # endregion
+        :type: :class:`Relationship`
+        """
+        return relationship.many_to_one(cls, 'relationship')
 
+    @declared_attr
+    def capability(cls):
+        """
+        Containing capability (can be ``None``).
 
-class PropertyBase(ParameterMixin):
+        :type: :class:`Capability`
+        """
+        return relationship.many_to_one(cls, 'capability')
 
-    __tablename__ = 'property'
+    @declared_attr
+    def artifact(cls):
+        """
+        Containing artifact (can be ``None``).
+
+        :type: :class:`Artifact`
+        """
+        return relationship.many_to_one(cls, 'artifact')
+
+    # endregion
 
     # region foreign keys
 
@@ -215,65 +398,39 @@ class PropertyBase(ParameterMixin):
     @declared_attr
     def artifact_fk(cls):
         return relationship.foreign_key('artifact', nullable=True)
+
     # endregion
 
-    # region many_to_one relationships
 
-    @declared_attr
-    def node_template(cls):
-        return relationship.many_to_one(cls, 'node_template')
-
-    @declared_attr
-    def group_template(cls):
-        return relationship.many_to_one(cls, 'group_template')
+class AttributeBase(ParameterMixin):
+    """
+    Attribute parameter or declaration for an attribute parameter.
+    """
 
-    @declared_attr
-    def policy_template(cls):
-        return relationship.many_to_one(cls, 'policy_template')
+    __tablename__ = 'attribute'
 
-    @declared_attr
-    def relationship_template(cls):
-        return relationship.many_to_one(cls, 'relationship_template')
+    # region many_to_one relationships
 
     @declared_attr
-    def capability_template(cls):
-        return relationship.many_to_one(cls, 'capability_template')
+    def node_template(cls):
+        """
+        Containing node template (can be ``None``).
 
-    @declared_attr
-    def artifact_template(cls):
-        return relationship.many_to_one(cls, 'artifact_template')
+        :type: :class:`NodeTemplate`
+        """
+        return relationship.many_to_one(cls, 'node_template')
 
     @declared_attr
     def node(cls):
-        return relationship.many_to_one(cls, 'node')
-
-    @declared_attr
-    def group(cls):
-        return relationship.many_to_one(cls, 'group')
-
-    @declared_attr
-    def policy(cls):
-        return relationship.many_to_one(cls, 'policy')
-
-    @declared_attr
-    def relationship(cls):
-        return relationship.many_to_one(cls, 'relationship')
-
-    @declared_attr
-    def capability(cls):
-        return relationship.many_to_one(cls, 'capability')
+        """
+        Containing node (can be ``None``).
 
-    @declared_attr
-    def artifact(cls):
-        return relationship.many_to_one(cls, 'artifact')
+        :type: :class:`Node`
+        """
+        return relationship.many_to_one(cls, 'node')
 
     # endregion
 
-
-class AttributeBase(ParameterMixin):
-
-    __tablename__ = 'attribute'
-
     # region foreign keys
 
     @declared_attr
@@ -288,40 +445,52 @@ class AttributeBase(ParameterMixin):
 
     # endregion
 
-    # region many_to_one relationships
-
-    @declared_attr
-    def node_template(cls):
-        return relationship.many_to_one(cls, 'node_template')
-
-    @declared_attr
-    def node(cls):
-        return relationship.many_to_one(cls, 'node')
-
-    # endregion
-
 
 class TypeBase(InstanceModelMixin):
     """
-    Represents a type and its children.
+    Type and its children. Can serve as the root for a type hierarchy.
     """
 
     __tablename__ = 'type'
 
-    __private_fields__ = ['parent_type_fk']
+    __private_fields__ = ('parent_type_fk',)
 
     variant = Column(Text, nullable=False)
-    description = Column(Text)
+
+    description = Column(Text, doc="""
+    Human-readable description.
+
+    :type: :obj:`basestring`
+    """)
+
     _role = Column(Text, name='role')
 
+    # region one_to_one relationships
+
     @declared_attr
     def parent(cls):
+        """
+        Parent type (will be ``None`` for the root of a type hierarchy).
+
+        :type: :class:`Type`
+        """
         return relationship.one_to_one_self(cls, 'parent_type_fk')
 
+    # endregion
+
+    # region one_to_many relationships
+
     @declared_attr
     def children(cls):
+        """
+        Children.
+
+        :type: [:class:`Type`]
+        """
         return relationship.one_to_many(cls, other_fk='parent_type_fk', self=True)
 
+    # endregion
+
     # region foreign keys
 
     @declared_attr
@@ -402,8 +571,9 @@ class TypeBase(InstanceModelMixin):
     @property
     def hierarchy(self):
         """
-        Return the type hierarchy.
-        :return:
+        Type hierarchy as a list beginning with this type and ending in the root.
+
+        :type: [:class:`Type`]
         """
         return [self] + (self.parent.hierarchy if self.parent else [])
 
@@ -414,9 +584,9 @@ class MetadataBase(TemplateModelMixin):
 
     This model is used by both service template and service instance elements.
 
-    :ivar name: Name
+    :ivar name: name
     :vartype name: basestring
-    :ivar value: Value
+    :ivar value: value
     :vartype value: basestring
     """