ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@apache.org
Subject [03/11] incubator-ariatosca git commit: ARIA-18 Migrate DSL parser and TOSCA extension code
Date Tue, 15 Nov 2016 16:22:27 GMT
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
new file mode 100644
index 0000000..9b0edb8
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
@@ -0,0 +1,497 @@
+# 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.
+
+import re
+from collections import OrderedDict
+
+from aria.parser import dsl_specification
+from aria.parser.presentation import (get_locator, validate_primitive)
+from aria.parser.utils import (import_fullname, full_type_name, safe_repr)
+from aria.parser.validation import Issue
+
+from ..functions import get_function
+from ..presentation.types import get_type_by_full_or_shorthand_name
+
+#
+# DataType
+#
+
+def get_inherited_constraints(context, presentation):
+    """
+    If we don't have constraints, will return our parent's constraints (if we have one),
+    recursively.
+
+    Implication: if we define even one constraint, the parent's constraints will not be inherited.
+    """
+
+    constraints = presentation.constraints
+
+    if constraints is None:
+        # If we don't have any, use our parent's
+        parent = presentation._get_parent(context)
+        parent_constraints = get_inherited_constraints(context, parent) \
+            if parent is not None else None
+        if parent_constraints is not None:
+            constraints = parent_constraints
+
+    return constraints
+
+def coerce_data_type_value(context, presentation, data_type, entry_schema, constraints, value, # pylint: disable=unused-argument
+                           aspect):
+    """
+    Handles the :code:`_coerce_data()` hook for complex data types.
+
+    There are two kinds of handling:
+
+    1. If we have a primitive type as our great ancestor, then we do primitive type coersion, and
+       just check for constraints.
+
+    2. Otherwise, for normal complex data types we return the assigned property values while making
+       sure they are defined in our type. The property definition's default value, if available,
+       will be used if we did not assign it. We also make sure that required definitions indeed end
+       up with a value.
+    """
+
+    primitive_type = data_type._get_primitive_ancestor(context)
+    if primitive_type is not None:
+        # Must be coercible to primitive ancestor
+        value = coerce_to_primitive(context, presentation, primitive_type, constraints, value,
+                                    aspect)
+    else:
+        definitions = data_type._get_properties(context)
+        if isinstance(value, dict):
+            temp = OrderedDict()
+
+            # Fill in our values, but make sure they are defined
+            for name, v in value.iteritems():
+                if name in definitions:
+                    definition = definitions[name]
+                    definition_type = definition._get_type(context)
+                    definition_entry_schema = definition.entry_schema
+                    definition_constraints = definition._get_constraints(context)
+                    temp[name] = coerce_value(context, presentation, definition_type,
+                                              definition_entry_schema, definition_constraints, v,
+                                              aspect)
+                else:
+                    context.validation.report(
+                        'assignment to undefined property "%s" in type "%s" in "%s"'
+                        % (name, data_type._fullname, presentation._fullname),
+                        locator=get_locator(v, value, presentation), level=Issue.BETWEEN_TYPES)
+
+            # Fill in defaults from the definitions, and check if required definitions have not been
+            # assigned
+            for name, definition in definitions.iteritems():
+                if (temp.get(name) is None) and hasattr(definition, 'default') \
+                    and (definition.default is not None):
+                    definition_type = definition._get_type(context)
+                    definition_entry_schema = definition.entry_schema
+                    definition_constraints = definition._get_constraints(context)
+                    temp[name] = coerce_value(context, presentation, definition_type,
+                                              definition_entry_schema, definition_constraints,
+                                              definition.default, 'default')
+
+                if getattr(definition, 'required', False) and (temp.get(name) is None):
+                    context.validation.report(
+                        'required property "%s" in type "%s" is not assigned a value in "%s"'
+                        % (name, data_type._fullname, presentation._fullname),
+                        locator=presentation._get_child_locator('definitions'),
+                        level=Issue.BETWEEN_TYPES)
+
+            value = temp
+        elif value is not None:
+            context.validation.report('value of type "%s" is not a dict in "%s"'
+                                      % (data_type._fullname, presentation._fullname),
+                                      locator=get_locator(value, presentation),
+                                      level=Issue.BETWEEN_TYPES)
+            value = None
+
+    return value
+
+def validate_data_type_name(context, presentation):
+    """
+    Makes sure the complex data type's name is not that of a built-in type.
+    """
+
+    name = presentation._name
+    if get_primitive_data_type(name) is not None:
+        context.validation.report('data type name is that of a built-in type: %s'
+                                  % safe_repr(name),
+                                  locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
+#
+# PropertyDefinition, AttributeDefinition, EntrySchema, DataType
+#
+
+def get_data_type(context, presentation, field_name, allow_none=False):
+    """
+    Returns the type, whether it's a complex data type (a DataType instance) or a primitive (a
+    Python primitive type class).
+
+    If the type is not specified, defaults to :class:`str`, per note in section 3.2.1.1 of the
+    `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca
+    /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html
+    #_Toc379455072>`__
+    """
+
+    type_name = getattr(presentation, field_name)
+
+    if type_name is None:
+        if allow_none:
+            return None
+        else:
+            return str
+
+    # Make sure not derived from self
+    if type_name == presentation._name:
+        return None
+
+    # Avoid circular definitions
+    container_data_type = get_container_data_type(presentation)
+    if (container_data_type is not None) and (container_data_type._name == type_name):
+        return None
+
+    # Try complex data type
+    data_type = get_type_by_full_or_shorthand_name(context, type_name, 'data_types')
+    if data_type is not None:
+        return data_type
+
+    # Try primitive data type
+    return get_primitive_data_type(type_name)
+
+#
+# PropertyDefinition, EntrySchema
+#
+
+def get_property_constraints(context, presentation):
+    """
+    If we don't have constraints, will return our type's constraints (if we have one), recursively.
+
+    Implication: if we define even one constraint, the type's constraints will not be inherited.
+    """
+
+    constraints = presentation.constraints
+
+    if constraints is None:
+        # If we don't have any, use our type's
+        the_type = presentation._get_type(context)
+        type_constraints = the_type._get_constraints(context) \
+            if hasattr(the_type, '_get_constraints') else None
+        if type_constraints is not None:
+            constraints = type_constraints
+
+    return constraints
+
+#
+# ConstraintClause
+#
+
+def apply_constraint_to_value(context, presentation, constraint_clause, value): # pylint: disable=too-many-statements,too-many-return-statements,too-many-branches
+    """
+    Returns false if the value does not conform to the constraint.
+    """
+
+    constraint_key = constraint_clause._raw.keys()[0]
+    the_type = constraint_clause._get_type(context)
+    # PropertyAssignment does not have this:
+    entry_schema = getattr(presentation, 'entry_schema', None)
+
+    def coerce_constraint(constraint):
+        return coerce_value(context, presentation, the_type, entry_schema, None, constraint,
+                            constraint_key)
+
+    def report(message, constraint):
+        context.validation.report('value %s %s per constraint in "%s": %s'
+                                  % (message, safe_repr(constraint),
+                                     presentation._name or presentation._container._name,
+                                     safe_repr(value)),
+                                  locator=presentation._locator, level=Issue.BETWEEN_FIELDS)
+
+    if constraint_key == 'equal':
+        constraint = coerce_constraint(constraint_clause.equal)
+        if value != constraint:
+            report('is not equal to', constraint)
+            return False
+
+    elif constraint_key == 'greater_than':
+        constraint = coerce_constraint(constraint_clause.greater_than)
+        if value <= constraint:
+            report('is not greater than', constraint)
+            return False
+
+    elif constraint_key == 'greater_or_equal':
+        constraint = coerce_constraint(constraint_clause.greater_or_equal)
+        if value < constraint:
+            report('is not greater than or equal to', constraint)
+            return False
+
+    elif constraint_key == 'less_than':
+        constraint = coerce_constraint(constraint_clause.less_than)
+        if value >= constraint:
+            report('is not less than', constraint)
+            return False
+
+    elif constraint_key == 'less_or_equal':
+        constraint = coerce_constraint(constraint_clause.less_or_equal)
+        if value > constraint:
+            report('is not less than or equal to', constraint)
+            return False
+
+    elif constraint_key == 'in_range':
+        lower, upper = constraint_clause.in_range
+        lower, upper = coerce_constraint(lower), coerce_constraint(upper)
+        if value < lower:
+            report('is not greater than or equal to lower bound', lower)
+            return False
+        if (upper != 'UNBOUNDED') and (value > upper):
+            report('is not lesser than or equal to upper bound', upper)
+            return False
+
+    elif constraint_key == 'valid_values':
+        constraint = tuple(coerce_constraint(v) for v in constraint_clause.valid_values)
+        if value not in constraint:
+            report('is not one of', constraint)
+            return False
+
+    elif constraint_key == 'length':
+        constraint = constraint_clause.length
+        try:
+            if len(value) != constraint:
+                report('is not of length', constraint)
+                return False
+        except TypeError:
+            pass # should be validated elsewhere
+
+    elif constraint_key == 'min_length':
+        constraint = constraint_clause.min_length
+        try:
+            if len(value) < constraint:
+                report('has a length lesser than', constraint)
+                return False
+        except TypeError:
+            pass # should be validated elsewhere
+
+    elif constraint_key == 'max_length':
+        constraint = constraint_clause.max_length
+        try:
+            if len(value) > constraint:
+                report('has a length greater than', constraint)
+                return False
+        except TypeError:
+            pass # should be validated elsewhere
+
+    elif constraint_key == 'pattern':
+        constraint = constraint_clause.pattern
+        try:
+            # Note: the TOSCA 1.0 spec does not specify the regular expression grammar, so we will
+            # just use Python's
+            if re.match(constraint, str(value)) is None:
+                report('does not match regular expression', constraint)
+                return False
+        except re.error:
+            pass # should be validated elsewhere
+
+    return True
+
+#
+# Repository
+#
+
+def get_data_type_value(context, presentation, field_name, type_name):
+    the_type = get_type_by_full_or_shorthand_name(context, type_name, 'data_types')
+    if the_type is not None:
+        value = getattr(presentation, field_name)
+        if value is not None:
+            return coerce_data_type_value(context, presentation, the_type, None, None, value, None)
+    else:
+        context.validation.report('field "%s" in "%s" refers to unknown data type "%s"'
+                                  % (field_name, presentation._fullname, type_name),
+                                  locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+    return None
+
+#
+# Utils
+#
+
+PRIMITIVE_DATA_TYPES = {
+    # YAML 1.2:
+    'tag:yaml.org,2002:str': str,
+    'tag:yaml.org,2002:integer': int,
+    'tag:yaml.org,2002:float': float,
+    'tag:yaml.org,2002:bool': bool,
+    'tag:yaml.org,2002:null': None.__class__,
+
+    # TOSCA aliases:
+    'string': str,
+    'integer': int,
+    'float': float,
+    'boolean': bool,
+    'null': None.__class__}
+
+@dsl_specification('3.2.1', 'tosca-simple-1.0')
+def get_primitive_data_type(type_name):
+    """
+    Many of the types we use in this profile are built-in types from the YAML 1.2 specification
+    (i.e., those identified by the "tag:yaml.org,2002" version tag) [YAML-1.2].
+
+    See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca
+    /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html
+    #_Toc373867862>`__
+    """
+
+    return PRIMITIVE_DATA_TYPES.get(type_name)
+
+def get_data_type_name(the_type):
+    """
+    Returns the name of the type, whether it's a DataType, a primitive type, or another class.
+    """
+
+    return the_type._name if hasattr(the_type, '_name') else full_type_name(the_type)
+
+def coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect=None): # pylint: disable=too-many-return-statements
+    """
+    Returns the value after it's coerced to its type, reporting validation errors if it cannot be
+    coerced.
+
+    Supports both complex data types and primitives.
+
+    Data types can use the :code:`coerce_value` extension to hook their own specialized function.
+    If the extension is present, we will delegate to that hook.
+    """
+
+    is_function, func = get_function(context, presentation, value)
+    if is_function:
+        return func
+
+    if the_type is None:
+        return value
+
+    if the_type == None.__class__:
+        if value is not None:
+            context.validation.report('field "%s" is of type "null" but has a non-null value: %s'
+                                      % (presentation._name, safe_repr(value)),
+                                      locator=presentation._locator, level=Issue.BETWEEN_FIELDS)
+            return None
+
+    # Delegate to 'coerce_value' extension
+    if hasattr(the_type, '_get_extension'):
+        coerce_value_fn_name = the_type._get_extension('coerce_value')
+        if coerce_value_fn_name is not None:
+            if value is None:
+                return None
+            coerce_value_fn = import_fullname(coerce_value_fn_name)
+            return coerce_value_fn(context, presentation, the_type, entry_schema, constraints,
+                                   value, aspect)
+
+    if hasattr(the_type, '_coerce_value'):
+        # Delegate to '_coerce_value' (likely a DataType instance)
+        return the_type._coerce_value(context, presentation, entry_schema, constraints, value,
+                                      aspect)
+
+    # Coerce to primitive type
+    return coerce_to_primitive(context, presentation, the_type, constraints, value, aspect)
+
+def coerce_to_primitive(context, presentation, primitive_type, constraints, value, aspect=None):
+    """
+    Returns the value after it's coerced to a primitive type, translating exceptions to validation
+    errors if it cannot be coerced.
+    """
+
+    if value is None:
+        return None
+
+    try:
+        # Coerce
+        value = validate_primitive(value, primitive_type,
+                                   context.validation.allow_primitive_coersion)
+
+        # Check constraints
+        apply_constraints_to_value(context, presentation, constraints, value)
+    except ValueError as e:
+        report_issue_for_bad_format(context, presentation, primitive_type, value, aspect, e)
+        value = None
+    except TypeError as e:
+        report_issue_for_bad_format(context, presentation, primitive_type, value, aspect, e)
+        value = None
+
+    return value
+
+def coerce_to_data_type_class(context, presentation, cls, entry_schema, constraints, value,
+                              aspect=None):
+    """
+    Returns the value after it's coerced to a data type class, reporting validation errors if it
+    cannot be coerced. Constraints will be applied after coersion.
+
+    Will either call a :code:`_create` static function in the class, or instantiate it using a
+    constructor if :code:`_create` is not available.
+
+    This will usually be called by a :code:`coerce_value` extension hook in a :class:`DataType`.
+    """
+
+    try:
+        if hasattr(cls, '_create'):
+            # Instantiate using creator function
+            value = cls._create(context, presentation, entry_schema, constraints, value, aspect)
+        else:
+            # Normal instantiation
+            value = cls(entry_schema, constraints, value, aspect)
+    except ValueError as e:
+        report_issue_for_bad_format(context, presentation, cls, value, aspect, e)
+        value = None
+
+    # Check constraints
+    value = apply_constraints_to_value(context, presentation, constraints, value)
+
+    return value
+
+def apply_constraints_to_value(context, presentation, constraints, value):
+    """
+    Applies all constraints to the value. If the value conforms, returns the value. If it does not
+    conform, returns None.
+    """
+
+    if (value is not None) and (constraints is not None):
+        valid = True
+        for constraint in constraints:
+            if not constraint._apply_to_value(context, presentation, value):
+                valid = False
+        if not valid:
+            value = None
+    return value
+
+def get_container_data_type(presentation):
+    if presentation is None:
+        return None
+    if type(presentation).__name__ == 'DataType':
+        return presentation
+    return get_container_data_type(presentation._container)
+
+def report_issue_for_bad_format(context, presentation, the_type, value, aspect, e):
+    if aspect == 'default':
+        aspect = '"default" value'
+    elif aspect is not None:
+        aspect = '"%s" aspect' % aspect
+
+    if aspect is not None:
+        context.validation.report('%s for field "%s" is not a valid "%s": %s'
+                                  % (aspect, presentation._name or presentation._container._name,
+                                     get_data_type_name(the_type), safe_repr(value)),
+                                  locator=presentation._locator, level=Issue.BETWEEN_FIELDS,
+                                  exception=e)
+    else:
+        context.validation.report('field "%s" is not a valid "%s": %s'
+                                  % (presentation._name or presentation._container._name,
+                                     get_data_type_name(the_type), safe_repr(value)),
+                                  locator=presentation._locator, level=Issue.BETWEEN_FIELDS,
+                                  exception=e)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
new file mode 100644
index 0000000..1d734cf
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
@@ -0,0 +1,504 @@
+# 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.
+
+from collections import OrderedDict
+
+from aria.parser.presentation import get_locator
+from aria.parser.utils import (merge, deepcopy_with_locators)
+from aria.parser.validation import Issue
+
+from .properties import (coerce_property_value, convert_property_definitions_to_values)
+
+#
+# InterfaceType
+#
+
+def get_inherited_operations(context, presentation):
+    """
+    Returns our operation definitions added on top of those of our parent, if we have one
+    (recursively).
+
+    Allows overriding all aspects of parent operations except input data types.
+    """
+
+    # Get operations from parent
+    parent = presentation._get_parent(context)
+    operations = get_inherited_operations(context, parent) if parent is not None else OrderedDict()
+
+    # Add/merge our operations
+    our_operations = presentation.operations # OperationDefinition
+    merge_operation_definitions(context, operations, our_operations, presentation._name,
+                                presentation, 'type')
+
+    for operation in operations.itervalues():
+        operation._reset_method_cache()
+
+    return operations
+
+#
+# InterfaceDefinition
+#
+
+def get_and_override_input_definitions_from_type(context, presentation):
+    """
+    Returns our input definitions added on top of those of the interface type, if specified.
+
+    Allows overriding all aspects of parent interface type inputs except data types.
+    """
+
+    inputs = OrderedDict()
+
+    # Get inputs from type
+    the_type = presentation._get_type(context) # IntefaceType
+    type_inputs = the_type._get_inputs(context) if the_type is not None else None
+    if type_inputs:
+        for input_name, type_input in type_inputs.iteritems():
+            inputs[input_name] = type_input._clone(presentation)
+
+    # Add/merge our inputs
+    our_inputs = presentation.inputs # PropertyDefinition
+    if our_inputs:
+        merge_input_definitions(context, inputs, our_inputs, presentation._name, None, presentation,
+                                'definition')
+
+    return inputs
+
+def get_and_override_operation_definitions_from_type(context, presentation):
+    """
+    Returns our operation definitions added on top of those of the interface type, if specified.
+
+    Allows overriding all aspects of parent interface type inputs except data types.
+    """
+
+    operations = OrderedDict()
+
+    # Get operations from type
+    the_type = presentation._get_type(context) # InterfaceType
+    type_operations = the_type._get_operations(context) if the_type is not None else None
+    if type_operations:
+        for operations_name, type_operation in type_operations.iteritems():
+            operations[operations_name] = type_operation._clone(presentation)
+
+    # Add/merge our operations
+    our_operations = presentation.operations # OperationDefinition
+    merge_operation_definitions(context, operations, our_operations, presentation._name,
+                                presentation, 'definition')
+
+    return operations
+
+#
+# NodeType, RelationshipType, GroupType
+#
+
+def get_inherited_interface_definitions(context, presentation, type_name, for_presentation=None):
+    """
+    Returns our interface definitions added on top of those of our parent, if we have one
+    (recursively).
+
+    Allows overriding all aspects of parent interfaces except interface and operation input data
+    types.
+    """
+
+    # Get interfaces from parent
+    parent = presentation._get_parent(context)
+    interfaces = get_inherited_interface_definitions(context, parent, type_name, presentation) \
+        if parent is not None else OrderedDict()
+
+    # Add/merge interfaces from their types
+    merge_interface_definitions_from_their_types(context, interfaces, presentation)
+
+    # Add/merge our interfaces
+    our_interfaces = presentation.interfaces
+    merge_interface_definitions(context, interfaces, our_interfaces, presentation,
+                                for_presentation=for_presentation)
+
+    return interfaces
+
+#
+# NodeTemplate, RelationshipTemplate, GroupTemplate
+#
+
+def get_template_interfaces(context, presentation, type_name):
+    """
+    Returns the assigned interface_template values while making sure they are defined in the type.
+    This includes the interfaces themselves, their operations, and inputs for interfaces and
+    operations.
+
+    Interface and operation inputs' default values, if available, will be used if we did not assign
+    them.
+
+    Makes sure that required inputs indeed end up with a value.
+
+    This code is especially complex due to the many levels of nesting involved.
+    """
+
+    template_interfaces = OrderedDict()
+
+    the_type = presentation._get_type(context) # NodeType, RelationshipType, GroupType
+    # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate):
+    interface_definitions = the_type._get_interfaces(context) if the_type is not None else None
+
+    # Copy over interfaces from the type (will initialize inputs with default values)
+    if interface_definitions is not None:
+        for interface_name, interface_definition in interface_definitions.iteritems():
+            # Note that in the case of a RelationshipTemplate, we will already have the values as
+            # InterfaceAssignment. It will not be converted, just cloned.
+            template_interfaces[interface_name] = \
+                convert_interface_definition_from_type_to_template(context, interface_definition,
+                                                                   presentation)
+
+    # Fill in our interfaces
+    our_interface_assignments = presentation.interfaces
+    if our_interface_assignments:
+        # InterfaceAssignment:
+        for interface_name, our_interface_assignment in our_interface_assignments.iteritems():
+            if interface_name in template_interfaces:
+                interface_assignment = template_interfaces[interface_name] # InterfaceAssignment
+                # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate):
+                interface_definition = interface_definitions[interface_name]
+                merge_interface(context, presentation, interface_assignment,
+                                our_interface_assignment, interface_definition, interface_name)
+            else:
+                context.validation.report(
+                    'interface definition "%s" not declared at %s "%s" in "%s"'
+                    % (interface_name, type_name, presentation.type, presentation._fullname),
+                    locator=our_interface_assignment._locator, level=Issue.BETWEEN_TYPES)
+
+    # Check that there are no required inputs that we haven't assigned
+    for interface_name, interface_template in template_interfaces.iteritems():
+        if interface_name in interface_definitions:
+            # InterfaceDefinition (or InterfaceAssignment in the case of RelationshipTemplate):
+            interface_definition = interface_definitions[interface_name]
+            our_interface_assignment = our_interface_assignments.get(interface_name) \
+                if our_interface_assignments is not None else None
+            validate_required_inputs(context, presentation, interface_template,
+                                     interface_definition, our_interface_assignment, interface_name)
+
+    return template_interfaces
+
+#
+# Utils
+#
+
+def convert_interface_definition_from_type_to_template(context, presentation, container):
+    from ..assignments import InterfaceAssignment
+
+    if isinstance(presentation, InterfaceAssignment):
+        # Nothing to convert, so just clone
+        return presentation._clone(container)
+
+    raw = convert_interface_definition_from_type_to_raw_template(context, presentation)
+    return InterfaceAssignment(name=presentation._name, raw=raw, container=container)
+
+def convert_interface_definition_from_type_to_raw_template(context, presentation): # pylint: disable=invalid-name
+    raw = OrderedDict()
+
+    # Copy default values for inputs
+    inputs = presentation._get_inputs(context)
+    if inputs is not None:
+        raw['inputs'] = convert_property_definitions_to_values(context, inputs)
+
+    # Copy operations
+    operations = presentation._get_operations(context)
+    if operations:
+        for operation_name, operation in operations.iteritems():
+            raw[operation_name] = OrderedDict()
+            description = operation.description
+            if description is not None:
+                raw[operation_name]['description'] = deepcopy_with_locators(description._raw)
+            implementation = operation.implementation
+            if implementation is not None:
+                raw[operation_name]['implementation'] = deepcopy_with_locators(implementation._raw)
+            inputs = operation.inputs
+            if inputs is not None:
+                raw[operation_name]['inputs'] = convert_property_definitions_to_values(context,
+                                                                                       inputs)
+
+    return raw
+
+def convert_requirement_interface_definitions_from_type_to_raw_template(context, raw_requirement, # pylint: disable=invalid-name
+                                                                        interface_definitions):
+    if not interface_definitions:
+        return
+    if 'interfaces' not in raw_requirement:
+        raw_requirement['interfaces'] = OrderedDict()
+    for interface_name, interface_definition in interface_definitions.iteritems():
+        raw_interface = convert_interface_definition_from_type_to_raw_template(context,
+                                                                               interface_definition)
+        if interface_name in raw_requirement['interfaces']:
+            merge(raw_requirement['interfaces'][interface_name], raw_interface)
+        else:
+            raw_requirement['interfaces'][interface_name] = raw_interface
+
+def merge_interface(context, presentation, interface_assignment, our_interface_assignment,
+                    interface_definition, interface_name):
+    # Assign/merge interface inputs
+    assign_raw_inputs(context, interface_assignment._raw, our_interface_assignment.inputs,
+                      interface_definition._get_inputs(context), interface_name, None, presentation)
+
+    # Assign operation implementations and inputs
+    our_operation_templates = our_interface_assignment.operations # OperationAssignment
+    # OperationDefinition or OperationAssignment:
+    operation_definitions = interface_definition._get_operations(context) \
+        if hasattr(interface_definition, '_get_operations') else interface_definition.operations
+    if our_operation_templates:
+        # OperationAssignment:
+        for operation_name, our_operation_template in our_operation_templates.iteritems():
+            operation_definition = operation_definitions.get(operation_name) # OperationDefinition
+
+            our_input_assignments = our_operation_template.inputs
+            our_implementation = our_operation_template.implementation
+
+            if operation_definition is None:
+                context.validation.report(
+                    'interface definition "%s" refers to an unknown operation "%s" in "%s"'
+                    % (interface_name, operation_name, presentation._fullname),
+                    locator=our_operation_template._locator, level=Issue.BETWEEN_TYPES)
+
+            if (our_input_assignments is not None) or (our_implementation is not None):
+                # Make sure we have the dict
+                if (operation_name not in interface_assignment._raw) \
+                    or (interface_assignment._raw[operation_name] is None):
+                    interface_assignment._raw[operation_name] = OrderedDict()
+
+            if our_implementation is not None:
+                interface_assignment._raw[operation_name]['implementation'] = \
+                    deepcopy_with_locators(our_implementation._raw)
+
+            # Assign/merge operation inputs
+            input_definitions = operation_definition.inputs \
+                if operation_definition is not None else None
+            assign_raw_inputs(context, interface_assignment._raw[operation_name],
+                              our_input_assignments, input_definitions, interface_name,
+                              operation_name, presentation)
+
+def merge_raw_input_definition(context, the_raw_input, our_input, interface_name, operation_name,
+                               presentation, type_name):
+    # Check if we changed the type
+    # TODO: allow a sub-type?
+    input_type1 = the_raw_input.get('type')
+    input_type2 = our_input.type
+    if input_type1 != input_type2:
+        if operation_name is not None:
+            context.validation.report(
+                'interface %s "%s" changes operation input "%s.%s" type from "%s" to "%s" in "%s"'
+                % (type_name, interface_name, operation_name, our_input._name, input_type1,
+                   input_type2, presentation._fullname),
+                locator=input_type2._locator, level=Issue.BETWEEN_TYPES)
+        else:
+            context.validation.report(
+                'interface %s "%s" changes input "%s" type from "%s" to "%s" in "%s"'
+                % (type_name, interface_name, our_input._name, input_type1, input_type2,
+                   presentation._fullname),
+                locator=input_type2._locator, level=Issue.BETWEEN_TYPES)
+
+    # Merge
+    merge(the_raw_input, our_input._raw)
+
+def merge_input_definitions(context, inputs, our_inputs, interface_name, operation_name,
+                            presentation, type_name):
+    for input_name, our_input in our_inputs.iteritems():
+        if input_name in inputs:
+            merge_raw_input_definition(context, inputs[input_name]._raw, our_input, interface_name,
+                                       operation_name, presentation, type_name)
+        else:
+            inputs[input_name] = our_input._clone(presentation)
+
+def merge_raw_input_definitions(context, raw_inputs, our_inputs, interface_name, operation_name,
+                                presentation, type_name):
+    for input_name, our_input in our_inputs.iteritems():
+        if input_name in raw_inputs:
+            merge_raw_input_definition(context, raw_inputs[input_name], our_input, interface_name,
+                                       operation_name, presentation, type_name)
+        else:
+            raw_inputs[input_name] = deepcopy_with_locators(our_input._raw)
+
+def merge_raw_operation_definition(context, raw_operation, our_operation, interface_name,
+                                   presentation, type_name):
+    if not isinstance(our_operation._raw, dict):
+        # Convert short form to long form
+        raw_operation['implementation'] = deepcopy_with_locators(our_operation._raw)
+        return
+
+    # Add/merge inputs
+    our_operation_inputs = our_operation.inputs
+    if our_operation_inputs:
+        # Make sure we have the dict
+        if ('inputs' not in raw_operation) or (raw_operation.get('inputs') is None):
+            raw_operation['inputs'] = OrderedDict()
+
+        merge_raw_input_definitions(context, raw_operation['inputs'], our_operation_inputs,
+                                    interface_name, our_operation._name, presentation, type_name)
+
+    # Override the description
+    if our_operation._raw.get('description') is not None:
+        raw_operation['description'] = deepcopy_with_locators(our_operation._raw['description'])
+
+    # Add/merge implementation
+    if our_operation._raw.get('implementation') is not None:
+        if raw_operation.get('implementation') is not None:
+            merge(raw_operation['implementation'],
+                  deepcopy_with_locators(our_operation._raw['implementation']))
+        else:
+            raw_operation['implementation'] = \
+                deepcopy_with_locators(our_operation._raw['implementation'])
+
+def merge_operation_definitions(context, operations, our_operations, interface_name, presentation,
+                                type_name):
+    if not our_operations:
+        return
+    for operation_name, our_operation in our_operations.iteritems():
+        if operation_name in operations:
+            merge_raw_operation_definition(context, operations[operation_name]._raw, our_operation,
+                                           interface_name, presentation, type_name)
+        else:
+            operations[operation_name] = our_operation._clone(presentation)
+
+def merge_raw_operation_definitions(context, raw_operations, our_operations, interface_name,
+                                    presentation, type_name):
+    for operation_name, our_operation in our_operations.iteritems():
+        if operation_name in raw_operations:
+            raw_operation = raw_operations[operation_name]
+            if isinstance(raw_operation, basestring):
+                # Convert short form to long form
+                raw_operations[operation_name] = OrderedDict((('implementation', raw_operation),))
+                raw_operation = raw_operations[operation_name]
+            merge_raw_operation_definition(context, raw_operation, our_operation, interface_name,
+                                           presentation, type_name)
+        else:
+            raw_operations[operation_name] = deepcopy_with_locators(our_operation._raw)
+
+# From either an InterfaceType or an InterfaceDefinition:
+def merge_interface_definition(context, interface, our_source, presentation, type_name):
+    if hasattr(our_source, 'type'):
+        # Check if we changed the interface type
+        input_type1 = interface.type
+        input_type2 = our_source.type
+        if (input_type1 is not None) and (input_type2 is not None) and (input_type1 != input_type2):
+            context.validation.report(
+                'interface definition "%s" changes type from "%s" to "%s" in "%s"'
+                % (interface._name, input_type1, input_type2, presentation._fullname),
+                locator=input_type2._locator, level=Issue.BETWEEN_TYPES)
+
+    # Add/merge inputs
+    our_interface_inputs = our_source._get_inputs(context) \
+        if hasattr(our_source, '_get_inputs') else our_source.inputs
+    if our_interface_inputs:
+        # Make sure we have the dict
+        if ('inputs' not in interface._raw) or (interface._raw.get('inputs') is None):
+            interface._raw['inputs'] = OrderedDict()
+
+        merge_raw_input_definitions(context, interface._raw['inputs'], our_interface_inputs,
+                                    our_source._name, None, presentation, type_name)
+
+    # Add/merge operations
+    our_operations = our_source._get_operations(context) \
+        if hasattr(our_source, '_get_operations') else our_source.operations
+    if our_operations is not None:
+        merge_raw_operation_definitions(context, interface._raw, our_operations, our_source._name,
+                                        presentation, type_name)
+
+def merge_interface_definitions(context, interfaces, our_interfaces, presentation,
+                                for_presentation=None):
+    if not our_interfaces:
+        return
+    for name, our_interface in our_interfaces.iteritems():
+        if name in interfaces:
+            merge_interface_definition(context, interfaces[name], our_interface, presentation,
+                                       'definition')
+        else:
+            interfaces[name] = our_interface._clone(for_presentation)
+
+def merge_interface_definitions_from_their_types(context, interfaces, presentation):
+    for interface in interfaces.itervalues():
+        the_type = interface._get_type(context) # InterfaceType
+        if the_type is not None:
+            merge_interface_definition(context, interface, the_type, presentation, 'type')
+
+def assign_raw_inputs(context, values, assignments, definitions, interface_name, operation_name,
+                      presentation):
+    if not assignments:
+        return
+
+    # Make sure we have the dict
+    if ('inputs' not in values) or (values['inputs'] is None):
+        values['inputs'] = OrderedDict()
+
+    # Assign inputs
+    for input_name, assignment in assignments.iteritems():
+        if (definitions is not None) and (input_name not in definitions):
+            if operation_name is not None:
+                context.validation.report(
+                    'interface definition "%s" assigns a value to an unknown operation input'
+                    ' "%s.%s" in "%s"'
+                    % (interface_name, operation_name, input_name, presentation._fullname),
+                    locator=assignment._locator, level=Issue.BETWEEN_TYPES)
+            else:
+                context.validation.report(
+                    'interface definition "%s" assigns a value to an unknown input "%s" in "%s"'
+                    % (interface_name, input_name, presentation._fullname),
+                    locator=assignment._locator, level=Issue.BETWEEN_TYPES)
+
+        definition = definitions.get(input_name) if definitions is not None else None
+
+        # Note: default value has already been assigned
+
+        # Coerce value
+        values['inputs'][input_name] = coerce_property_value(context, assignment, definition,
+                                                             assignment.value)
+
+def validate_required_inputs(context, presentation, assignment, definition, original_assignment,
+                             interface_name, operation_name=None):
+    input_definitions = definition.inputs
+    if input_definitions:
+        for input_name, input_definition in input_definitions.iteritems():
+            if input_definition.required:
+                prop = assignment.inputs.get(input_name) \
+                    if ((assignment is not None) and (assignment.inputs is not None)) else None
+                value = prop.value if prop is not None else None
+                value = value.value if value is not None else None
+                if value is None:
+                    if operation_name is not None:
+                        context.validation.report(
+                            'interface definition "%s" does not assign a value to a required'
+                            ' operation input "%s.%s" in "%s"'
+                            % (interface_name, operation_name, input_name, presentation._fullname),
+                            locator=get_locator(original_assignment, presentation._locator),
+                            level=Issue.BETWEEN_TYPES)
+                    else:
+                        context.validation.report(
+                            'interface definition "%s" does not assign a value to a required input'
+                            ' "%s" in "%s"'
+                            % (interface_name, input_name, presentation._fullname),
+                            locator=get_locator(original_assignment, presentation._locator),
+                            level=Issue.BETWEEN_TYPES)
+
+    if operation_name is not None:
+        return
+
+    assignment_operations = assignment.operations
+    operation_definitions = definition._get_operations(context)
+    if operation_definitions:
+        for operation_name, operation_definition in operation_definitions.iteritems():
+            assignment_operation = assignment_operations.get(operation_name) \
+                if assignment_operations is not None else None
+            original_operation = \
+                original_assignment.operations.get(operation_name, original_assignment) \
+                if (original_assignment is not None) \
+                and (original_assignment.operations is not None) \
+                else original_assignment
+            validate_required_inputs(context, presentation, assignment_operation,
+                                     operation_definition, original_operation, interface_name,
+                                     operation_name)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
new file mode 100644
index 0000000..fba1972
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
@@ -0,0 +1,79 @@
+# 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.
+
+from ..presentation.types import convert_shorthand_to_full_type_name
+
+#
+# PolicyType
+#
+
+def get_inherited_targets(context, presentation):
+    """
+    Returns our target node types and group types if we have them or those of our parent, if we have
+    one (recursively).
+    """
+
+    parent = presentation._get_parent(context)
+
+    node_types, group_types = get_inherited_targets(context, parent) \
+        if parent is not None else ([], [])
+
+    our_targets = presentation.targets
+    if our_targets:
+        all_node_types = context.presentation.get('service_template', 'node_types') or {}
+        all_group_types = context.presentation.get('service_template', 'group_types') or {}
+        node_types = []
+        group_types = []
+
+        for our_target in our_targets:
+            if our_target in all_node_types:
+                our_target = convert_shorthand_to_full_type_name(context, our_target,
+                                                                 all_node_types)
+                node_types.append(all_node_types[our_target])
+            elif our_target in all_group_types:
+                our_target = convert_shorthand_to_full_type_name(context, our_target,
+                                                                 all_group_types)
+                group_types.append(all_group_types[our_target])
+
+    return node_types, group_types
+
+#
+# PolicyTemplate
+#
+
+def get_policy_targets(context, presentation):
+    """
+    Returns our target node templates and groups if we have them.
+    """
+
+    node_templates = []
+    groups = []
+
+    our_targets = presentation.targets
+    if our_targets:
+        all_node_templates = \
+            context.presentation.get('service_template', 'topology_template', 'node_templates') \
+            or {}
+        all_groups = \
+            context.presentation.get('service_template', 'topology_template', 'groups') \
+            or {}
+
+        for our_target in our_targets:
+            if our_target in all_node_templates:
+                node_templates.append(all_node_templates[our_target])
+            elif our_target in all_groups:
+                groups.append(all_groups[our_target])
+
+    return node_templates, groups

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
new file mode 100644
index 0000000..d803609
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
@@ -0,0 +1,201 @@
+# 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.
+
+from collections import OrderedDict
+
+from aria.parser.presentation import Value
+from aria.parser.utils import (merge, deepcopy_with_locators)
+from aria.parser.validation import Issue
+
+from .data_types import coerce_value
+
+#
+# ArtifactType, DataType, CapabilityType, RelationshipType, NodeType, GroupType, PolicyType
+#
+
+# Works on properties, parameters, inputs, and attributes
+def get_inherited_property_definitions(context, presentation, field_name, for_presentation=None):
+    """
+    Returns our property definitions added on top of those of our parent, if we have one
+    (recursively).
+
+    Allows overriding all aspects of parent properties except data type.
+    """
+
+    # Get definitions from parent
+    # If we inherit from a primitive, it does not have a parent:
+    parent = presentation._get_parent(context) if hasattr(presentation, '_get_parent') else None
+    definitions = get_inherited_property_definitions(context, parent, field_name,
+                                                     for_presentation=presentation) \
+                                                     if parent is not None else OrderedDict()
+
+    # Add/merge our definitions
+    # If we inherit from a primitive, it does not have our field
+    our_definitions = getattr(presentation, field_name, None)
+    if our_definitions:
+        our_definitions_clone = OrderedDict()
+        for name, our_definition in our_definitions.iteritems():
+            our_definitions_clone[name] = our_definition._clone(for_presentation)
+        our_definitions = our_definitions_clone
+        merge_property_definitions(context, presentation, definitions, our_definitions, field_name)
+
+    for definition in definitions.itervalues():
+        definition._reset_method_cache()
+
+    return definitions
+
+#
+# NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate
+#
+
+def get_assigned_and_defined_property_values(context, presentation):
+    """
+    Returns the assigned property values while making sure they are defined in our type.
+
+    The property definition's default value, if available, will be used if we did not assign it.
+
+    Makes sure that required properties indeed end up with a value.
+    """
+
+    values = OrderedDict()
+
+    the_type = presentation._get_type(context)
+    assignments = presentation.properties
+    definitions = the_type._get_properties(context) if the_type is not None else None
+
+    # Fill in our assignments, but make sure they are defined
+    if assignments:
+        for name, value in assignments.iteritems():
+            if (definitions is not None) and (name in definitions):
+                definition = definitions[name]
+                values[name] = coerce_property_value(context, value, definition, value.value)
+            else:
+                context.validation.report('assignment to undefined property "%s" in "%s"'
+                                          % (name, presentation._fullname),
+                                          locator=value._locator, level=Issue.BETWEEN_TYPES)
+
+    # Fill in defaults from the definitions
+    if definitions:
+        for name, definition in definitions.iteritems():
+            if (values.get(name) is None) and (definition.default is not None):
+                values[name] = coerce_property_value(context, presentation, definition,
+                                                     definition.default)
+
+    validate_required_values(context, presentation, values, definitions)
+
+    return values
+
+#
+# TopologyTemplate
+#
+
+def get_parameter_values(context, presentation, field_name):
+    values = OrderedDict()
+
+    parameters = getattr(presentation, field_name)
+
+    # Fill in defaults and values
+    if parameters:
+        for name, parameter in parameters.iteritems():
+            if values.get(name) is None:
+                if hasattr(parameter, 'value') and (parameter.value is not None):
+                    # For parameters only:
+                    values[name] = coerce_property_value(context, presentation, parameter,
+                                                         parameter.value)
+                else:
+                    default = parameter.default if hasattr(parameter, 'default') else None
+                    values[name] = coerce_property_value(context, presentation, parameter, default)
+
+    return values
+
+#
+# Utils
+#
+
+def validate_required_values(context, presentation, values, definitions):
+    """
+    Check if required properties have not been assigned.
+    """
+
+    if not definitions:
+        return
+    for name, definition in definitions.iteritems():
+        if getattr(definition, 'required', False) \
+            and ((values is None) or (values.get(name) is None)):
+            context.validation.report('required property "%s" is not assigned a value in "%s"'
+                                      % (name, presentation._fullname),
+                                      locator=presentation._get_child_locator('properties'),
+                                      level=Issue.BETWEEN_TYPES)
+
+def merge_raw_property_definition(context, presentation, raw_property_definition,
+                                  our_property_definition, field_name, property_name):
+    # Check if we changed the type
+    # TODO: allow a sub-type?
+    type1 = raw_property_definition.get('type')
+    type2 = our_property_definition.type
+    if type1 != type2:
+        context.validation.report(
+            'override changes type from "%s" to "%s" for property "%s" in "%s"'
+            % (type1, type2, property_name, presentation._fullname),
+            locator=presentation._get_child_locator(field_name, property_name),
+            level=Issue.BETWEEN_TYPES)
+
+    merge(raw_property_definition, our_property_definition._raw)
+
+def merge_raw_property_definitions(context, presentation, raw_property_definitions,
+                                   our_property_definitions, field_name):
+    if not our_property_definitions:
+        return
+    for property_name, our_property_definition in our_property_definitions.iteritems():
+        if property_name in raw_property_definitions:
+            raw_property_definition = raw_property_definitions[property_name]
+            merge_raw_property_definition(context, presentation, raw_property_definition,
+                                          our_property_definition, field_name, property_name)
+        else:
+            raw_property_definitions[property_name] = \
+                deepcopy_with_locators(our_property_definition._raw)
+
+def merge_property_definitions(context, presentation, property_definitions,
+                               our_property_definitions, field_name):
+    if not our_property_definitions:
+        return
+    for property_name, our_property_definition in our_property_definitions.iteritems():
+        if property_name in property_definitions:
+            property_definition = property_definitions[property_name]
+            merge_raw_property_definition(context, presentation, property_definition._raw,
+                                          our_property_definition, field_name, property_name)
+        else:
+            property_definitions[property_name] = our_property_definition
+
+# Works on properties, inputs, and parameters
+def coerce_property_value(context, presentation, definition, value, aspect=None):
+    the_type = definition._get_type(context) if definition is not None else None
+    entry_schema = definition.entry_schema if definition is not None else None
+    constraints = definition._get_constraints(context) if definition is not None else None
+    value = coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect)
+    if (the_type is not None) and hasattr(the_type, '_name'):
+        type_name = the_type._name
+    else:
+        type_name = getattr(definition, 'type', None)
+    description = getattr(definition, 'description', None)
+    description = description.value if description is not None else None
+    return Value(type_name, value, description)
+
+def convert_property_definitions_to_values(context, definitions):
+    values = OrderedDict()
+    for name, definition in definitions.iteritems():
+        default = definition.default
+        values[name] = coerce_property_value(context, definition, definition, default)
+    return values

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py
new file mode 100644
index 0000000..721ea09
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py
@@ -0,0 +1,358 @@
+# 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.
+
+from collections import OrderedDict
+
+from aria.parser.validation import Issue
+from aria.parser.utils import deepcopy_with_locators
+
+from .properties import (convert_property_definitions_to_values, validate_required_values,
+                         coerce_property_value)
+from .interfaces import (convert_requirement_interface_definitions_from_type_to_raw_template,
+                         merge_interface_definitions, merge_interface, validate_required_inputs)
+
+#
+# NodeType
+#
+
+def get_inherited_requirement_definitions(context, presentation):
+    """
+    Returns our requirement definitions added on top of those of our parent, if we have one
+    (recursively).
+
+    Allows overriding requirement definitions if they have the same name.
+    """
+
+    parent = presentation._get_parent(context)
+    requirement_definitions = get_inherited_requirement_definitions(context, parent) \
+        if parent is not None else []
+
+    our_requirement_definitions = presentation.requirements
+    if our_requirement_definitions:
+        for requirement_name, our_requirement_definition in our_requirement_definitions:
+            # Remove existing requirement definitions of this name if they exist
+            for name, requirement_definition in requirement_definitions:
+                if name == requirement_name:
+                    requirement_definitions.remove((name, requirement_definition))
+
+            requirement_definitions.append((requirement_name, our_requirement_definition))
+
+    return requirement_definitions
+
+#
+# NodeTemplate
+#
+
+def get_template_requirements(context, presentation):
+    """
+    Returns our requirements added on top of those of the node type if they exist there.
+
+    If the requirement has a relationship, the relationship properties and interfaces are assigned.
+
+    Returns the assigned property, interface input, and interface operation input values while
+    making sure they are defined in our type. Default values, if available, will be used if we did
+    not assign them. Also makes sure that required properties and inputs indeed end up with a value.
+    """
+
+    requirement_assignments = []
+
+    the_type = presentation._get_type(context) # NodeType
+    requirement_definitions = the_type._get_requirements(context) if the_type is not None else None
+
+    # Add our requirement assignments
+    our_requirement_assignments = presentation.requirements
+    if our_requirement_assignments:
+        add_requirement_assignments(context, presentation, requirement_assignments,
+                                    requirement_definitions, our_requirement_assignments)
+
+    # Validate occurrences
+    if requirement_definitions:
+        for requirement_name, requirement_definition in requirement_definitions:
+            # Allowed occurrences
+            allowed_occurrences = requirement_definition.occurrences
+            allowed_occurrences = allowed_occurrences if allowed_occurrences is not None else None
+
+            # Count actual occurrences
+            actual_occurrences = 0
+            for name, _ in requirement_assignments:
+                if name == requirement_name:
+                    actual_occurrences += 1
+
+            if allowed_occurrences is None:
+                # If not specified, we interpret this to mean that exactly 1 occurrence is required
+                if actual_occurrences == 0:
+                    # If it's not there, we will automatically add it (this behavior is not in the
+                    # TOSCA spec, but seems implied)
+                    requirement_assignment, \
+                    relationship_property_definitions, \
+                    relationship_interface_definitions = \
+                        convert_requirement_from_definition_to_assignment(context,
+                                                                          requirement_definition,
+                                                                          None, presentation)
+                    validate_requirement_assignment(context, presentation, requirement_assignment,
+                                                    relationship_property_definitions,
+                                                    relationship_interface_definitions)
+                    requirement_assignments.append((requirement_name, requirement_assignment))
+                elif actual_occurrences > 1:
+                    context.validation.report(
+                        'requirement "%s" is allowed only one occurrence in "%s": %d'
+                        % (requirement_name, presentation._fullname, actual_occurrences),
+                        locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+            else:
+                if not allowed_occurrences.is_in(actual_occurrences):
+                    if allowed_occurrences.value[1] == 'UNBOUNDED':
+                        context.validation.report(
+                            'requirement "%s" does not have at least %d occurrences in "%s": has %d'
+                            % (requirement_name, allowed_occurrences.value[0],
+                               presentation._fullname, actual_occurrences),
+                            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+                    else:
+                        context.validation.report(
+                            'requirement "%s" is allowed between %d and %d occurrences in "%s":'
+                            ' has %d'
+                            % (requirement_name, allowed_occurrences.value[0],
+                               allowed_occurrences.value[1], presentation._fullname,
+                               actual_occurrences),
+                            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
+    return requirement_assignments
+
+#
+# Utils
+#
+
+def convert_requirement_from_definition_to_assignment(context, requirement_definition, # pylint: disable=too-many-branches
+                                                      our_requirement_assignment, container):
+    from ..assignments import RequirementAssignment
+
+    raw = OrderedDict()
+
+    # Capability type name:
+    raw['capability'] = deepcopy_with_locators(requirement_definition.capability)
+
+    node_type = requirement_definition._get_node_type(context)
+    if node_type is not None:
+        raw['node'] = deepcopy_with_locators(node_type._name)
+
+    relationship_type = None
+    relationship_template = None
+    relationship_property_definitions = None
+    relationship_interface_definitions = None
+
+    # First try to find the relationship if we declared it
+    # RelationshipAssignment:
+    our_relationship = our_requirement_assignment.relationship \
+        if our_requirement_assignment is not None else None
+    if our_relationship is not None:
+        relationship_type, relationship_type_variant = our_relationship._get_type(context)
+        if relationship_type_variant == 'relationship_template':
+            relationship_template = relationship_type
+            relationship_type = relationship_template._get_type(context)
+
+    # If not exists, try at the node type
+    relationship_definition = None
+    if relationship_type is None:
+        relationship_definition = requirement_definition.relationship # RelationshipDefinition
+        if relationship_definition is not None:
+            relationship_type = relationship_definition._get_type(context)
+
+    if relationship_type is not None:
+        raw['relationship'] = OrderedDict()
+
+        type_name = our_relationship.type if our_relationship is not None else None
+        if type_name is None:
+            type_name = relationship_type._name
+
+        raw['relationship']['type'] = deepcopy_with_locators(type_name)
+
+        # These are our property definitions
+        relationship_property_definitions = relationship_type._get_properties(context)
+
+        if relationship_template is not None:
+            # Property values from template
+            raw['properties'] = relationship_template._get_property_values(context)
+        else:
+            if relationship_property_definitions:
+                # Convert property definitions to values
+                raw['properties'] = \
+                    convert_property_definitions_to_values(context,
+                                                           relationship_property_definitions)
+
+        # These are our interface definitions
+        # InterfaceDefinition:
+        relationship_interface_definitions = OrderedDict(relationship_type._get_interfaces(context))
+
+        if relationship_definition:
+            # Merge extra interface definitions
+            # InterfaceDefinition:
+            relationship_interface_definitions = relationship_definition.interfaces
+            merge_interface_definitions(context, relationship_interface_definitions,
+                                        relationship_interface_definitions, requirement_definition,
+                                        container)
+
+        if relationship_template is not None:
+            # Interfaces from template
+            interfaces = relationship_template._get_interfaces(context)
+            if interfaces:
+                raw['relationship']['interfaces'] = OrderedDict()
+                for interface_name, interface in interfaces.iteritems():
+                    raw['relationship']['interfaces'][interface_name] = interface._raw
+        else:
+            # Convert interface definitions to templates
+            convert_requirement_interface_definitions_from_type_to_raw_template(
+                context,
+                raw['relationship'],
+                relationship_interface_definitions)
+
+    return \
+        RequirementAssignment(name=requirement_definition._name, raw=raw, container=container), \
+        relationship_property_definitions, \
+        relationship_interface_definitions
+
+def add_requirement_assignments(context, presentation, requirement_assignments,
+                                requirement_definitions, our_requirement_assignments):
+    for requirement_name, our_requirement_assignment in our_requirement_assignments:
+        requirement_definition = get_first_requirement(requirement_definitions, requirement_name)
+        if requirement_definition is not None:
+            requirement_assignment, \
+            relationship_property_definitions, \
+            relationship_interface_definitions = \
+                convert_requirement_from_definition_to_assignment(context, requirement_definition,
+                                                                  our_requirement_assignment,
+                                                                  presentation)
+            merge_requirement_assignment(context,
+                                         relationship_property_definitions,
+                                         relationship_interface_definitions,
+                                         requirement_assignment, our_requirement_assignment)
+            validate_requirement_assignment(context,
+                                            our_requirement_assignment.relationship \
+                                            or our_requirement_assignment,
+                                            requirement_assignment,
+                                            relationship_property_definitions,
+                                            relationship_interface_definitions)
+            requirement_assignments.append((requirement_name, requirement_assignment))
+        else:
+            context.validation.report('requirement "%s" not declared at node type "%s" in "%s"'
+                                      % (requirement_name, presentation.type,
+                                         presentation._fullname),
+                                      locator=our_requirement_assignment._locator,
+                                      level=Issue.BETWEEN_TYPES)
+
+def merge_requirement_assignment(context, relationship_property_definitions,
+                                 relationship_interface_definitions, requirement, our_requirement):
+    our_capability = our_requirement.capability
+    if our_capability is not None:
+        requirement._raw['capability'] = deepcopy_with_locators(our_capability)
+
+    our_node = our_requirement.node
+    if our_node is not None:
+        requirement._raw['node'] = deepcopy_with_locators(our_node)
+
+    our_node_filter = our_requirement.node_filter
+    if our_node_filter is not None:
+        requirement._raw['node_filter'] = deepcopy_with_locators(our_node_filter._raw)
+
+    our_relationship = our_requirement.relationship # RelationshipAssignment
+    if our_relationship is not None:
+        # Make sure we have a dict
+        if 'relationship' not in requirement._raw:
+            requirement._raw['relationship'] = OrderedDict()
+        elif not isinstance(requirement._raw['relationship'], dict):
+            # Convert existing short form to long form
+            the_type = requirement._raw['relationship']
+            requirement._raw['relationship'] = OrderedDict()
+            requirement._raw['relationship']['type'] = deepcopy_with_locators(the_type)
+
+        merge_requirement_assignment_relationship(context, our_relationship,
+                                                  relationship_property_definitions,
+                                                  relationship_interface_definitions,
+                                                  requirement, our_relationship)
+
+def merge_requirement_assignment_relationship(context, presentation, property_definitions,
+                                              interface_definitions, requirement, our_relationship):
+    the_type = our_relationship.type
+    if the_type is not None:
+        # Could be a type or a template:
+        requirement._raw['relationship']['type'] = deepcopy_with_locators(the_type)
+
+    our_relationship_properties = our_relationship._raw.get('properties')
+    if our_relationship_properties:
+        # Make sure we have a dict
+        if 'properties' not in requirement._raw['relationship']:
+            requirement._raw['relationship']['properties'] = OrderedDict()
+
+        # Merge our properties
+        for property_name, prop in our_relationship_properties.iteritems():
+            if property_name in property_definitions:
+                definition = property_definitions[property_name]
+                requirement._raw['relationship']['properties'][property_name] = \
+                    coerce_property_value(context, presentation, definition, prop)
+            else:
+                context.validation.report(
+                    'relationship property "%s" not declared at definition of requirement "%s"'
+                    ' in "%s"'
+                    % (property_name, presentation._fullname,
+                       presentation._container._container._fullname),
+                    locator=our_relationship._get_child_locator('properties', property_name),
+                    level=Issue.BETWEEN_TYPES)
+
+    our_interfaces = our_relationship.interfaces
+    if our_interfaces:
+        # Make sure we have a dict
+        if 'interfaces' not in requirement._raw['relationship']:
+            requirement._raw['relationship']['interfaces'] = OrderedDict()
+
+        # Merge interfaces
+        for interface_name, our_interface in our_interfaces.iteritems():
+            if interface_name not in requirement._raw['relationship']['interfaces']:
+                requirement._raw['relationship']['interfaces'][interface_name] = OrderedDict()
+
+            if (interface_definitions is not None) and (interface_name in interface_definitions):
+                interface_definition = interface_definitions[interface_name]
+                interface_assignment = requirement.relationship.interfaces[interface_name]
+                merge_interface(context, presentation, interface_assignment, our_interface,
+                                interface_definition, interface_name)
+            else:
+                context.validation.report(
+                    'interface definition "%s" not declared at definition of requirement "%s"'
+                    ' in "%s"'
+                    % (interface_name, presentation._fullname,
+                       presentation._container._container._fullname),
+                    locator=our_relationship._locator, level=Issue.BETWEEN_TYPES)
+
+def validate_requirement_assignment(context, presentation, requirement_assignment,
+                                    relationship_property_definitions,
+                                    relationship_interface_definitions):
+    relationship = requirement_assignment.relationship
+    if relationship is None:
+        return
+
+    validate_required_values(context, presentation, relationship.properties,
+                             relationship_property_definitions)
+
+    if relationship_interface_definitions:
+        for interface_name, relationship_interface_definition \
+            in relationship_interface_definitions.iteritems():
+            interface_assignment = relationship.interfaces.get(interface_name) \
+                if relationship.interfaces is not None else None
+            validate_required_inputs(context, presentation, interface_assignment,
+                                     relationship_interface_definition, None, interface_name)
+
+def get_first_requirement(requirement_definitions, name):
+    if requirement_definitions is not None:
+        for requirement_name, requirement_definition in requirement_definitions:
+            if requirement_name == name:
+                return requirement_definition
+    return None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py
new file mode 100644
index 0000000..e0252b1
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py
@@ -0,0 +1,126 @@
+# 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.
+
+from aria.parser.utils import safe_repr
+from aria.parser.validation import Issue
+
+def validate_subtitution_mappings_requirement(context, presentation):
+    if not validate_format(context, presentation, 'requirement'):
+        return
+
+    node_template = get_node_template(context, presentation, 'requirement')
+    if node_template is None:
+        return
+
+    node_type = presentation._container._get_type(context)
+    if node_type is None:
+        return
+
+    requirements = node_type._get_requirements(context)
+    type_requirement = None
+    for name, the_requirement in requirements:
+        if name == presentation._name:
+            type_requirement = the_requirement
+            break
+    if type_requirement is None:
+        context.validation.report(
+            'substitution mappings requirement "%s" is not declared in node type "%s"'
+            % (presentation._name, node_type._name),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+        return
+
+    requirement_name = presentation._raw[1]
+    requirements = node_template._get_requirements(context)
+    requirement = None
+    for name, the_requirement in requirements:
+        if name == requirement_name:
+            requirement = the_requirement
+            break
+
+    if requirement is None:
+        context.validation.report(
+            'substitution mappings requirement "%s" refers to an unknown requirement of node '
+            'template "%s": %s'
+            % (presentation._name, node_template._name, safe_repr(requirement_name)),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+        return
+
+def validate_subtitution_mappings_capability(context, presentation):
+    if not validate_format(context, presentation, 'capability'):
+        return
+
+    node_template = get_node_template(context, presentation, 'capability')
+    if node_template is None:
+        return
+
+    node_type = presentation._container._get_type(context)
+    if node_type is None:
+        return
+
+    capabilities = node_type._get_capabilities(context)
+    type_capability = capabilities.get(presentation._name)
+    if type_capability is None:
+        context.validation.report(
+            'substitution mappings capability "%s" is not declared in node type "%s"'
+            % (presentation._name, node_type._name), locator=presentation._locator,
+            level=Issue.BETWEEN_TYPES)
+        return
+
+    capability_name = presentation._raw[1]
+    capabilities = node_template._get_capabilities(context)
+    capability = capabilities.get(capability_name)
+
+    if capability is None:
+        context.validation.report(
+            'substitution mappings capability "%s" refers to an unknown capability of node template'
+            ' "%s": %s'
+            % (presentation._name, node_template._name, safe_repr(capability_name)),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+        return
+
+    type_capability_type = type_capability._get_type(context)
+    capability_type = capability._get_type(context)
+
+    if not type_capability_type._is_descendant(context, capability_type):
+        context.validation.report(
+            'type "%s" of substitution mappings capability "%s" is not a descendant of "%s"'
+            % (capability_type._name, presentation._name, type_capability_type._name),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
+#
+# Utils
+#
+
+def validate_format(context, presentation, name):
+    if (not isinstance(presentation._raw, list)) or (len(presentation._raw) != 2) \
+        or (not isinstance(presentation._raw[0], basestring)) \
+        or (not isinstance(presentation._raw[1], basestring)):
+        context.validation.report(
+            'substitution mappings %s "%s" is not a list of 2 strings: %s'
+            % (name, presentation._name, safe_repr(presentation._raw)),
+            locator=presentation._locator, level=Issue.FIELD)
+        return False
+    return True
+
+def get_node_template(context, presentation, name):
+    node_template_name = presentation._raw[0]
+    node_template = context.presentation.get_from_dict('service_template', 'topology_template',
+                                                       'node_templates', node_template_name)
+    if node_template is None:
+        context.validation.report(
+            'substitution mappings %s "%s" refers to an unknown node template: %s'
+            % (name, presentation._name, safe_repr(node_template_name)),
+            locator=presentation._locator, level=Issue.FIELD)
+    return node_template

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/__init__.py
@@ -0,0 +1,14 @@
+# 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.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py
new file mode 100644
index 0000000..22e9606
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py
@@ -0,0 +1,32 @@
+# 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.
+
+from aria.parser.presentation import (Presentation, has_fields, primitive_dict_field)
+from aria.parser.utils import cachedmethod
+
+@has_fields
+class ExtensiblePresentation(Presentation):
+    """
+    A presentation that supports an optional :code:`_extensions` dict field.
+    """
+
+    @primitive_dict_field()
+    def _extensions(self):
+        pass
+
+    @cachedmethod
+    def _get_extension(self, name, default=None):
+        extensions = self._extensions
+        return extensions.get(name, default) if extensions is not None else None # pylint: disable=no-member


Mime
View raw message