http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
index 9bafeec..e411104 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
@@ -88,7 +88,7 @@ def get_assigned_and_defined_parameter_values(context, 
presentation, field_name)
                 definition = definitions[name]
                 values[name] = coerce_parameter_value(context, value, 
definition, value.value)
             else:
-                context.validation.report('assignment to undefined {0} "{1}" 
in "{2}"'
+                context.validation.report(u'assignment to undefined {0} "{1}" 
in "{2}"'
                                           .format(field_name, name, 
presentation._fullname),
                                           locator=value._locator, 
level=Issue.BETWEEN_TYPES)
 
@@ -99,7 +99,7 @@ def get_assigned_and_defined_parameter_values(context, 
presentation, field_name)
             if (name not in values) and \
                 (('default' in definition._raw) or (field_name == 
'attribute')):
                 values[name] = coerce_parameter_value(context, presentation, 
definition,
-                                                      definition.default)
+                                                      definition.default, 
'default')
 
     validate_required_values(context, presentation, values, definitions)
 
@@ -131,7 +131,8 @@ def get_parameter_values(context, presentation, field_name):
                                                           parameter.value)
                 else:
                     default = parameter.default if hasattr(parameter, 
'default') else None
-                    values[name] = coerce_parameter_value(context, 
presentation, parameter, default)
+                    values[name] = coerce_parameter_value(context, 
presentation, parameter, default,
+                                                          'default')
 
     return values
 
@@ -147,11 +148,21 @@ def validate_required_values(context, presentation, 
values, definitions):
 
     if not definitions:
         return
+
+    def has_value(name):
+        if values is None:
+            return False
+        value = values.get(name)
+        if value is None:
+            return False
+        if isinstance(value, Value) and (value.value is None):
+            return False
+        return True
+
     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),
+        if getattr(definition, 'required', False) and not has_value(name):
+            context.validation.report(u'required property "{0}" is not 
assigned a value in "{1}"'
+                                      .format(name, presentation._fullname),
                                       
locator=presentation._get_child_locator('properties'),
                                       level=Issue.BETWEEN_TYPES)
 
@@ -166,14 +177,14 @@ def merge_raw_parameter_definition(context, presentation, 
raw_property_definitio
     our_property_definition._reset_method_cache()
     type2 = our_property_definition._get_type(context)
 
-    if type1 != type2:
-        if not hasattr(type1, '_is_descendant') or not 
type1._is_descendant(context, type2):
-            context.validation.report(
-                'property definition type "{0}" is not a descendant of 
overridden '
-                'property definition type "{1}"' \
-                .format(type1_name, type2._name),
-                locator=presentation._get_child_locator(field_name, 
property_name),
-                level=Issue.BETWEEN_TYPES)
+    if (type1 is not type2) and \
+        (not hasattr(type1, '_is_descendant') or not 
type1._is_descendant(context, type2)):
+        context.validation.report(
+            u'property definition type "{0}" is not a descendant of overridden 
'
+            u'property definition type "{1}"' \
+            .format(our_property_definition.type, type1_name),
+            locator=presentation._get_child_locator(field_name, property_name),
+            level=Issue.BETWEEN_TYPES)
 
     merge(raw_property_definition, our_property_definition._raw)
 
@@ -225,6 +236,6 @@ def coerce_parameter_value(context, presentation, 
definition, value, aspect=None
 def convert_parameter_definitions_to_values(context, definitions):
     values = OrderedDict()
     for name, definition in definitions.iteritems():
-        default = definition.default
-        values[name] = coerce_parameter_value(context, definition, definition, 
default)
+        values[name] = coerce_parameter_value(context, definition, definition, 
definition.default,
+                                              'default')
     return values

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/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
index 6bdb5b1..79958a1 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/requirements.py
@@ -82,7 +82,6 @@ def get_template_requirements(context, presentation):
         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
@@ -103,28 +102,30 @@ def get_template_requirements(context, presentation):
                                                                           
None, presentation)
                     validate_requirement_assignment(context, presentation, 
requirement_assignment,
                                                     
relationship_property_definitions,
-                                                    
relationship_interface_definitions)
+                                                    
relationship_interface_definitions,
+                                                    requirement_definition)
                     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),
+                        u'requirement "{0}" is allowed only one occurrence in 
"{1}": {2:d}'
+                        .format(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),
+                            u'requirement "{0}" does not have at least {1:d} 
occurrences in "{3}":'
+                            u' has {4:d}'
+                            .format(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),
+                            u'requirement "{0}" is allowed between {1:d} and 
{2:d} occurrences in'
+                            u' "{3}": has {4:d}'
+                            .format(requirement_name, 
allowed_occurrences.value[0],
+                                    allowed_occurrences.value[1], 
presentation._fullname,
+                                    actual_occurrences),
                             locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
 
     return requirement_assignments
@@ -134,7 +135,7 @@ def get_template_requirements(context, presentation):
 # Utils
 #
 
-def convert_requirement_from_definition_to_assignment(context, 
requirement_definition, # pylint: disable=too-many-branches
+def convert_requirement_from_definition_to_assignment(context, 
requirement_definition,              # pylint: disable=too-many-branches
                                                       
our_requirement_assignment, container):
     from ..assignments import RequirementAssignment
 
@@ -174,9 +175,9 @@ def 
convert_requirement_from_definition_to_assignment(context, requirement_defin
         # Make sure the type is derived
         if not definition_relationship_type._is_descendant(context, 
relationship_type):
             context.validation.report(
-                'assigned relationship type "%s" is not a descendant of 
declared relationship type'
-                ' "%s"' \
-                % (relationship_type._name, 
definition_relationship_type._name),
+                u'assigned relationship type "{0}" is not a descendant of 
declared relationship '
+                u' type "{1}"'
+                .format(relationship_type._name, 
definition_relationship_type._name),
                 locator=container._locator, level=Issue.BETWEEN_TYPES)
 
     if relationship_type is not None:
@@ -253,12 +254,13 @@ def add_requirement_assignments(context, presentation, 
requirement_assignments,
                                             or our_requirement_assignment,
                                             requirement_assignment,
                                             relationship_property_definitions,
-                                            relationship_interface_definitions)
+                                            relationship_interface_definitions,
+                                            requirement_definition)
             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),
+            context.validation.report(u'requirement "{0}" not declared at node 
type "{1}" in "{2}"'
+                                      .format(requirement_name, 
presentation.type,
+                                              presentation._fullname),
                                       
locator=our_requirement_assignment._locator,
                                       level=Issue.BETWEEN_TYPES)
 
@@ -278,7 +280,7 @@ def merge_requirement_assignment(context, 
relationship_property_definitions,
         requirement._raw['node_filter'] = 
deepcopy_with_locators(our_node_filter._raw)
 
     our_relationship = our_requirement.relationship # RelationshipAssignment
-    if (our_relationship is not None) and (our_relationship.type is None):
+    if our_relationship is not None:
         # Make sure we have a dict
         if 'relationship' not in requirement._raw:
             requirement._raw['relationship'] = OrderedDict()
@@ -291,7 +293,8 @@ def merge_requirement_assignment(context, 
relationship_property_definitions,
 
 def merge_requirement_assignment_relationship(context, presentation, 
property_definitions,
                                               interface_definitions, 
requirement, our_relationship):
-    our_relationship_properties = our_relationship._raw.get('properties')
+    our_relationship_properties = our_relationship._raw.get('properties') \
+        if isinstance(our_relationship._raw, dict) else None
     if our_relationship_properties:
         # Make sure we have a dict
         if 'properties' not in requirement._raw['relationship']:
@@ -305,10 +308,10 @@ def merge_requirement_assignment_relationship(context, 
presentation, property_de
                     coerce_parameter_value(context, presentation, definition, 
prop)
             else:
                 context.validation.report(
-                    'relationship property "%s" not declared at definition of 
requirement "%s"'
-                    ' in "%s"'
-                    % (property_name, requirement._fullname,
-                       presentation._container._container._fullname),
+                    u'relationship property "{0}" not declared at definition 
of requirement "{1}"'
+                    u' in "{2}"'
+                    .format(property_name, requirement._fullname,
+                            presentation._container._container._fullname),
                     locator=our_relationship._get_child_locator('properties', 
property_name),
                     level=Issue.BETWEEN_TYPES)
 
@@ -330,28 +333,58 @@ def merge_requirement_assignment_relationship(context, 
presentation, property_de
                                 interface_definition, interface_name)
             else:
                 context.validation.report(
-                    'relationship interface "%s" not declared at definition of 
requirement "%s"'
-                    ' in "%s"'
-                    % (interface_name, requirement._fullname,
-                       presentation._container._container._fullname),
+                    u'relationship interface "{0}" not declared at definition 
of requirement "{1}"'
+                    u' in "{2}"'
+                    .format(interface_name, requirement._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_interface_definitions, 
requirement_definition):
+    # Validate node
+    definition_node_type = requirement_definition._get_node_type(context)
+    assignment_node_type, node_variant = 
requirement_assignment._get_node(context)
+    if node_variant == 'node_template':
+        assignment_node_type = assignment_node_type._get_type(context)
+    if (assignment_node_type is not None) and (definition_node_type is not 
None) and \
+        (assignment_node_type is not definition_node_type) and \
+        (not definition_node_type._is_descendant(context, 
assignment_node_type)):
+        context.validation.report(
+            u'requirement assignment node "{0}" is not derived from node type 
"{1}" of requirement '
+            u'definition in {2}'
+            .format(requirement_assignment.node, requirement_definition.node,
+                    presentation._container._fullname),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
+    # Validate capability
+    definition_capability_type = 
requirement_definition._get_capability_type(context)
+    assignment_capability_type, capability_variant = 
requirement_assignment._get_capability(context)
+    if capability_variant == 'capability_assignment':
+        assignment_capability_type = 
assignment_capability_type._get_type(context)
+    if (assignment_capability_type is not None) and 
(definition_capability_type is not None) and \
+        (assignment_capability_type is not definition_capability_type) and \
+        (not definition_capability_type._is_descendant(context, 
assignment_capability_type)):
+        context.validation.report(
+            u'requirement assignment capability "{0}" is not derived from 
capability type "{1}" of '
+            u'requirement definition in {2}'
+            .format(requirement_assignment.capability, 
requirement_definition.capability,
+                    presentation._container._fullname),
+            locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
     relationship = requirement_assignment.relationship
-    if relationship is None:
-        return
 
-    validate_required_values(context, presentation, relationship.properties,
-                             relationship_property_definitions)
+    values = OrderedDict((name, prop.value)
+                         for name, prop in 
relationship.properties.iteritems()) \
+                         if (relationship and relationship.properties) else {}
+    validate_required_values(context, presentation, values, 
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
+                if (relationship and relationship.interfaces) else None
             validate_required_inputs(context, presentation, 
interface_assignment,
                                      relationship_interface_definition, None, 
interface_name)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/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
index e2af4b8..ae2f924 100644
--- 
a/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py
+++ 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py
@@ -18,8 +18,7 @@ from aria.parser.validation import Issue
 
 
 def validate_substitution_mappings_requirement(context, presentation):
-
-    # validate that the requirement in substitution_mapping is defined in the 
substitution node type
+    # Validate that the requirement in substitution_mapping is defined in the 
substitution node type
     substitution_node_type = presentation._container._get_type(context)
     if substitution_node_type is None:
         return
@@ -29,7 +28,7 @@ def validate_substitution_mappings_requirement(context, 
presentation):
             break
     else:
         context.validation.report(
-            'substitution mapping requirement "{0}" is not declared in node 
type "{1}"'.format(
+            u'substitution mapping requirement "{0}" is not declared in node 
type "{1}"'.format(
                 presentation._name, substitution_node_type._name),
             locator=presentation._locator, level=Issue.BETWEEN_TYPES)
         return
@@ -38,7 +37,7 @@ def validate_substitution_mappings_requirement(context, 
presentation):
         _report_invalid_mapping_format(context, presentation, 
field='requirement')
         return
 
-    # validate that the mapped requirement is defined in the corresponding 
node template
+    # Validate that the mapped requirement is defined in the corresponding 
node template
     node_template = _get_node_template(context, presentation)
     if node_template is None:
         _report_missing_node_template(context, presentation, 
field='requirement')
@@ -50,24 +49,24 @@ def validate_substitution_mappings_requirement(context, 
presentation):
             break
     else:
         context.validation.report(
-            'substitution mapping requirement "{0}" refers to an unknown 
requirement of node '
-            'template "{1}": {mapped_requirement_name}'.format(
+            u'substitution mapping requirement "{0}" refers to an unknown 
requirement of node '
+            u'template "{1}": {mapped_requirement_name}'.format(
                 presentation._name, node_template._name,
                 mapped_requirement_name=safe_repr(mapped_requirement_name)),
             locator=presentation._locator, level=Issue.BETWEEN_TYPES)
         return
 
-    # validate that the requirement's capability type in substitution_mapping 
is derived from the
+    # Validate that the requirement's capability type in substitution_mapping 
is derived from the
     # requirement's capability type in the corresponding node template
     substitution_type_requirement_capability_type = \
         substitution_type_requirement._get_capability_type(context)
     node_template_requirement_capability_type = \
         node_template_requirement._get_capability(context)[0]
-    if not node_template_requirement_capability_type._is_descendant(
-            context, substitution_type_requirement_capability_type):
+    if not substitution_type_requirement_capability_type._is_descendant(
+            context, node_template_requirement_capability_type):
         context.validation.report(
-            'substitution mapping requirement "{0}" of capability type "{1}" 
is not a descendant '
-            'of the mapped node template capability type "{2}"'.format(
+            u'substitution mapping requirement "{0}" of capability type "{1}" 
is not a descendant '
+            u'of the mapped node template capability type "{2}"'.format(
                 presentation._name,
                 substitution_type_requirement_capability_type._name,
                 node_template_requirement_capability_type._name),
@@ -75,8 +74,7 @@ def validate_substitution_mappings_requirement(context, 
presentation):
 
 
 def validate_substitution_mappings_capability(context, presentation):
-
-    # validate that the capability in substitution_mapping is defined in the 
substitution node type
+    # Validate that the capability in substitution_mapping is defined in the 
substitution node type
     substitution_node_type = presentation._container._get_type(context)
     if substitution_node_type is None:
         return
@@ -84,8 +82,8 @@ def validate_substitution_mappings_capability(context, 
presentation):
     substitution_type_capability = 
substitution_type_capabilities.get(presentation._name)
     if substitution_type_capability is None:
         context.validation.report(
-            'substitution mapping capability "{0}" '
-            'is not declared in node type "{substitution_type}"'.format(
+            u'substitution mapping capability "{0}" '
+            u'is not declared in node type "{substitution_type}"'.format(
                 presentation._name, 
substitution_type=substitution_node_type._name),
             locator=presentation._locator, level=Issue.BETWEEN_TYPES)
         return
@@ -94,7 +92,7 @@ def validate_substitution_mappings_capability(context, 
presentation):
         _report_invalid_mapping_format(context, presentation, 
field='capability')
         return
 
-    # validate that the capability in substitution_mapping is declared in the 
corresponding
+    # Validate that the capability in substitution_mapping is declared in the 
corresponding
     # node template
     node_template = _get_node_template(context, presentation)
     if node_template is None:
@@ -105,22 +103,21 @@ def validate_substitution_mappings_capability(context, 
presentation):
 
     if node_template_capability is None:
         context.validation.report(
-            'substitution mapping capability "{0}" refers to an unknown '
-            'capability of node template "{1}": 
{mapped_capability_name}'.format(
+            u'substitution mapping capability "{0}" refers to an unknown '
+            u'capability of node template "{1}": 
{mapped_capability_name}'.format(
                 presentation._name, node_template._name,
                 mapped_capability_name=safe_repr(mapped_capability_name)),
             locator=presentation._locator, level=Issue.BETWEEN_TYPES)
         return
 
-    # validate that the capability type in substitution_mapping is derived 
from the capability type
+    # Validate that the capability type in substitution_mapping is derived 
from the capability type
     # in the corresponding node template
     substitution_type_capability_type = 
substitution_type_capability._get_type(context)
     node_template_capability_type = node_template_capability._get_type(context)
-
     if not substitution_type_capability_type._is_descendant(context, 
node_template_capability_type):
         context.validation.report(
-            'node template capability type "{0}" is not a descendant of 
substitution mapping '
-            'capability "{1}" of type "{2}"'.format(
+            u'node template capability type "{0}" is not a descendant of 
substitution mapping '
+            u'capability "{1}" of type "{2}"'.format(
                 node_template_capability_type._name,
                 presentation._name,
                 substitution_type_capability_type._name),
@@ -132,7 +129,9 @@ def validate_substitution_mappings_capability(context, 
presentation):
 #
 
 def _validate_mapping_format(presentation):
-    """Validate that the mapping is a list of 2 strings"""
+    """
+    Validate that the mapping is a list of 2 strings.
+    """
     if not isinstance(presentation._raw, list) or \
             len(presentation._raw) != 2 or \
             not isinstance(presentation._raw[0], basestring) or \
@@ -150,8 +149,8 @@ def _get_node_template(context, presentation):
 
 def _report_missing_node_template(context, presentation, field):
     context.validation.report(
-        'substitution mappings {field} "{node_template_mapping}" '
-        'refers to an unknown node template: {node_template_name}'.format(
+        u'substitution mappings {field} "{node_template_mapping}" '
+        u'refers to an unknown node template: {node_template_name}'.format(
             field=field,
             node_template_mapping=presentation._name,
             node_template_name=safe_repr(presentation._raw[0])),
@@ -160,7 +159,7 @@ def _report_missing_node_template(context, presentation, 
field):
 
 def _report_invalid_mapping_format(context, presentation, field):
     context.validation.report(
-        'substitution mapping {field} "{field_name}" is not a list of 2 
strings: {value}'.format(
+        u'substitution mapping {field} "{field_name}" is not a list of 2 
strings: {value}'.format(
             field=field,
             field_name=presentation._name,
             value=safe_repr(presentation._raw)),

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/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
index 0e3c94d..9fa056d 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/extensible.py
@@ -30,4 +30,4 @@ class ExtensiblePresentation(Presentation):
     @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
+        return extensions.get(name, default) if extensions is not None else 
None                    # pylint: disable=no-member

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
----------------------------------------------------------------------
diff --git 
a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py 
b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
index f14164a..9cd58e2 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py
@@ -14,10 +14,12 @@
 # limitations under the License.
 
 from aria.utils.formatting import safe_repr
+from aria.utils.type import full_type_name
 from aria.parser.exceptions import InvalidValueError
+from aria.parser.presentation import NULL
 
 
-def data_type_class_getter(cls):
+def data_type_class_getter(cls, allow_null=False):
     """
     Wraps the field value in a specialized data type class.
 
@@ -26,12 +28,14 @@ def data_type_class_getter(cls):
 
     def getter(field, presentation, context=None):
         raw = field.default_get(presentation, context)
-        if raw is not None:
-            try:
-                return cls(None, None, raw, None)
-            except ValueError as e:
-                raise InvalidValueError(
-                    '%s is not a valid "%s" in "%s": %s'
-                    % (field.full_name, field.full_cls_name, 
presentation._name, safe_repr(raw)),
-                    cause=e, locator=field.get_locator(raw))
+        if (raw is None) or (allow_null and (raw is NULL)):
+            return raw
+        try:
+            return cls(None, None, raw, None)
+        except ValueError as e:
+            raise InvalidValueError(
+                u'{0} is not a valid "{1}" in "{2}": {3}'
+                .format(field.full_name, full_type_name(cls), 
presentation._name,
+                        safe_repr(raw)),
+                cause=e, locator=field.get_locator(raw))
     return getter

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py
----------------------------------------------------------------------
diff --git 
a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py 
b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py
index e5853d8..2ff5143 100644
--- 
a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py
+++ 
b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py
@@ -52,8 +52,8 @@ def copy_validator(template_type_name, templates_dict_name):
             else:
                 if copy.copy is not None:
                     context.validation.report(
-                        '"copy" field refers to a %s that itself is a copy in 
"%s": %s'
-                        % (template_type_name, presentation._fullname, 
safe_repr(value)),
+                        u'"copy" field refers to a {0} that itself is a copy 
in "{1}": {2}'
+                        .format(template_type_name, presentation._fullname, 
safe_repr(value)),
                         locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
 
     return validator_fn
@@ -84,8 +84,8 @@ def data_type_validator(type_name='data type'):
             container_data_type = get_container_data_type(presentation)
             if (container_data_type is not None) and 
(container_data_type._name == value):
                 context.validation.report(
-                    'type of property "%s" creates a circular value hierarchy: 
%s'
-                    % (presentation._fullname, safe_repr(value)),
+                    u'type of property "{0}" creates a circular value 
hierarchy: {1}'
+                    .format(presentation._fullname, safe_repr(value)),
                     locator=presentation._get_child_locator('type'), 
level=Issue.BETWEEN_TYPES)
 
             # Can be a complex data type
@@ -135,14 +135,14 @@ def entry_schema_validator(field, presentation, context):
     if use_entry_schema:
         if value is None:
             context.validation.report(
-                '"entry_schema" does not have a value as required by data type 
"%s" in "%s"'
-                % (get_data_type_name(the_type), 
presentation._container._fullname),
+                u'"entry_schema" does not have a value as required by data 
type "{0}" in "{1}"'
+                .format(get_data_type_name(the_type), 
presentation._container._fullname),
                 locator=presentation._locator, level=Issue.BETWEEN_TYPES)
     else:
         if value is not None:
             context.validation.report(
-                '"entry_schema" has a value but it is not used by data type 
"%s" in "%s"'
-                % (get_data_type_name(the_type), 
presentation._container._fullname),
+                u'"entry_schema" has a value but it is not used by data type 
"{0}" in "{1}"'
+                .format(get_data_type_name(the_type), 
presentation._container._fullname),
                 locator=presentation._locator, level=Issue.BETWEEN_TYPES)
 
 
@@ -201,8 +201,8 @@ def data_type_constraints_validator(field, presentation, 
context):
     if value is not None:
         if presentation._get_primitive_ancestor(context) is None:
             context.validation.report(
-                'data type "%s" defines constraints but does not have a 
primitive ancestor'
-                % presentation._fullname,
+                u'data type "{0}" defines constraints but does not have a 
primitive ancestor'
+                .format(presentation._fullname),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.BETWEEN_TYPES)
 
 
@@ -220,8 +220,8 @@ def data_type_properties_validator(field, presentation, 
context):
     if values is not None:
         if presentation._get_primitive_ancestor(context) is not None:
             context.validation.report(
-                'data type "%s" defines properties even though it has a 
primitive ancestor'
-                % presentation._fullname,
+                u'data type "{0}" defines properties even though it has a 
primitive ancestor'
+                .format(presentation._fullname),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.BETWEEN_TYPES)
 
 
@@ -272,17 +272,18 @@ def constraint_clause_in_range_validator(field, 
presentation, context):
                 # Upper bound be coercible
                 upper = coerce_value(context, presentation, the_type, None, 
None, upper, field.name)
 
-                # Second "in_range" value must be greater than first
+                # Second "in_range" value must be greater or equal than first
                 if (lower is not None) and (upper is not None) and (lower >= 
upper):
                     context.validation.report(
-                        'upper bound of "in_range" constraint is not greater 
than the lower bound'
-                        ' in "%s": %s <= %s'
-                        % (presentation._container._fullname, 
safe_repr(lower), safe_repr(upper)),
+                        u'upper bound of "in_range" constraint is not greater 
than the lower bound'
+                        u' in "{0}": {1} <= {2}'
+                        .format(presentation._container._fullname, 
safe_repr(lower),
+                                safe_repr(upper)),
                         locator=presentation._locator, level=Issue.FIELD)
         else:
             context.validation.report(
-                'constraint "%s" is not a list of exactly 2 elements in "%s"'
-                % (field.name, presentation._fullname),
+                u'constraint "{0}" is not a list of exactly 2 elements in 
"{1}": {2}'
+                .format(field.name, presentation._fullname, safe_repr(values)),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.FIELD)
 
 
@@ -325,8 +326,8 @@ def constraint_clause_pattern_validator(field, 
presentation, context):
             re.compile(value)
         except re.error as e:
             context.validation.report(
-                'constraint "%s" is not a valid regular expression in "%s"'
-                % (field.name, presentation._fullname),
+                u'constraint "{0}" is not a valid regular expression in "{1}": 
{2}'
+                .format(field.name, presentation._fullname, safe_repr(value)),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.FIELD, exception=e)
 
 
@@ -379,21 +380,21 @@ def capability_definition_or_type_validator(field, 
presentation, context):
         if get_type_by_name(context, value, 'capability_types') is not None:
             if node is not None:
                 context.validation.report(
-                    '"%s" refers to a capability type even though "node" has a 
value in "%s"'
-                    % (presentation._name, presentation._container._fullname),
+                    u'"{0}" refers to a capability type even though "node" has 
a value in "{1}"'
+                    .format(presentation._name, 
presentation._container._fullname),
                     locator=presentation._get_child_locator(field.name), 
level=Issue.BETWEEN_FIELDS)
             return
 
         if node_variant == 'node_template':
             context.validation.report(
-                'requirement "%s" refers to an unknown capability definition 
name or capability'
-                ' type in "%s": %s'
-                % (presentation._name, presentation._container._fullname, 
safe_repr(value)),
+                u'requirement "{0}" refers to an unknown capability definition 
name or capability'
+                u' type in "{1}": {2}'
+                .format(presentation._name, presentation._container._fullname, 
safe_repr(value)),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.BETWEEN_TYPES)
         else:
             context.validation.report(
-                'requirement "%s" refers to an unknown capability type in 
"%s": %s'
-                % (presentation._name, presentation._container._fullname, 
safe_repr(value)),
+                u'requirement "{0}" refers to an unknown capability type in 
"{1}": {2}'
+                .format(presentation._name, presentation._container._fullname, 
safe_repr(value)),
                 locator=presentation._get_child_locator(field.name), 
level=Issue.BETWEEN_TYPES)
 
 
@@ -412,9 +413,9 @@ def node_filter_validator(field, presentation, context):
         _, node_type_variant = presentation._get_node(context)
         if node_type_variant != 'node_type':
             context.validation.report(
-                'requirement "%s" has a node filter even though "node" does 
not refer to a node'
-                ' type in "%s"'
-                % (presentation._fullname, presentation._container._fullname),
+                u'requirement "{0}" has a node filter even though "node" does 
not refer to a node'
+                u' type in "{1}"'
+                .format(presentation._fullname, 
presentation._container._fullname),
                 locator=presentation._locator, level=Issue.BETWEEN_FIELDS)
 
 
@@ -468,6 +469,54 @@ def list_node_type_or_group_type_validator(field, 
presentation, context):
 
 
 #
+# GroupTemplate
+#
+
+def group_members_validator(field, presentation, context):
+    """
+    Makes sure that the field's elements refer to node templates  and that 
they match the node types
+    declared in the group type.
+
+    Used with the :func:`field_validator` decorator for the ``targets`` field 
in
+    :class:`GroupTemplate`.
+    """
+
+    field.default_validate(presentation, context)
+
+    values = getattr(presentation, field.name)
+    if values is not None:
+        node_templates = \
+            context.presentation.get('service_template', 'topology_template', 
'node_templates') \
+                or {}
+        for value in values:
+            if value not in node_templates:
+                report_issue_for_unknown_type(context, presentation, 'node 
template', field.name,
+                                              value)
+
+            group_type = presentation._get_type(context)
+            if group_type is None:
+                break
+
+            node_types = group_type._get_members(context)
+
+            is_valid = False
+
+            if value in node_templates:
+                our_node_type = node_templates[value]._get_type(context)
+                for node_type in node_types:
+                    if node_type._is_descendant(context, our_node_type):
+                        is_valid = True
+                        break
+
+            if not is_valid:
+                context.validation.report(
+                    u'group definition target does not match a node type'
+                    u' declared in the group type in "{0}": {1}'
+                    .format(presentation._name, safe_repr(value)),
+                    locator=presentation._locator, level=Issue.BETWEEN_TYPES)
+
+
+#
 # PolicyTemplate
 #
 
@@ -484,13 +533,12 @@ def policy_targets_validator(field, presentation, 
context):
 
     values = getattr(presentation, field.name)
     if values is not None:
-        for value in values:
-            node_templates = \
-                context.presentation.get('service_template', 
'topology_template',
-                                         'node_templates') \
-                or {}
-            groups = context.presentation.get('service_template', 
'topology_template', 'groups') \
+        node_templates = \
+            context.presentation.get('service_template', 'topology_template', 
'node_templates') \
                 or {}
+        groups = context.presentation.get('service_template', 
'topology_template', 'groups') \
+            or {}
+        for value in values:
             if (value not in node_templates) and (value not in groups):
                 report_issue_for_unknown_type(context, presentation, 'node 
template or group',
                                               field.name, value)
@@ -519,9 +567,9 @@ def policy_targets_validator(field, presentation, context):
 
             if not is_valid:
                 context.validation.report(
-                    'policy definition target does not match either a node 
type or a group type'
-                    ' declared in the policy type in "%s": %s'
-                    % (presentation._name, safe_repr(value)),
+                    u'policy definition target does not match either a node 
type or a group type'
+                    u' declared in the policy type in "{0}": {1}'
+                    .format(presentation._name, safe_repr(value)),
                     locator=presentation._locator, level=Issue.BETWEEN_TYPES)
 
 
@@ -547,8 +595,8 @@ def node_filter_properties_validator(field, presentation, 
context):
             for name, _ in values:
                 if name not in properties:
                     context.validation.report(
-                        'node filter refers to an unknown property definition 
in "%s": %s'
-                        % (node_type._name, name),
+                        u'node filter refers to an unknown property definition 
in "{0}": {1}'
+                        .format(node_type._name, name),
                         locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
 
 
@@ -564,7 +612,7 @@ def node_filter_capabilities_validator(field, presentation, 
context):
     field.default_validate(presentation, context)
 
     values = getattr(presentation, field.name)
-    if values is not None: # pylint: disable=too-many-nested-blocks
+    if values is not None:                                                     
                     # pylint: disable=too-many-nested-blocks
         node_type = presentation._get_node_type(context)
         if node_type is not None:
             capabilities = node_type._get_capabilities(context)
@@ -577,12 +625,12 @@ def node_filter_capabilities_validator(field, 
presentation, context):
                         for property_name, _ in properties:
                             if property_name not in capability_properties:
                                 context.validation.report(
-                                    'node filter refers to an unknown 
capability definition'
-                                    ' property in "%s": %s'
-                                    % (node_type._name, property_name),
+                                    u'node filter refers to an unknown 
capability definition'
+                                    u' property in "{0}": {1}'
+                                    .format(node_type._name, property_name),
                                     locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
                 else:
                     context.validation.report(
-                        'node filter refers to an unknown capability 
definition in "%s": %s'
-                        % (node_type._name, name),
+                        u'node filter refers to an unknown capability 
definition in "{0}": {1}'
+                        .format(node_type._name, name),
                         locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py 
b/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py
index 5f9750e..f31b6c9 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 
-def convert_name_to_full_type_name(context, name, types_dict): # pylint: 
disable=unused-argument
+def convert_name_to_full_type_name(context, name, types_dict):                 
                     # pylint: disable=unused-argument
     """
     Converts a type name to its full type name, or else returns it unchanged.
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/presenter.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/presenter.py 
b/extensions/aria_extension_tosca/simple_v1_0/presenter.py
index 28c9f7b..e84decc 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/presenter.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/presenter.py
@@ -23,7 +23,7 @@ from .modeling.functions import (Concat, Token, GetInput, 
GetProperty, GetAttrib
 from .templates import ServiceTemplate
 
 
-class ToscaSimplePresenter1_0(Presenter): # pylint: 
disable=invalid-name,abstract-method
+class ToscaSimplePresenter1_0(Presenter):                                      
                     # pylint: disable=invalid-name,abstract-method
     """
     ARIA presenter for the `TOSCA Simple Profile v1.0 cos01 
<http://docs.oasis-open.org/tosca
     
/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html>`__.
@@ -70,7 +70,7 @@ class ToscaSimplePresenter1_0(Presenter): # pylint: 
disable=invalid-name,abstrac
     @cachedmethod
     def _get_import_locations(self, context):
         import_locations = []
-        if context.presentation.import_profile:
+        if context.presentation.configuration.get('tosca.import_profile', 
True):
             import_locations.append(self.SIMPLE_PROFILE_LOCATION)
         imports = self._get('service_template', 'imports')
         if imports:
@@ -78,5 +78,5 @@ class ToscaSimplePresenter1_0(Presenter): # pylint: 
disable=invalid-name,abstrac
         return FrozenList(import_locations) if import_locations else 
EMPTY_READ_ONLY_LIST
 
     @cachedmethod
-    def _get_model(self, context): # pylint: disable=no-self-use
+    def _get_model(self, context):                                             
                     # pylint: disable=no-self-use
         return create_service_template_model(context)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/templates.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/templates.py 
b/extensions/aria_extension_tosca/simple_v1_0/templates.py
index 3c36bb8..d4d012e 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/templates.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/templates.py
@@ -19,11 +19,11 @@ from aria.parser import implements_specification
 from aria.parser.presentation import (has_fields, primitive_field, 
primitive_list_field,
                                       object_field, object_list_field, 
object_dict_field,
                                       object_sequenced_list_field, 
field_validator,
-                                      type_validator, list_type_validator)
+                                      type_validator)
 
 from .assignments import (PropertyAssignment, AttributeAssignment, 
RequirementAssignment,
                           CapabilityAssignment, InterfaceAssignment, 
ArtifactAssignment)
-from .definitions import ParameterDefinition
+from .definitions import (InputDefinition, OutputDefinition)
 from .filters import NodeFilter
 from .misc import (Description, MetaData, Repository, Import, 
SubstitutionMappings)
 from .modeling.parameters import (get_assigned_and_defined_parameter_values, 
get_parameter_values)
@@ -34,7 +34,8 @@ from .modeling.artifacts import 
get_inherited_artifact_definitions
 from .modeling.policies import get_policy_targets
 from .modeling.copy import get_default_raw_from_copy
 from .presentation.extensible import ExtensiblePresentation
-from .presentation.field_validators import copy_validator, 
policy_targets_validator
+from .presentation.field_validators import (copy_validator, 
group_members_validator,
+                                            policy_targets_validator)
 from .presentation.types import (convert_name_to_full_type_name, 
get_type_by_name)
 from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, 
RelationshipType,
                     NodeType, GroupType, PolicyType)
@@ -182,6 +183,7 @@ class NodeTemplate(ExtensiblePresentation):
     def _validate(self, context):
         super(NodeTemplate, self)._validate(context)
         self._get_property_values(context)
+        self._get_attribute_default_values(context)
         self._get_requirements(context)
         self._get_capabilities(context)
         self._get_interfaces(context)
@@ -284,12 +286,17 @@ class RelationshipTemplate(ExtensiblePresentation):
         return FrozenDict(get_assigned_and_defined_parameter_values(context, 
self, 'property'))
 
     @cachedmethod
+    def _get_attribute_default_values(self, context):
+        return FrozenDict(get_assigned_and_defined_parameter_values(context, 
self, 'attribute'))
+
+    @cachedmethod
     def _get_interfaces(self, context):
         return FrozenDict(get_template_interfaces(context, self, 'relationship 
template'))
 
     def _validate(self, context):
         super(RelationshipTemplate, self)._validate(context)
         self._get_property_values(context)
+        self._get_attribute_default_values(context)
         self._get_interfaces(context)
 
     def _dump(self, context):
@@ -340,7 +347,7 @@ class GroupTemplate(ExtensiblePresentation):
         :type: {:obj:`basestring`: :class:`PropertyAssignment`}
         """
 
-    @field_validator(list_type_validator('node template', 'topology_template', 
'node_templates'))
+    @field_validator(group_members_validator)
     @primitive_list_field(str)
     def members(self):
         """
@@ -464,13 +471,13 @@ class TopologyTemplate(ExtensiblePresentation):
         :type: :class:`Description`
         """
 
-    @object_dict_field(ParameterDefinition)
+    @object_dict_field(InputDefinition)
     def inputs(self):
         """
         An optional list of input parameters (i.e., as parameter definitions) 
for the Topology
         Template.
 
-        :type: {:obj:`basestring`: :class:`ParameterDefinition`}
+        :type: {:obj:`basestring`: :class:`InputDefinition`}
         """
 
     @object_dict_field(NodeTemplate)
@@ -506,13 +513,13 @@ class TopologyTemplate(ExtensiblePresentation):
         :type: {:obj:`basestring`: :class:`PolicyTemplate`}
         """
 
-    @object_dict_field(ParameterDefinition)
+    @object_dict_field(OutputDefinition)
     def outputs(self):
         """
         An optional list of output parameters (i.e., as parameter definitions) 
for the Topology
         Template.
 
-        :type: {:obj:`basestring`: :class:`ParameterDefinition`}
+        :type: {:obj:`basestring`: :class:`OutputDefinition`}
         """
 
     @object_field(SubstitutionMappings)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/types.py 
b/extensions/aria_extension_tosca/simple_v1_0/types.py
index 43af44b..8ab7b07 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/types.py
@@ -34,6 +34,7 @@ from .modeling.capabilities import 
(get_inherited_valid_source_types,
 from .modeling.data_types import (get_data_type, get_inherited_constraints, 
coerce_data_type_value,
                                   validate_data_type_name)
 from .modeling.interfaces import (get_inherited_interface_definitions, 
get_inherited_operations)
+from .modeling.groups import get_inherited_members
 from .modeling.policies import get_inherited_targets
 from .modeling.parameters import get_inherited_parameter_definitions
 from .modeling.requirements import get_inherited_requirement_definitions
@@ -70,7 +71,7 @@ class ArtifactType(ExtensiblePresentation):
         """
 
     @field_getter(data_type_class_getter(Version))
-    @primitive_field()
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Artifact Type definition.
@@ -153,7 +154,8 @@ class DataType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Data Type definition.
@@ -210,7 +212,7 @@ class DataType(ExtensiblePresentation):
             if not isinstance(parent, DataType):
                 return parent
             else:
-                return parent._get_primitive_ancestor(context) # pylint: 
disable=no-member
+                return parent._get_primitive_ancestor(context)                 
                     # pylint: disable=no-member
         return None
 
     @cachedmethod
@@ -261,7 +263,8 @@ class CapabilityType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Capability Type definition.
@@ -312,7 +315,9 @@ class CapabilityType(ExtensiblePresentation):
 
     @cachedmethod
     def _is_descendant(self, context, other_type):
-        """returns True iff `other_type` is a descendant of the represented 
capability type"""
+        """
+        Checks if ``other_type`` is our descendant (or equal to us).
+        """
         if other_type is None:
             return False
         elif other_type._name == self._name:
@@ -324,12 +329,17 @@ class CapabilityType(ExtensiblePresentation):
         return FrozenDict(get_inherited_parameter_definitions(context, self, 
'properties'))
 
     @cachedmethod
+    def _get_attributes(self, context):
+        return FrozenDict(get_inherited_parameter_definitions(context, self, 
'attributes'))
+
+    @cachedmethod
     def _get_valid_source_types(self, context):
         return get_inherited_valid_source_types(context, self)
 
     def _validate(self, context):
         super(CapabilityType, self)._validate(context)
         self._get_properties(context)
+        self._get_attributes(context)
 
     def _dump(self, context):
         self._dump_content(context, (
@@ -363,7 +373,8 @@ class InterfaceType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Interface Type definition.
@@ -417,8 +428,7 @@ class InterfaceType(ExtensiblePresentation):
     def _validate(self, context):
         super(InterfaceType, self)._validate(context)
         self._get_inputs(context)
-        for operation in self.operations.itervalues(): # pylint: 
disable=no-member
-            operation._validate(context)
+        self._get_operations(context)
 
     def _dump(self, context):
         self._dump_content(context, (
@@ -450,7 +460,8 @@ class RelationshipType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Relationship Type definition.
@@ -508,6 +519,9 @@ class RelationshipType(ExtensiblePresentation):
 
     @cachedmethod
     def _is_descendant(self, context, the_type):
+        """
+        Checks if ``other_type`` is our descendant (or equal to us).
+        """
         if the_type is None:
             return False
         elif the_type._name == self._name:
@@ -565,7 +579,8 @@ class NodeType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Node Type definition.
@@ -639,6 +654,9 @@ class NodeType(ExtensiblePresentation):
 
     @cachedmethod
     def _is_descendant(self, context, the_type):
+        """
+        Checks if ``other_type`` is our descendant (or equal to us).
+        """
         if the_type is None:
             return False
         elif the_type._name == self._name:
@@ -721,7 +739,8 @@ class GroupType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Group Type definition.
@@ -775,6 +794,9 @@ class GroupType(ExtensiblePresentation):
 
     @cachedmethod
     def _is_descendant(self, context, the_type):
+        """
+        Checks if ``other_type`` is our descendant (or equal to us).
+        """
         if the_type is None:
             return False
         elif the_type._name == self._name:
@@ -786,6 +808,11 @@ class GroupType(ExtensiblePresentation):
         return FrozenDict(get_inherited_parameter_definitions(context, self, 
'properties'))
 
     @cachedmethod
+    def _get_members(self, context):
+        node_types = get_inherited_members(context, self)
+        return FrozenList(node_types)
+
+    @cachedmethod
     def _get_interfaces(self, context):
         return FrozenDict(get_inherited_interface_definitions(context, self, 
'group type'))
 
@@ -827,7 +854,8 @@ class PolicyType(ExtensiblePresentation):
         :type: :obj:`basestring`
         """
 
-    @object_field(Version)
+    @field_getter(data_type_class_getter(Version))
+    @primitive_field(str)
     def version(self):
         """
         An optional version for the Policy Type definition.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/requirements.in
----------------------------------------------------------------------
diff --git a/requirements.in b/requirements.in
index c5bfc78..f71a1ee 100644
--- a/requirements.in
+++ b/requirements.in
@@ -17,7 +17,7 @@ backports.shutil_get_terminal_size>=1, <2
 blinker>=1.4, <1.5
 bottle>=0.12, <0.13
 CacheControl[filecache]>=0.11.0, <0.13
-click>=6, < 7
+click>=6, <7
 click_didyoumean>=0.0.3, <0.1
 colorama>=0.3, <=0.4
 Jinja2>=2.9, <3.0

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 2af8fe3..bbbe97b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,15 +7,15 @@
 backports.shutil-get-terminal-size==1.0.0
 blinker==1.4
 bottle==0.12.13
-cachecontrol[filecache]==0.12.1
+cachecontrol[filecache]==0.12.3
 click-didyoumean==0.0.3
 click==6.7
 colorama==0.3.9
 decorator==4.1.2          # via networkx
 jinja2==2.9.6
-jsonpickle==0.9.4
+jsonpickle==0.9.5
 lockfile==0.12.2          # via cachecontrol
-logutils==0.3.4.1
+logutils==0.3.5
 markupsafe==1.0           # via jinja2
 msgpack-python==0.4.8     # via cachecontrol
 networkx==2.0
@@ -23,12 +23,12 @@ prettytable==0.7.2
 psutil==5.4.0
 requests==2.13.0
 retrying==1.3.3
-ruamel.ordereddict==0.4.9  # via ruamel.yaml
+ruamel.ordereddict==0.4.13  # via ruamel.yaml
 ruamel.yaml==0.15.34
 shortuuid==0.5.0
-six==1.10.0               # via retrying
-sqlalchemy==1.1.6
-wagon==0.6.0
+six==1.11.0               # via retrying
+sqlalchemy==1.1.14
+wagon==0.6.1
 wheel==0.29.0             # via wagon
 
 # The following packages are considered to be unsafe in a requirements file:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/setup.py
----------------------------------------------------------------------
diff --git a/setup.py b/setup.py
index 8483c5b..c833da8 100644
--- a/setup.py
+++ b/setup.py
@@ -60,7 +60,7 @@ extras_require = {
 
 with open(os.path.join(root_dir, 'requirements.in')) as requirements:
     for requirement in requirements.readlines():
-        requirement = requirement.split('#')[0].strip() # Get rid of comments 
or trailing comments
+        requirement = requirement.split('#', 1)[0].strip() # Remove comments
         if not requirement:
             continue # Skip empty and comment lines
 
@@ -70,7 +70,7 @@ with open(os.path.join(root_dir, 'requirements.in')) as 
requirements:
         # 
https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies
         # https://hynek.me/articles/conditional-python-dependencies/
         if ';' in requirement:
-            package, condition = requirement.split(';')
+            package, condition = requirement.split(';', 1)
             cond_name = ':{0}'.format(condition.strip())
             extras_require.setdefault(cond_name, [])
             extras_require[cond_name].append(package.strip())

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/end2end/test_hello_world.py
----------------------------------------------------------------------
diff --git a/tests/end2end/test_hello_world.py 
b/tests/end2end/test_hello_world.py
index 094ffc3..eeb1781 100644
--- a/tests/end2end/test_hello_world.py
+++ b/tests/end2end/test_hello_world.py
@@ -55,7 +55,7 @@ def _verify_deployed_service_in_storage(service_name, 
model_storage):
     service = service_templates[0].services[service_name]
     assert service.name == service_name
     assert len(service.executions) == 1
-    assert len(service.nodes) == 2
+    assert len(service.nodes) == 1
     assert service.outputs['port'].value == 9090
     assert all(node.state == node.STARTED for node in 
service.nodes.itervalues())
     assert len(service.executions[0].logs) > 0

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/__init__.py b/tests/extensions/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/__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/89b9f130/tests/extensions/aria_extension_tosca/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/__init__.py 
b/tests/extensions/aria_extension_tosca/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/__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/89b9f130/tests/extensions/aria_extension_tosca/aria_v1_0/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/aria_v1_0/__init__.py 
b/tests/extensions/aria_extension_tosca/aria_v1_0/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/aria_v1_0/__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/89b9f130/tests/extensions/aria_extension_tosca/aria_v1_0/test_profile.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/aria_v1_0/test_profile.py 
b/tests/extensions/aria_extension_tosca/aria_v1_0/test_profile.py
new file mode 100644
index 0000000..14a2e8a
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/aria_v1_0/test_profile.py
@@ -0,0 +1,22 @@
+# 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.
+
+
+def test_profile(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+  - aria-1.0
+""", import_profile=True, validate_normative=True).assert_success()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/aria_extension_tosca/conftest.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/conftest.py 
b/tests/extensions/aria_extension_tosca/conftest.py
new file mode 100644
index 0000000..a2020b7
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/conftest.py
@@ -0,0 +1,45 @@
+# 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.
+
+"""
+PyTest configuration module.
+
+Add support for a "--tosca-parser" CLI option.
+"""
+
+import pytest
+
+from ...mechanisms.parsing.aria import AriaParser
+
+
+def pytest_addoption(parser):
+    parser.addoption('--tosca-parser', action='store', default='aria', 
help='TOSCA parser')
+
+
+def pytest_report_header(config):
+    tosca_parser = config.getoption('--tosca-parser')
+    return 'tosca-parser: {0}'.format(tosca_parser)
+
+
+@pytest.fixture(scope='session')
+def parser(request):
+    tosca_parser = request.config.getoption('--tosca-parser')
+    verbose = request.config.getoption('verbose') > 0
+    if tosca_parser == 'aria':
+        with AriaParser() as p:
+            p.verbose = verbose
+            yield p
+    else:
+        pytest.fail('configured tosca-parser not supported: 
{0}'.format(tosca_parser))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py 
b/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/__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/89b9f130/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/test_profile.py
----------------------------------------------------------------------
diff --git 
a/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/test_profile.py 
b/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/test_profile.py
new file mode 100644
index 0000000..fb756bc
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_nfv_v1_0/test_profile.py
@@ -0,0 +1,20 @@
+# 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.
+
+
+def test_profile(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0
+""", import_profile=True, validate_normative=True).assert_success()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py 
b/tests/extensions/aria_extension_tosca/simple_v1_0/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/__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/89b9f130/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
----------------------------------------------------------------------
diff --git a/tests/extensions/aria_extension_tosca/simple_v1_0/data.py 
b/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
new file mode 100644
index 0000000..104e6bb
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/data.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# 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.
+
+
+# Keywords
+
+TYPE_NAME_PLURAL = {
+    'artifact': 'artifacts',
+    'data': 'datatypes',
+    'capability': 'capabilities',
+    'interface': 'interfaces',
+    'relationship': 'relationships',
+    'node': 'nodes',
+    'group': 'groups',
+    'policy': 'policies'
+}
+TEMPLATE_NAME_SECTIONS = {
+    'node': 'node_templates',
+    'group': 'groups',
+    'relationship': 'relationship_templates',
+    'policy': 'policies'
+}
+PRIMITIVE_TYPE_NAMES = ('string', 'integer', 'float', 'boolean')
+PARAMETER_TYPE_NAMES = PRIMITIVE_TYPE_NAMES + ('MyType',)
+CONSTRAINTS_WITH_VALUE = ('equal', 'greater_than', 'greater_or_equal', 
'less_than', 'less_or_equal')
+CONSTRAINTS_WITH_VALUE_LIST = ('valid_values',)
+CONSTRAINTS_WITH_VALUE_RANGE = ('in_range',)
+CONSTRAINTS_WITH_VALUE_NON_NEGATIVE_INT = ('length', 'min_length', 
'max_length')
+
+
+# Values
+
+PRIMITIVE_VALUES = ('null', 'true', 'a string', '123', '0.123', '[]', '{}')
+NOT_A_DICT = ('null', 'true', 'a string', '123', '0.123', '[]')
+NOT_A_DICT_WITH_ONE_KEY = NOT_A_DICT + ('{}', '{k1: v1, k2: v2}',)
+NOT_A_DICT_OR_STRING = ('null', 'true', '123', '0.123', '[]')
+NOT_A_LIST = ('null', 'true', 'a string', '123', '0.123', '{}')
+NOT_A_LIST_OF_TWO = NOT_A_LIST + ('[]', '[a]', '[a, b, c]')
+NOT_A_STRING = ('null', 'true', '123', '0.123', '[]', '{}')
+NOT_A_BOOL = ('null', 'a string', '123', '0.123', '[]', '{}')
+NOT_A_RANGE = NOT_A_LIST + (
+    '[]', '[ 1 ]', '[ 1, 2, 3 ]',
+    '[ 1, 1 ]', '[ 2, 1 ]',
+    '[ 1, a string ]', '[ a string, 1 ]',
+    '[ 1.5, 2 ]', '[ 1, 2.5 ]'
+)
+OCCURRENCES = ('[ 0, 1 ]', '[ 10, UNBOUNDED ]')
+BAD_OCCURRENCES = NOT_A_RANGE + ('[ -1, 1 ]', '[ 0, unbounded ]')
+GOOD_VERSIONS = ("'6.1'", '2.0.1', '3.1.0.beta', "'1.0.0.alpha-10'")
+BAD_VERSIONS = ('a_string', '1.2.3.4.5', '1.2.beta', '1.0.0.alpha-x')
+STATUSES = ('supported', 'unsupported', 'experimental', 'deprecated')
+PARAMETER_VALUES = (
+    ('string', 'a string'),
+    ('integer', '1'),
+    ('float', '1.1'),
+    ('MyType', '{my_field: a string}')
+)
+ENTRY_SCHEMA_VALUES = (
+    ('string', 'a string', 'another string'),
+    ('integer', '1', '2'),
+    ('float', '1.1', '2.2'),
+    ('MyType', '{my_field: a string}', '{}')
+)
+ENTRY_SCHEMA_VALUES_BAD = (
+    ('string', 'a string', '1'),
+    ('integer', '1', 'a string'),
+    ('float', '1.1', 'a string'),
+    ('MyType', '{my_field: a string}', 'a string')
+)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/aria_extension_tosca/simple_v1_0/functions/__init__.py
----------------------------------------------------------------------
diff --git 
a/tests/extensions/aria_extension_tosca/simple_v1_0/functions/__init__.py 
b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/__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/89b9f130/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_concat.py
----------------------------------------------------------------------
diff --git 
a/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_concat.py
 
b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_concat.py
new file mode 100644
index 0000000..23a274a
--- /dev/null
+++ 
b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_concat.py
@@ -0,0 +1,102 @@
+    # -*- coding: utf-8 -*-
+# 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.
+
+
+def test_functions_concat_syntax_empty(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { concat: [] }
+""").assert_success()
+
+
+def test_functions_concat_strings(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { concat: [ a, b, c ] }
+""").assert_success()
+
+
+def test_functions_concat_mixed(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { concat: [ a, 1, 1.1, null, [], {} ] }
+""").assert_success()
+
+
+def test_functions_concat_nested(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { concat: [ a, { concat: [ b, c ] } ] }
+""").assert_success()
+
+
+# Unicode
+
+def test_functions_concat_unicode(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  類型:
+    properties:
+      參數:
+        type: string
+topology_template:
+  node_templates:
+    模板:
+      type: 類型
+      properties:
+        參數: { concat: [ 一, 二, 三 ] }
+""").assert_success()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_get_artifact.py
----------------------------------------------------------------------
diff --git 
a/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_get_artifact.py
 
b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_get_artifact.py
new file mode 100644
index 0000000..6fa1a3c
--- /dev/null
+++ 
b/tests/extensions/aria_extension_tosca/simple_v1_0/functions/test_function_get_artifact.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# 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 pytest
+
+
+# Syntax
+
+def test_functions_get_artifact_syntax_empty(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { get_artifact: [] } # needs at least two args
+""").assert_failure()
+
+
+# Arguments
+
+def test_functions_get_artifact_2_arguments(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+artifact_types:
+  MyType: {}
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+    artifacts:
+      my_artifact:
+        type: MyType
+        file: filename
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { get_artifact: [ my_node, my_artifact ] }
+""").assert_success()
+
+
+@pytest.mark.xfail(reason='not yet implemented')
+def test_functions_get_artifact_unknown(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+artifact_types:
+  MyType: {}
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+    artifacts:
+      my_artifact:
+        type: MyType
+        file: filename
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { get_artifact: [ unknown, my_artifact ] }
+""").assert_failure()
+
+
+def test_functions_get_artifact_3_arguments(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+artifact_types:
+  MyType: {}
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+    artifacts:
+      my_artifact:
+        type: MyType
+        file: filename
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { get_artifact: [ my_node, my_artifact, path ] }
+""").assert_success()
+
+
+def test_functions_get_artifact_4_arguments(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+artifact_types:
+  MyType: {}
+node_types:
+  MyType:
+    properties:
+      my_parameter:
+        type: string
+    artifacts:
+      my_artifact:
+        type: MyType
+        file: filename
+topology_template:
+  node_templates:
+    my_node:
+      type: MyType
+      properties:
+        my_parameter: { get_artifact: [ my_node, my_artifact, path, true ] }
+""").assert_success()
+
+
+# Unicode
+
+def test_functions_get_artifact_unicode(parser):
+    parser.parse_literal("""
+tosca_definitions_version: tosca_simple_yaml_1_0
+artifact_types:
+  類型: {}
+node_types:
+  類型:
+    properties:
+      參數:
+        type: string
+    artifacts:
+      神器:
+        type: 類型
+        file: 文件名
+topology_template:
+  node_templates:
+    模板:
+      type: 類型
+      properties:
+        參數: { get_artifact: [ 模板, 神器, 路徑, true ] }
+""").assert_success()


Reply via email to