http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/data_types.py 
b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
index 216f1e4..b85caa1 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
@@ -37,13 +37,13 @@ class Timezone(tzinfo):
         super(Timezone, self).__init__()
         self._offset = timedelta(hours=hours, minutes=minutes)
 
-    def utcoffset(self, dt): # pylint: disable=unused-argument
+    def utcoffset(self, dt):                                                   
                     # pylint: disable=unused-argument
         return self._offset
 
-    def tzname(self, dt): # pylint: disable=unused-argument
-        return str(self._offset)
+    def tzname(self, dt):                                                      
                     # pylint: disable=unused-argument
+        return unicode(self._offset)
 
-    def dst(self, dt): # pylint: disable=unused-argument
+    def dst(self, dt):                                                         
                     # pylint: disable=unused-argument
         return Timezone._ZERO
 
     _ZERO = timedelta(0)
@@ -74,8 +74,8 @@ class Timestamp(object):
         r'(([ 
\t]*)Z|(?P<tzhour>[-+][0-9][0-9])?(:(?P<tzminute>[0-9][0-9])?)?)?$'
     CANONICAL = '%Y-%m-%dT%H:%M:%S'
 
-    def __init__(self, entry_schema, constraints, value, aspect): # pylint: 
disable=unused-argument
-        value = str(value)
+    def __init__(self, entry_schema, constraints, value, aspect):              
                     # pylint: disable=unused-argument
+        value = unicode(value)
         match = re.match(Timestamp.REGULAR_SHORT, value)
         if match is not None:
             # Parse short form
@@ -116,8 +116,8 @@ class Timestamp(object):
                                       Timezone(tzhour, tzminute))
             else:
                 raise ValueError(
-                    'timestamp must be formatted as YAML ISO8601 variant or 
"YYYY-MM-DD": %s'
-                    % safe_repr(value))
+                    u'timestamp must be formatted as YAML ISO8601 variant or 
"YYYY-MM-DD": {0}'
+                    .format(safe_repr(value)))
 
     @property
     def as_datetime_utc(self):
@@ -129,8 +129,8 @@ class Timestamp(object):
 
     def __str__(self):
         the_datetime = self.as_datetime_utc
-        return '%s%sZ' \
-            % (the_datetime.strftime(Timestamp.CANONICAL), 
Timestamp._fraction_as_str(the_datetime))
+        return u'{0}{1}Z'.format(the_datetime.strftime(Timestamp.CANONICAL),
+                                 Timestamp._fraction_as_str(the_datetime))
 
     def __repr__(self):
         return repr(self.__str__())
@@ -145,7 +145,7 @@ class Timestamp(object):
 
     @staticmethod
     def _fraction_as_str(the_datetime):
-        return '{0:g}'.format(the_datetime.microsecond / 1000000.0).lstrip('0')
+        return u'{0:g}'.format(the_datetime.microsecond / 
1000000.0).lstrip('0')
 
 
 @total_ordering
@@ -165,7 +165,7 @@ class Version(object):
 
     REGEX = \
         r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<fix>\d+)' + \
-        r'((\.(?P<qualifier>\d+))(\-(?P<build>\d+))?)?)?$'
+        r'((\.(?P<qualifier>\w+))(\-(?P<build>\d+))?)?)?$'
 
     @staticmethod
     def key(version):
@@ -174,14 +174,13 @@ class Version(object):
         """
         return (version.major, version.minor, version.fix, version.qualifier, 
version.build)
 
-    def __init__(self, entry_schema, constraints, value, aspect): # pylint: 
disable=unused-argument
-        str_value = str(value)
-        match = re.match(Version.REGEX, str_value)
+    def __init__(self, entry_schema, constraints, value, aspect):              
                     # pylint: disable=unused-argument
+        str_value = unicode(value)
+        match = re.match(Version.REGEX, str_value, flags=re.UNICODE)
         if match is None:
             raise ValueError(
-                'version must be formatted as <major_version>.<minor_version>'
-                '[.<fix_version>[.<qualifier>[-<build_version]]]: %s'
-                % safe_repr(value))
+                u'version must be formatted as <major_version>.<minor_version>'
+                u'[.<fix_version>[.<qualifier>[-<build_version]]]: 
{0}'.format(safe_repr(value)))
 
         self.value = str_value
 
@@ -193,8 +192,6 @@ class Version(object):
         if self.fix is not None:
             self.fix = int(self.fix)
         self.qualifier = match.group('qualifier')
-        if self.qualifier is not None:
-            self.qualifier = int(self.qualifier)
         self.build = match.group('build')
         if self.build is not None:
             self.build = int(self.build)
@@ -215,6 +212,7 @@ class Version(object):
         return (self.major, self.minor, self.fix, self.qualifier, self.build) 
== \
             (version.major, version.minor, version.fix, version.qualifier, 
version.build)
 
+    @implements_specification('3.2.2.1', 'tosca-simple-1.0')
     def __lt__(self, version):
         if self.major < version.major:
             return True
@@ -225,9 +223,7 @@ class Version(object):
                 if self.fix < version.fix:
                     return True
                 elif self.fix == version.fix:
-                    if self.qualifier < version.qualifier:
-                        return True
-                    elif self.qualifier == version.qualifier:
+                    if self.qualifier == version.qualifier:
                         if self.build < version.build:
                             return True
         return False
@@ -244,28 +240,29 @@ class Range(object):
     #TYPE_TOSCA_RANGE>`__
     """
 
-    def __init__(self, entry_schema, constraints, value, aspect): # pylint: 
disable=unused-argument
+    def __init__(self, entry_schema, constraints, value, aspect):              
                     # pylint: disable=unused-argument
         if not isinstance(value, list):
-            raise ValueError('range value is not a list: %s' % 
safe_repr(value))
+            raise ValueError(u'range value is not a list: 
{0}'.format(safe_repr(value)))
         if len(value) != 2:
-            raise ValueError('range value does not have exactly 2 elements: 
%s' % safe_repr(value))
+            raise ValueError(u'range value does not have exactly 2 elements: 
{0}'
+                             .format(safe_repr(value)))
 
         def is_int(v):
             return isinstance(v, int) and (not isinstance(v, bool)) # In 
Python bool is an int
 
         if not is_int(value[0]):
-            raise ValueError('lower bound of range is not a valid integer: %s'
-                             % safe_repr(value[0]))
+            raise ValueError(u'lower bound of range is not a valid integer: 
{0}'
+                             .format(safe_repr(value[0])))
 
         if value[1] != 'UNBOUNDED':
             if not is_int(value[1]):
-                raise ValueError('upper bound of range is not a valid integer 
or "UNBOUNDED": %s'
-                                 % safe_repr(value[0]))
+                raise ValueError(u'upper bound of range is not a valid integer 
or "UNBOUNDED": {0}'
+                                 .format(safe_repr(value[0])))
 
             if value[0] >= value[1]:
                 raise ValueError(
-                    'upper bound of range is not greater than the lower bound: 
%s >= %s'
-                    % (safe_repr(value[0]), safe_repr(value[1])))
+                    u'upper bound of range is not greater than the lower 
bound: {0} >= {1}'
+                    .format(safe_repr(value[0]), safe_repr(value[1])))
 
         self.value = value
 
@@ -294,9 +291,9 @@ class List(list):
     """
 
     @staticmethod
-    def _create(context, presentation, entry_schema, constraints, value, 
aspect): # pylint: disable=unused-argument
+    def _create(context, presentation, entry_schema, constraints, value, 
aspect):                   # pylint: disable=unused-argument
         if not isinstance(value, list):
-            raise ValueError('"list" data type value is not a list: %s' % 
safe_repr(value))
+            raise ValueError(u'"list" data type value is not a list: 
{0}'.format(safe_repr(value)))
 
         entry_schema_type = entry_schema._get_type(context)
         entry_schema_constraints = entry_schema.constraints
@@ -328,12 +325,12 @@ class Map(StrictDict):
     """
 
     @staticmethod
-    def _create(context, presentation, entry_schema, constraints, value, 
aspect): # pylint: disable=unused-argument
+    def _create(context, presentation, entry_schema, constraints, value, 
aspect):                   # pylint: disable=unused-argument
         if not isinstance(value, dict):
-            raise ValueError('"map" data type value is not a dict: %s' % 
safe_repr(value))
+            raise ValueError(u'"map" data type value is not a dict: 
{0}'.format(safe_repr(value)))
 
         if entry_schema is None:
-            raise ValueError('"map" data type does not define "entry_schema"')
+            raise ValueError(u'"map" data type does not define "entry_schema"')
 
         entry_schema_type = entry_schema._get_type(context)
         entry_schema_constraints = entry_schema.constraints
@@ -348,7 +345,7 @@ class Map(StrictDict):
         return the_map
 
     def __init__(self, items=None):
-        super(Map, self).__init__(items, key_class=str)
+        super(Map, self).__init__(items, key_class=basestring)
 
     # Can't define as property because it's old-style Python class
     def as_raw(self):
@@ -374,29 +371,31 @@ class Scalar(object):
         """
         return scalar.value
 
-    def __init__(self, entry_schema, constraints, value, aspect): # pylint: 
disable=unused-argument
-        str_value = str(value)
-        match = re.match(self.REGEX, str_value) # pylint: disable=no-member
+    def __init__(self, entry_schema, constraints, value, aspect):              
                     # pylint: disable=unused-argument
+        str_value = unicode(value)
+        match = re.match(self.REGEX, str_value, flags=re.UNICODE)              
                     # pylint: disable=no-member
         if match is None:
-            raise ValueError('scalar must be formatted as <scalar> <unit>: %s' 
% safe_repr(value))
+            raise ValueError(u'scalar must be formatted as <scalar> <unit>: 
{0}'
+                             .format(safe_repr(value)))
 
         self.factor = float(match.group('scalar'))
         if self.factor < 0:
-            raise ValueError('scalar is negative: %s' % safe_repr(self.factor))
+            raise ValueError('scalar is negative: 
{0}'.format(safe_repr(self.factor)))
 
         self.unit = match.group('unit')
 
         unit_lower = self.unit.lower()
         unit_size = None
-        for k, v in self.UNITS.iteritems(): # pylint: disable=no-member
+        for k, v in self.UNITS.iteritems():                                    
                     # pylint: disable=no-member
             if k.lower() == unit_lower:
                 self.unit = k
                 unit_size = v
                 break
         if unit_size is None:
-            raise ValueError('scalar specified with unsupported unit: %s' % 
safe_repr(self.unit))
+            raise ValueError(u'scalar specified with unsupported unit: {0}'
+                             .format(safe_repr(self.unit)))
 
-        self.value = self.TYPE(self.factor * unit_size) # pylint: 
disable=no-member
+        self.value = self.TYPE(self.factor * unit_size)                        
                     # pylint: disable=no-member
 
     @property
     def as_raw(self):
@@ -404,10 +403,10 @@ class Scalar(object):
             ('value', self.value),
             ('factor', self.factor),
             ('unit', self.unit),
-            ('unit_size', self.UNITS[self.unit]))) # pylint: disable=no-member
+            ('unit_size', self.UNITS[self.unit])))                             
                     # pylint: disable=no-member
 
     def __str__(self):
-        return '%s %s' % (self.value, self.UNIT) # pylint: disable=no-member
+        return u'{0} {1}'.format(self.value, self.UNIT)                        
                     # pylint: disable=no-member
 
     def __repr__(self):
         return repr(self.__str__())
@@ -416,14 +415,14 @@ class Scalar(object):
         if isinstance(scalar, Scalar):
             value = scalar.value
         else:
-            value = self.TYPE(scalar) # pylint: disable=no-member
+            value = self.TYPE(scalar)                                          
                     # pylint: disable=no-member
         return self.value == value
 
     def __lt__(self, scalar):
         if isinstance(scalar, Scalar):
             value = scalar.value
         else:
-            value = self.TYPE(scalar) # pylint: disable=no-member
+            value = self.TYPE(scalar)                                          
                     # pylint: disable=no-member
         return self.value < value
 
 
@@ -509,12 +508,12 @@ class ScalarFrequency(Scalar):
 # The following are hooked in the YAML as 'coerce_value' extensions
 #
 
-def coerce_timestamp(context, presentation, the_type, entry_schema, 
constraints, value, aspect): # pylint: disable=unused-argument
+def coerce_timestamp(context, presentation, the_type, entry_schema, 
constraints, value, aspect):    # pylint: disable=unused-argument
     return coerce_to_data_type_class(context, presentation, Timestamp, 
entry_schema, constraints,
                                      value, aspect)
 
 
-def coerce_version(context, presentation, the_type, entry_schema, constraints, 
value, aspect): # pylint: disable=unused-argument
+def coerce_version(context, presentation, the_type, entry_schema, constraints, 
value, aspect):      # pylint: disable=unused-argument
     return coerce_to_data_type_class(context, presentation, Version, 
entry_schema, constraints,
                                      value, aspect)
 
@@ -533,23 +532,23 @@ def coerce_range(context, presentation, the_type, 
entry_schema, constraints, val
                                          value, aspect)
 
 
-def coerce_list(context, presentation, the_type, entry_schema, constraints, 
value, aspect): # pylint: disable=unused-argument
+def coerce_list(context, presentation, the_type, entry_schema, constraints, 
value, aspect):         # pylint: disable=unused-argument
     return coerce_to_data_type_class(context, presentation, List, 
entry_schema, constraints,
                                      value, aspect)
 
 
-def coerce_map_value(context, presentation, the_type, entry_schema, 
constraints, value, aspect): # pylint: disable=unused-argument
+def coerce_map_value(context, presentation, the_type, entry_schema, 
constraints, value, aspect):    # pylint: disable=unused-argument
     return coerce_to_data_type_class(context, presentation, Map, entry_schema, 
constraints, value,
                                      aspect)
 
 
-def coerce_scalar_unit_size(context, presentation, the_type, entry_schema, 
constraints, value, # pylint: disable=unused-argument
+def coerce_scalar_unit_size(context, presentation, the_type, entry_schema, 
constraints, value,      # pylint: disable=unused-argument
                             aspect):
     return coerce_to_data_type_class(context, presentation, ScalarSize, 
entry_schema, constraints,
                                      value, aspect)
 
 
-def coerce_scalar_unit_time(context, presentation, the_type, entry_schema, 
constraints, value, # pylint: disable=unused-argument
+def coerce_scalar_unit_time(context, presentation, the_type, entry_schema, 
constraints, value,      # pylint: disable=unused-argument
                             aspect):
     return coerce_to_data_type_class(context, presentation, ScalarTime, 
entry_schema, constraints,
                                      value, aspect)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/definitions.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/definitions.py 
b/extensions/aria_extension_tosca/simple_v1_0/definitions.py
index 9158776..a7e2806 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/definitions.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/definitions.py
@@ -15,7 +15,9 @@
 
 from aria.utils.collections import FrozenDict
 from aria.utils.caching import cachedmethod
+from aria.utils.formatting import safe_repr
 from aria.parser import implements_specification
+from aria.parser.validation import Issue
 from aria.parser.presentation import (has_fields, short_form_field, 
allow_unknown_fields,
                                       primitive_field, primitive_list_field, 
object_field,
                                       object_list_field, object_dict_field,
@@ -192,8 +194,8 @@ class AttributeDefinition(ExtensiblePresentation):
 
 
 @has_fields
-@implements_specification('3.5.12', 'tosca-simple-1.0')
-class ParameterDefinition(PropertyDefinition):
+@implements_specification('3.5.12-1', 'tosca-simple-1.0')
+class InputDefinition(PropertyDefinition):
     """
     A parameter definition is essentially a TOSCA property definition; 
however, it also allows a
     value to be assigned to it (as for a TOSCA property assignment). In 
addition, in the case of
@@ -205,6 +207,18 @@ class ParameterDefinition(PropertyDefinition):
     #DEFN_ELEMENT_PARAMETER_DEF>`__
     """
 
+    @field_validator(data_value_validator)
+    @primitive_field()
+    def value(self):
+        """
+        The type-compatible value to assign to the named parameter. Parameter 
values may be provided
+        as the result from the evaluation of an expression or a function.
+        """
+
+
+@has_fields
+@implements_specification('3.5.12-2', 'tosca-simple-1.0')
+class OutputDefinition(InputDefinition):
     @field_validator(data_type_validator())
     @primitive_field(str)
     def type(self):
@@ -214,15 +228,10 @@ class ParameterDefinition(PropertyDefinition):
         Note: This keyname is required for a TOSCA Property definition, but is 
not for a TOSCA
         Parameter definition.
 
-        :type: :obj:`basestring`
-        """
+        ARIA NOTE: the spec must be mistaken: inputs should have this field 
requires, only outputs
+        have it as optional.
 
-    @field_validator(data_value_validator)
-    @primitive_field()
-    def value(self):
-        """
-        The type-compatible value to assign to the named parameter. Parameter 
values may be provided
-        as the result from the evaluation of an expression or a function.
+        :type: :obj:`basestring`
         """
 
 
@@ -283,7 +292,7 @@ class InterfaceDefinition(ExtensiblePresentation):
 
     @field_validator(type_validator('interface type', 
convert_name_to_full_type_name,
                                     'interface_types'))
-    @primitive_field(str)
+    @primitive_field(str, required=True)
     def type(self):
         """
         ARIA NOTE: This field is not mentioned in the spec, but is implied.
@@ -322,9 +331,8 @@ class InterfaceDefinition(ExtensiblePresentation):
 
     def _validate(self, context):
         super(InterfaceDefinition, self)._validate(context)
-        if self.operations:
-            for operation in self.operations.itervalues(): # pylint: 
disable=no-member
-                operation._validate(context)
+        self._get_inputs(context)
+        self._get_operations(context)
 
 
 @short_form_field('type')
@@ -342,6 +350,8 @@ class RelationshipDefinition(ExtensiblePresentation):
         The optional reserved keyname used to provide the name of the 
Relationship Type for the
         requirement definition's relationship keyname.
 
+        ARIA NOTE: the spec shows this as a required field.
+
         :type: :obj:`basestring`
         """
 
@@ -428,6 +438,16 @@ class RequirementDefinition(ExtensiblePresentation):
     def _get_node_type(self, context):
         return context.presentation.get_from_dict('service_template', 
'node_types', self.node)
 
+    def _validate(self, context):
+        super(RequirementDefinition, self)._validate(context)
+        occurrences = self.occurrences
+        if (occurrences is not None) and ((occurrences.value[0] < 0) or \
+            ((occurrences.value[1] != 'UNBOUNDED') and (occurrences.value[1] < 
0))):
+            context.validation.report(
+                'requirements definition "{0}" occurrences range includes 
negative integers: {1}'
+                .format(self._name, safe_repr(occurrences)),
+                locator=self._locator, level=Issue.BETWEEN_TYPES)
+
 
 @short_form_field('type')
 @has_fields
@@ -516,3 +536,13 @@ class CapabilityDefinition(ExtensiblePresentation):
             if container_parent is not None else None
         return container_parent_capabilities.get(self._name) \
             if container_parent_capabilities is not None else None
+
+    def _validate(self, context):
+        super(CapabilityDefinition, self)._validate(context)
+        occurrences = self.occurrences
+        if (occurrences is not None) and ((occurrences.value[0] < 0) or \
+            ((occurrences.value[1] != 'UNBOUNDED') and (occurrences.value[1] < 
0))):
+            context.validation.report(
+                'capability definition "{0}" occurrences range includes 
negative integers: {1}'
+                .format(self._name, safe_repr(occurrences)),
+                locator=self._locator, level=Issue.BETWEEN_TYPES)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/misc.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/misc.py 
b/extensions/aria_extension_tosca/simple_v1_0/misc.py
index 221163c..914691e 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/misc.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/misc.py
@@ -20,14 +20,16 @@ from aria.parser import implements_specification
 from aria.parser.presentation import (AsIsPresentation, has_fields, 
allow_unknown_fields,
                                       short_form_field, primitive_field, 
primitive_list_field,
                                       primitive_dict_unknown_fields, 
object_field,
-                                      object_list_field, object_dict_field, 
field_validator,
-                                      type_validator)
+                                      object_list_field, object_dict_field, 
field_getter,
+                                      field_validator, type_validator, 
not_negative_validator)
 
+from .data_types import Version
 from .modeling.data_types import (get_data_type, get_data_type_value, 
get_property_constraints,
                                   apply_constraint_to_value)
 from .modeling.substitution_mappings import 
(validate_substitution_mappings_requirement,
                                              
validate_substitution_mappings_capability)
 from .presentation.extensible import ExtensiblePresentation
+from .presentation.field_getters import data_type_class_getter
 from .presentation.field_validators import (constraint_clause_field_validator,
                                             
constraint_clause_in_range_validator,
                                             
constraint_clause_valid_values_validator,
@@ -47,7 +49,7 @@ class Description(AsIsPresentation):
     #DEFN_ELEMENT_DESCRIPTION>`__
     """
 
-    def __init__(self, name=None, raw=None, container=None, cls=None): # 
pylint: disable=unused-argument
+    def __init__(self, name=None, raw=None, container=None, cls=None):         
                     # pylint: disable=unused-argument
         super(Description, self).__init__(name, raw, container, cls=unicode)
 
     def _dump(self, context):
@@ -79,6 +81,7 @@ class MetaData(ExtensiblePresentation):
         as a single-line string value.
         """
 
+    @field_getter(data_type_class_getter(Version, allow_null=True))
     @primitive_field(str)
     @implements_specification('3.9.3.5', 'tosca-simple-1.0')
     def template_version(self):
@@ -87,7 +90,7 @@ class MetaData(ExtensiblePresentation):
         service template as a single-line string value.
         """
 
-    @primitive_dict_unknown_fields()
+    @primitive_dict_unknown_fields(str)
     def custom(self):
         """
         :type: dict
@@ -135,6 +138,10 @@ class Repository(ExtensiblePresentation):
     def _get_credential(self, context):
         return get_data_type_value(context, self, 'credential', 
'tosca.datatypes.Credential')
 
+    def _validate(self, context):
+        super(Repository, self)._validate(context)
+        self._get_credential(context)
+
 
 @short_form_field('file')
 @has_fields
@@ -255,18 +262,21 @@ class ConstraintClause(ExtensiblePresentation):
         Constrains a property or parameter to a value that is in the list of 
declared values.
         """
 
+    @field_validator(not_negative_validator)
     @primitive_field(int)
     def length(self):
         """
         Constrains the property or parameter to a value of a given length.
         """
 
+    @field_validator(not_negative_validator)
     @primitive_field(int)
     def min_length(self):
         """
         Constrains the property or parameter to a value to a minimum length.
         """
 
+    @field_validator(not_negative_validator)
     @primitive_field(int)
     def max_length(self):
         """

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
index 0c621a0..17b94fc 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -27,7 +27,7 @@ from datetime import datetime
 
 
 from aria.parser.validation import Issue
-from aria.utils.formatting import string_list_as_string
+from aria.utils.formatting import (string_list_as_string, safe_repr)
 from aria.utils.collections import (StrictDict, OrderedDict)
 from aria.utils.yaml import yaml
 from aria.orchestrator import WORKFLOW_DECORATOR_RESERVED_ARGUMENTS
@@ -49,7 +49,7 @@ from ..data_types import coerce_value
 IMPLEMENTATION_PREFIX_REGEX = re.compile(r'(?<!\\)(?:\\\\)*>')
 
 
-def create_service_template_model(context): # pylint: 
disable=too-many-locals,too-many-branches
+def create_service_template_model(context):                                    
                     # pylint: disable=too-many-locals,too-many-branches
     model = ServiceTemplate(created_at=datetime.now(),
                             
main_file_name=os.path.basename(str(context.presentation.location)))
 
@@ -315,6 +315,10 @@ def create_relationship_template_model(context, 
service_template, relationship):
     create_parameter_models_from_assignments(model.properties,
                                              relationship.properties,
                                              model_cls=Property)
+    # TODO: does not exist in models, but should
+    #create_parameter_models_from_assignments(model.attributes,
+    #                                         relationship.attributes,
+    #                                         model_cls=Attribute)
     create_interface_template_models(context, service_template, 
model.interface_templates,
                                      relationship.interfaces)
 
@@ -346,6 +350,10 @@ def create_capability_template_model(context, 
service_template, capability):
     create_parameter_models_from_assignments(model.properties,
                                              capability.properties,
                                              model_cls=Property)
+    # TODO: does not exist in models, but should
+    #create_parameter_models_from_assignments(model.attributes,
+    #                                         capability.attributes,
+    #                                         model_cls=Attribute)
 
     return model
 
@@ -399,7 +407,7 @@ def create_operation_template_model(context, 
service_template, operation):
                         value = yaml.load(value, Loader=yaml.SafeLoader)
                     except yaml.parser.MarkedYAMLError as e:
                         context.validation.report(
-                            'YAML parser {0} in operation configuration: {1}'
+                            u'YAML parser {0} in operation configuration: {1}'
                             .format(e.problem, value),
                             locator=implementation._locator,
                             level=Issue.FIELD)
@@ -518,7 +526,7 @@ def create_workflow_operation_template_model(context, 
service_template, policy):
 
     used_reserved_names = 
WORKFLOW_DECORATOR_RESERVED_ARGUMENTS.intersection(model.inputs.keys())
     if used_reserved_names:
-        context.validation.report('using reserved arguments in workflow policy 
"{0}": {1}'
+        context.validation.report(u'using reserved arguments in workflow 
policy "{0}": {1}'
                                   .format(
                                       policy._name,
                                       
string_list_as_string(used_reserved_names)),
@@ -630,7 +638,8 @@ def create_node_filter_constraints(context, node_filter, 
target_node_template_co
         for property_name, constraint_clause in properties:
             constraint = create_constraint(context, node_filter, 
constraint_clause, property_name,
                                            None)
-            target_node_template_constraints.append(constraint)
+            if constraint is not None:
+                target_node_template_constraints.append(constraint)
 
     capabilities = node_filter.capabilities
     if capabilities is not None:
@@ -640,24 +649,33 @@ def create_node_filter_constraints(context, node_filter, 
target_node_template_co
                 for property_name, constraint_clause in properties:
                     constraint = create_constraint(context, node_filter, 
constraint_clause,
                                                    property_name, 
capability_name)
-                    target_node_template_constraints.append(constraint)
+                    if constraint is not None:
+                        target_node_template_constraints.append(constraint)
 
 
-def create_constraint(context, node_filter, constraint_clause, property_name, 
capability_name): # pylint: disable=too-many-return-statements
+def create_constraint(context, node_filter, constraint_clause, property_name, 
capability_name):     # pylint: disable=too-many-return-statements
+    if (not isinstance(constraint_clause._raw, dict)) or 
(len(constraint_clause._raw) != 1):
+        context.validation.report(
+            u'node_filter constraint is not a dict with one key: {0}'
+            .format(safe_repr(constraint_clause._raw)),
+            locator=node_filter._locator,
+            level=Issue.FIELD)
+        return None
+
     constraint_key = constraint_clause._raw.keys()[0]
 
     the_type = constraint_clause._get_type(context)
 
-    def coerce_constraint(constraint):
+    def coerce_constraint(constraint, the_type=the_type):
         if the_type is not None:
             return coerce_value(context, node_filter, the_type, None, None, 
constraint,
                                 constraint_key)
         else:
             return constraint
 
-    def coerce_constraints(constraints):
+    def coerce_constraints(constraints, the_type=the_type):
         if the_type is not None:
-            return tuple(coerce_constraint(constraint) for constraint in 
constraints)
+            return tuple(coerce_constraint(constraint, the_type) for 
constraint in constraints)
         else:
             return constraints
 
@@ -684,18 +702,22 @@ def create_constraint(context, node_filter, 
constraint_clause, property_name, ca
                            coerce_constraints(constraint_clause.valid_values))
     elif constraint_key == 'length':
         return Length(property_name, capability_name,
-                      coerce_constraint(constraint_clause.length))
+                      coerce_constraint(constraint_clause.length, int))
     elif constraint_key == 'min_length':
         return MinLength(property_name, capability_name,
-                         coerce_constraint(constraint_clause.min_length))
+                         coerce_constraint(constraint_clause.min_length, int))
     elif constraint_key == 'max_length':
         return MaxLength(property_name, capability_name,
-                         coerce_constraint(constraint_clause.max_length))
+                         coerce_constraint(constraint_clause.max_length, int))
     elif constraint_key == 'pattern':
         return Pattern(property_name, capability_name,
-                       coerce_constraint(constraint_clause.pattern))
+                       coerce_constraint(constraint_clause.pattern, unicode))
     else:
-        raise ValueError('malformed node_filter: {0}'.format(constraint_key))
+        context.validation.report(
+            u'unsupported node_filter constraint: {0}'.format(constraint_key),
+            locator=node_filter._locator,
+            level=Issue.FIELD)
+        return None
 
 
 def split_prefix(string):
@@ -703,7 +725,7 @@ def split_prefix(string):
     Splits the prefix on the first non-escaped ">".
     """
 
-    split = IMPLEMENTATION_PREFIX_REGEX.split(string, 1)
+    split = IMPLEMENTATION_PREFIX_REGEX.split(string, 1) if string is not None 
else ()
     if len(split) < 2:
         return None, None
     return split[0].strip(), split[1].strip()
@@ -740,7 +762,7 @@ def extract_implementation_primary(context, 
service_template, presentation, mode
         model.function = postfix
         if model.plugin_specification is None:
             context.validation.report(
-                'no policy for plugin "{0}" specified in operation 
implementation: {1}'
+                u'no policy for plugin "{0}" specified in operation 
implementation: {1}'
                 .format(prefix, primary),
                 locator=presentation._get_child_locator('properties', 
'implementation'),
                 level=Issue.BETWEEN_TYPES)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
----------------------------------------------------------------------
diff --git 
a/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
index 1b95bec..bf6636b 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
@@ -73,8 +73,8 @@ def get_inherited_capability_definitions(context, 
presentation, for_presentation
 
                 if not type1._is_descendant(context, type2):
                     context.validation.report(
-                        'capability definition type "{0}" is not a descendant 
of overridden '
-                        'capability definition type "{1}"' \
+                        u'capability definition type "{0}" is not a descendant 
of overridden '
+                        u'capability definition type "{1}"' \
                         .format(type1._name, type2._name),
                         locator=our_capability_definition._locator, 
level=Issue.BETWEEN_TYPES)
 
@@ -139,9 +139,18 @@ def get_template_capabilities(context, presentation):
                 if values:
                     capability_assignment._raw['properties'] = values
                     capability_assignment._reset_method_cache()
+
+                # Assign attributes
+                values = get_assigned_and_defined_parameter_values(context,
+                                                                   
our_capability_assignment,
+                                                                   'attribute')
+
+                if values:
+                    capability_assignment._raw['attributes'] = values
+                    capability_assignment._reset_method_cache()
             else:
                 context.validation.report(
-                    'capability "{0}" not declared at node type "{1}" in "{2}"'
+                    u'capability "{0}" not declared at node type "{1}" in 
"{2}"'
                     .format(capability_name, presentation.type, 
presentation._fullname),
                     locator=our_capability_assignment._locator, 
level=Issue.BETWEEN_TYPES)
 
@@ -161,29 +170,38 @@ def 
convert_capability_from_definition_to_assignment(context, presentation, cont
     if properties is not None:
         raw['properties'] = convert_parameter_definitions_to_values(context, 
properties)
 
-    # TODO attributes
+    attributes = presentation.attributes
+    if attributes is not None:
+        raw['attributes'] = convert_parameter_definitions_to_values(context, 
attributes)
 
     return CapabilityAssignment(name=presentation._name, raw=raw, 
container=container)
 
 
 def merge_capability_definition(context, presentation, capability_definition,
                                 from_capability_definition):
-    raw_properties = OrderedDict()
-
     capability_definition._raw['type'] = from_capability_definition.type
 
-    # Merge properties from type
-    from_property_defintions = from_capability_definition.properties
-    merge_raw_parameter_definitions(context, presentation, raw_properties, 
from_property_defintions,
-                                    'properties')
+    raw_properties = OrderedDict()
+    raw_attributes = OrderedDict()
 
-    # Merge our properties
+    # Merge parameters from type
     merge_raw_parameter_definitions(context, presentation, raw_properties,
                                     capability_definition.properties, 
'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_attributes,
+                                    capability_definition.attributes, 
'attributes')
+
+    # Merge our parameters
+    merge_raw_parameter_definitions(context, presentation, raw_properties,
+                                    from_capability_definition.properties, 
'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_attributes,
+                                    from_capability_definition.attributes, 
'attributes')
 
     if raw_properties:
         capability_definition._raw['properties'] = raw_properties
         capability_definition._reset_method_cache()
+    if raw_attributes:
+        capability_definition._raw['attributes'] = raw_attributes
+        capability_definition._reset_method_cache()
 
     # Merge occurrences
     occurrences = from_capability_definition._raw.get('occurrences')
@@ -194,23 +212,31 @@ def merge_capability_definition(context, presentation, 
capability_definition,
 
 def merge_capability_definition_from_type(context, presentation, 
capability_definition):
     """
-    Merge ``properties`` and ``valid_source_types`` from the node type's 
capability definition
-    over those taken from the parent node type.
+    Merge ``properties``, ``attributes``, and ``valid_source_types`` from the 
node type's capability
+    definition over those taken from the parent node type.
     """
     raw_properties = OrderedDict()
+    raw_attributes = OrderedDict()
 
-    # Merge properties from parent
+    # Merge parameters from parent
     the_type = capability_definition._get_type(context)
     type_property_defintions = the_type._get_properties(context)
+    type_attribute_defintions = the_type._get_attributes(context)
     merge_raw_parameter_definitions(context, presentation, raw_properties, 
type_property_defintions,
                                     'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_attributes,
+                                    type_attribute_defintions, 'attributes')
 
-    # Merge our properties (might override definitions in parent)
+    # Merge our parameters (might override definitions in parent)
     merge_raw_parameter_definitions(context, presentation, raw_properties,
                                     capability_definition.properties, 
'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_attributes,
+                                    capability_definition.attributes, 
'attributes')
 
     if raw_properties:
         capability_definition._raw['properties'] = raw_properties
+    if raw_attributes:
+        capability_definition._raw['attributes'] = raw_attributes
 
     # Override valid_source_types
     if capability_definition._raw.get('valid_source_types') is None:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py
index bd9037f..b3c2e49 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/copy.py
@@ -23,7 +23,7 @@ def get_default_raw_from_copy(presentation, field_name):
     """
 
     copy = presentation._raw.get('copy')
-    if copy is not None:
+    if isinstance(copy, basestring):
         templates = getattr(presentation._container, field_name)
         if templates is not None:
             template = templates.get(copy)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/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
index 13ce9a3..25e53c6 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
@@ -52,7 +52,7 @@ def get_inherited_constraints(context, presentation):
     return constraints
 
 
-def coerce_data_type_value(context, presentation, data_type, entry_schema, 
constraints, value, # pylint: disable=unused-argument
+def coerce_data_type_value(context, presentation, data_type, entry_schema, 
constraints, value,      # pylint: disable=unused-argument
                            aspect):
     """
     Handles the ``_coerce_data()`` hook for complex data types.
@@ -90,8 +90,8 @@ def coerce_data_type_value(context, presentation, data_type, 
entry_schema, const
                                               aspect)
                 else:
                     context.validation.report(
-                        'assignment to undefined property "%s" in type "%s" in 
"%s"'
-                        % (name, data_type._fullname, presentation._fullname),
+                        u'assignment to undefined property "{0}" in type "{1}" 
in "{2}"'
+                        .format(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
@@ -108,15 +108,15 @@ def coerce_data_type_value(context, presentation, 
data_type, entry_schema, const
 
                 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),
+                        u'required property "{0}" in type "{1}" is not 
assigned a value in "{2}"'
+                        .format(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),
+            context.validation.report(u'value of type "{0}" is not a dict in 
"{1}"'
+                                      .format(data_type._fullname, 
presentation._fullname),
                                       locator=get_locator(value, presentation),
                                       level=Issue.BETWEEN_TYPES)
             value = None
@@ -131,8 +131,8 @@ def validate_data_type_name(context, presentation):
 
     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),
+        context.validation.report(u'data type name is that of a built-in type: 
{0}'
+                                  .format(safe_repr(name)),
                                   locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
 
 
@@ -201,7 +201,7 @@ def get_property_constraints(context, presentation):
 # ConstraintClause
 #
 
-def apply_constraint_to_value(context, presentation, constraint_clause, 
value): # pylint: 
disable=too-many-statements,too-many-return-statements,too-many-branches
+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.
     """
@@ -216,10 +216,10 @@ def apply_constraint_to_value(context, presentation, 
constraint_clause, value):
                             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)),
+        context.validation.report(u'value {0} {1} per constraint in "{2}": {3}'
+                                  .format(message, safe_repr(constraint),
+                                          presentation._name or 
presentation._container._name,
+                                          safe_repr(value)),
                                   locator=presentation._locator, 
level=Issue.BETWEEN_FIELDS)
 
     if constraint_key == 'equal':
@@ -318,15 +318,15 @@ def apply_constraint_to_value(context, presentation, 
constraint_clause, value):
 #
 
 def get_data_type_value(context, presentation, field_name, type_name):
-    the_type = get_type_by_name(context, type_name, 'data_types')
-    if the_type is not None:
-        value = getattr(presentation, field_name)
-        if value is not None:
+    value = getattr(presentation, field_name)
+    if value is not None:
+        the_type = get_type_by_name(context, type_name, 'data_types')
+        if the_type 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)
+        else:
+            context.validation.report(u'field "{0}" in "{1}" refers to unknown 
data type "{2}"'
+                                      .format(field_name, 
presentation._fullname, type_name),
+                                      locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
     return None
 
 
@@ -372,7 +372,7 @@ def get_data_type_name(the_type):
     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
+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.
@@ -394,8 +394,8 @@ def coerce_value(context, presentation, the_type, 
entry_schema, constraints, val
 
     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)),
+            context.validation.report(u'field "{0}" is of type "null" but has 
a non-null value: {1}'
+                                      .format(presentation._name, 
safe_repr(value)),
                                       locator=presentation._locator, 
level=Issue.BETWEEN_FIELDS)
             return None
 
@@ -498,17 +498,18 @@ def report_issue_for_bad_format(context, presentation, 
the_type, value, aspect,
     if aspect == 'default':
         aspect = '"default" value'
     elif aspect is not None:
-        aspect = '"%s" aspect' % aspect
+        aspect = u'"{0}" aspect'.format(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)),
+        context.validation.report(u'{0} for field "{1}" is not a valid "{2}": 
{3}'
+                                  .format(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)),
+        context.validation.report(u'field "{0}" is not a valid "{1}": {2}'
+                                  .format(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/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py
index ecbfde9..16c49fa 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/functions.py
@@ -24,6 +24,7 @@ from aria.parser.exceptions import InvalidValueError
 from aria.parser.validation import Issue
 from aria.modeling.exceptions import CannotEvaluateFunctionException
 from aria.modeling.models import (Node, NodeTemplate, Relationship, 
RelationshipTemplate)
+from aria.modeling.mixins import ParameterMixin
 from aria.modeling.functions import (Function, Evaluation)
 
 
@@ -43,7 +44,7 @@ class Concat(Function):
 
         if not isinstance(argument, list):
             raise InvalidValueError(
-                'function "concat" argument must be a list of string 
expressions: {0}'
+                u'function "concat" argument must be a list of string 
expressions: {0}'
                 .format(safe_repr(argument)),
                 locator=self.locator)
 
@@ -84,7 +85,7 @@ class Token(Function):
         self.locator = presentation._locator
 
         if (not isinstance(argument, list)) or (len(argument) != 3):
-            raise InvalidValueError('function "token" argument must be a list 
of 3 parameters: {0}'
+            raise InvalidValueError(u'function "token" argument must be a list 
of 3 parameters: {0}'
                                     .format(safe_repr(argument)),
                                     locator=self.locator)
 
@@ -95,6 +96,10 @@ class Token(Function):
                                                              argument[1])
         self.substring_index = parse_int(context, presentation, 'token', 2,
                                          'the 0-based index of the token to 
return', argument[2])
+        if self.substring_index < 0:
+            raise invalid_value('token', 2, 'a non-negative integer',
+                                'the 0-based index of the token to return', 
self.substring_index,
+                                presentation._locator)
 
     @property
     def as_raw(self):
@@ -143,7 +148,7 @@ class GetInput(Function):
                                                            'inputs', 
self.input_property_name)
             if the_input is None:
                 raise InvalidValueError(
-                    'function "get_input" argument is not a valid input name: 
{0}'
+                    u'function "get_input" argument is not a valid input name: 
{0}'
                     .format(safe_repr(argument)),
                     locator=self.locator)
 
@@ -162,7 +167,7 @@ class GetInput(Function):
             return Evaluation(value, False) # We never return final 
evaluations!
 
         raise InvalidValueError(
-            'function "get_input" argument is not a valid input name: {0}'
+            u'function "get_input" argument is not a valid input name: {0}'
             .format(safe_repr(self.input_property_name)),
             locator=self.locator)
 
@@ -179,8 +184,8 @@ class GetProperty(Function):
 
         if (not isinstance(argument, list)) or (len(argument) < 2):
             raise InvalidValueError(
-                'function "get_property" argument must be a list of at least 2 
string expressions: '
-                '{0}'.format(safe_repr(argument)),
+                u'function "get_property" argument must be a list of at least 
2 string expressions:'
+                u' {0}'.format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_modelable_entity_name(context, 
presentation,
@@ -224,14 +229,13 @@ class GetProperty(Function):
                 properties = modelable_entity.properties
                 nested_property_name_or_index = 
self.nested_property_name_or_index
 
-            evaluation = get_modelable_entity_parameter(modelable_entity, 
properties,
-                                                        
nested_property_name_or_index)
+            evaluation = get_modelable_entity_parameter(properties, 
nested_property_name_or_index)
             if evaluation is not None:
                 return evaluation
 
         raise InvalidValueError(
-            'function "get_property" could not find "{0}" in modelable entity 
"{1}"'
-            .format('.'.join(self.nested_property_name_or_index), 
self.modelable_entity_name),
+            u'function "get_property" could not find "{0}" in modelable entity 
"{1}"'
+            .format(u'.'.join(self.nested_property_name_or_index), 
self.modelable_entity_name),
             locator=self.locator)
 
 
@@ -251,8 +255,8 @@ class GetAttribute(Function):
 
         if (not isinstance(argument, list)) or (len(argument) < 2):
             raise InvalidValueError(
-                'function "get_attribute" argument must be a list of at least 
2 string expressions:'
-                ' {0}'.format(safe_repr(argument)),
+                u'function "get_attribute" argument must be a list of at least 
2 string '
+                u'expressions: {0}'.format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_modelable_entity_name(context, 
presentation,
@@ -270,15 +274,14 @@ class GetAttribute(Function):
         for modelable_entity in modelable_entities:
             attributes = modelable_entity.attributes
             nested_attribute_name_or_index = 
self.nested_attribute_name_or_index
-            evaluation = get_modelable_entity_parameter(modelable_entity, 
attributes,
-                                                        
nested_attribute_name_or_index)
+            evaluation = get_modelable_entity_parameter(attributes, 
nested_attribute_name_or_index)
             if evaluation is not None:
                 evaluation.final = False # We never return final evaluations!
                 return evaluation
 
         raise InvalidValueError(
-            'function "get_attribute" could not find "{0}" in modelable entity 
"{1}"'
-            .format('.'.join(self.nested_attribute_name_or_index), 
self.modelable_entity_name),
+            u'function "get_attribute" could not find "{0}" in modelable 
entity "{1}"'
+            .format(u'.'.join(self.nested_attribute_name_or_index), 
self.modelable_entity_name),
             locator=self.locator)
 
 
@@ -286,7 +289,7 @@ class GetAttribute(Function):
 # Operation
 #
 
-@implements_specification('4.6.1', 'tosca-simple-1.0') # pylint: 
disable=abstract-method
+@implements_specification('4.6.1', 'tosca-simple-1.0')                         
                     # pylint: disable=abstract-method
 class GetOperationOutput(Function):
     """
     The ``get_operation_output`` function is used to retrieve the values of 
variables exposed /
@@ -298,7 +301,7 @@ class GetOperationOutput(Function):
 
         if (not isinstance(argument, list)) or (len(argument) != 4):
             raise InvalidValueError(
-                'function "get_operation_output" argument must be a list of 4 
parameters: {0}'
+                u'function "get_operation_output" argument must be a list of 4 
parameters: {0}'
                 .format(safe_repr(argument)),
                 locator=self.locator)
 
@@ -327,6 +330,9 @@ class GetOperationOutput(Function):
         return {'get_operation_output': [self.modelable_entity_name, 
interface_name, operation_name,
                                          output_variable_name]}
 
+    def __evaluate__(self, container):
+        return Evaluation(None)
+
 
 #
 # Navigation
@@ -349,7 +355,7 @@ class GetNodesOfType(Function):
             node_types = context.presentation.get('service_template', 
'node_types')
             if (node_types is None) or (self.node_type_name not in node_types):
                 raise InvalidValueError(
-                    'function "get_nodes_of_type" argument is not a valid node 
type name: {0}'
+                    u'function "get_nodes_of_type" argument is not a valid 
node type name: {0}'
                     .format(safe_repr(argument)),
                     locator=self.locator)
 
@@ -361,14 +367,14 @@ class GetNodesOfType(Function):
         return {'get_nodes_of_type': node_type_name}
 
     def __evaluate__(self, container):
-        pass
+        return Evaluation(None)
 
 
 #
 # Artifact
 #
 
-@implements_specification('4.8.1', 'tosca-simple-1.0') # pylint: 
disable=abstract-method
+@implements_specification('4.8.1', 'tosca-simple-1.0')                         
                     # pylint: disable=abstract-method
 class GetArtifact(Function):
     """
     The ``get_artifact`` function is used to retrieve artifact location 
between modelable
@@ -380,7 +386,7 @@ class GetArtifact(Function):
 
         if (not isinstance(argument, list)) or (len(argument) < 2) or 
(len(argument) > 4):
             raise InvalidValueError(
-                'function "get_artifact" argument must be a list of 2 to 4 
parameters: {0}'
+                u'function "get_artifact" argument must be a list of 2 to 4 
parameters: {0}'
                 .format(safe_repr(argument)),
                 locator=self.locator)
 
@@ -389,10 +395,16 @@ class GetArtifact(Function):
                                                              argument[0])
         self.artifact_name = parse_string_expression(context, presentation, 
'get_artifact', 1,
                                                      'the artifact name', 
argument[1])
-        self.location = parse_string_expression(context, presentation, 
'get_artifact', 2,
-                                                'the location or 
"LOCAL_FILE"', argument[2])
-        self.remove = parse_bool(context, presentation, 'get_artifact', 3, 
'the removal flag',
-                                 argument[3])
+        if len(argument) > 2:
+            self.location = parse_string_expression(context, presentation, 
'get_artifact', 2,
+                                                    'the location or 
"LOCAL_FILE"', argument[2])
+        else:
+            self.location = None
+        if len(argument) > 3:
+            self.remove = parse_bool(context, presentation, 'get_artifact', 3, 
'the removal flag',
+                                     argument[3])
+        else:
+            self.remove = None
 
     @property
     def as_raw(self):
@@ -400,9 +412,22 @@ class GetArtifact(Function):
         if hasattr(artifact_name, 'as_raw'):
             artifact_name = as_raw(artifact_name)
         location = self.location
-        if hasattr(location, 'as_raw'):
-            location = as_raw(location)
-        return {'get_artifacts': [self.modelable_entity_name, artifact_name, 
location, self.remove]}
+        if location is not None:
+            if hasattr(location, 'as_raw'):
+                location = as_raw(location)
+            remove = self.remove
+            if hasattr(remove, 'as_raw'):
+                remove = as_raw(remove)
+            if remove is not None:
+                return {'get_artifact': [self.modelable_entity_name, 
artifact_name, location,
+                                         remove]}
+            else:
+                return {'get_artifact': [self.modelable_entity_name, 
artifact_name, location]}
+        else:
+            return {'get_artifact': [self.modelable_entity_name, 
artifact_name]}
+
+    def __evaluate__(self, container):
+        return Evaluation(None)
 
 
 #
@@ -422,16 +447,16 @@ def get_function(context, presentation, value):
     return False, None
 
 
-def parse_string_expression(context, presentation, name, index, explanation, 
value): # pylint: disable=unused-argument
+def parse_string_expression(context, presentation, name, index, explanation, 
value):                # pylint: disable=unused-argument
     is_function, func = get_function(context, presentation, value)
     if is_function:
         return func
     else:
-        value = str(value)
+        value = unicode(value)
     return value
 
 
-def parse_int(context, presentation, name, index, explanation, value): # 
pylint: disable=unused-argument
+def parse_int(context, presentation, name, index, explanation, value):         
                     # pylint: disable=unused-argument
     if not isinstance(value, int):
         try:
             value = int(value)
@@ -441,7 +466,7 @@ def parse_int(context, presentation, name, index, 
explanation, value): # pylint:
     return value
 
 
-def parse_bool(context, presentation, name, index, explanation, value): # 
pylint: disable=unused-argument
+def parse_bool(context, presentation, name, index, explanation, value):        
                     # pylint: disable=unused-argument
     if not isinstance(value, bool):
         raise invalid_value(name, index, 'a boolean', explanation, value, 
presentation._locator)
     return value
@@ -475,7 +500,7 @@ def parse_modelable_entity_name(context, presentation, 
name, index, value):
             or {}
         if (value not in node_templates) and (value not in 
relationship_templates):
             raise InvalidValueError(
-                'function "{0}" parameter {1:d} is not a valid modelable 
entity name: {2}'
+                u'function "{0}" parameter {1:d} is not a valid modelable 
entity name: {2}'
                 .format(name, index + 1, safe_repr(value)),
                 locator=presentation._locator, level=Issue.BETWEEN_TYPES)
     return value
@@ -548,7 +573,7 @@ def get_modelable_entities(container_holder, name, locator, 
modelable_entity_nam
 
         return modelable_entities
 
-    raise InvalidValueError('function "{0}" could not find modelable entity 
"{1}"'
+    raise InvalidValueError(u'function "{0}" could not find modelable entity 
"{1}"'
                             .format(name, modelable_entity_name),
                             locator=locator)
 
@@ -564,9 +589,9 @@ def get_self(container_holder, name, locator):
         (not isinstance(container, NodeTemplate)) and \
         (not isinstance(container, Relationship)) and \
         (not isinstance(container, RelationshipTemplate)):
-        raise InvalidValueError('function "{0}" refers to "SELF" but it is not 
contained in '
-                                'a node or a relationship: {1}'.format(name,
-                                                                       
full_type_name(container)),
+        raise InvalidValueError(u'function "{0}" refers to "SELF" but it is 
not contained in '
+                                u'a node or a relationship: {1}'.format(name,
+                                                                        
full_type_name(container)),
                                 locator=locator)
 
     return [container]
@@ -586,8 +611,8 @@ def get_hosts(container_holder, name, locator):
 
     container = container_holder.container
     if (not isinstance(container, Node)) and (not isinstance(container, 
NodeTemplate)):
-        raise InvalidValueError('function "{0}" refers to "HOST" but it is not 
contained in '
-                                'a node: {1}'.format(name, 
full_type_name(container)),
+        raise InvalidValueError(u'function "{0}" refers to "HOST" but it is 
not contained in '
+                                u'a node: {1}'.format(name, 
full_type_name(container)),
                                 locator=locator)
 
     if not isinstance(container, Node):
@@ -611,8 +636,8 @@ def get_source(container_holder, name, locator):
     container = container_holder.container
     if (not isinstance(container, Relationship)) and \
         (not isinstance(container, RelationshipTemplate)):
-        raise InvalidValueError('function "{0}" refers to "SOURCE" but it is 
not contained in '
-                                'a relationship: {1}'.format(name, 
full_type_name(container)),
+        raise InvalidValueError(u'function "{0}" refers to "SOURCE" but it is 
not contained in '
+                                u'a relationship: {1}'.format(name, 
full_type_name(container)),
                                 locator=locator)
 
     if not isinstance(container, RelationshipTemplate):
@@ -631,8 +656,8 @@ def get_target(container_holder, name, locator):
     container = container_holder.container
     if (not isinstance(container, Relationship)) and \
         (not isinstance(container, RelationshipTemplate)):
-        raise InvalidValueError('function "{0}" refers to "TARGET" but it is 
not contained in '
-                                'a relationship: {1}'.format(name, 
full_type_name(container)),
+        raise InvalidValueError(u'function "{0}" refers to "TARGET" but it is 
not contained in '
+                                u'a relationship: {1}'.format(name, 
full_type_name(container)),
                                 locator=locator)
 
     if not isinstance(container, RelationshipTemplate):
@@ -642,21 +667,25 @@ def get_target(container_holder, name, locator):
     return [container.target_node]
 
 
-def get_modelable_entity_parameter(modelable_entity, parameters, 
nested_parameter_name_or_index):
+def get_modelable_entity_parameter(parameters, nested_parameter_name_or_index):
     if not parameters:
         return Evaluation(None, True)
 
     found = True
     final = True
     value = parameters
+    last_container = parameters
 
     for name_or_index in nested_parameter_name_or_index:
         if (isinstance(value, dict) and (name_or_index in value)) \
             or ((isinstance(value, list) and (name_or_index < len(value)))):
-            value = value[name_or_index] # Parameter
-            # We are not using Parameter.value, but rather Parameter._value, 
because we want to make
-            # sure to get "final" (it is swallowed by Parameter.value)
-            value, final = evaluate(value._value, final, value)
+            value = value[name_or_index]
+            if isinstance(value, ParameterMixin):
+                last_container = value
+                # We are not using Parameter.value, but rather 
Parameter._value, because we want to
+                # make sure to get "final" (it is swallowed by Parameter.value)
+                value = value._value
+            value, final = evaluate(value, final, last_container)
         else:
             found = False
             break
@@ -665,17 +694,17 @@ def get_modelable_entity_parameter(modelable_entity, 
parameters, nested_paramete
 
 
 def invalid_modelable_entity_name(name, index, value, locator, contexts):
-    return InvalidValueError('function "{0}" parameter {1:d} can be "{2}" only 
in {3}'
+    return InvalidValueError(u'function "{0}" parameter {1:d} can be "{2}" 
only in {3}'
                              .format(name, index + 1, value, contexts),
                              locator=locator, level=Issue.FIELD)
 
 
 def invalid_value(name, index, the_type, explanation, value, locator):
     return InvalidValueError(
-        'function "{0}" {1} is not {2}{3}: {4}'
+        u'function "{0}" {1} is not {2}{3}: {4}'
         .format(name,
-                'parameter {0:d}'.format(index + 1) if index is not None else 
'argument',
+                u'parameter {0:d}'.format(index + 1) if index is not None else 
'argument',
                 the_type,
-                ', {0}'.format(explanation) if explanation is not None else '',
+                u', {0}'.format(explanation) if explanation is not None else 
'',
                 safe_repr(value)),
         locator=locator, level=Issue.FIELD)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/extensions/aria_extension_tosca/simple_v1_0/modeling/groups.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/groups.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/groups.py
new file mode 100644
index 0000000..1d8013b
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/groups.py
@@ -0,0 +1,43 @@
+# 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_name_to_full_type_name
+
+
+#
+# GroupType
+#
+
+def get_inherited_members(context, presentation):
+    """
+    Returns our target node types if we have them or those of our parent, if 
we have one
+    (recursively).
+    """
+
+    parent = presentation._get_parent(context)
+
+    node_types = get_inherited_members(context, parent) if parent is not None 
else []
+
+    our_members = presentation.members
+    if our_members:
+        all_node_types = context.presentation.get('service_template', 
'node_types') or {}
+        node_types = []
+
+        for our_member in our_members:
+            if our_member in all_node_types:
+                our_member = convert_name_to_full_type_name(context, 
our_member, all_node_types)
+                node_types.append(all_node_types[our_member])
+
+    return node_types

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/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
index 23a03b7..4450fc2 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
@@ -18,6 +18,7 @@ from aria.parser.presentation import get_locator
 from aria.parser.validation import Issue
 
 from .parameters import (coerce_parameter_value, 
convert_parameter_definitions_to_values)
+from .data_types import (get_type_by_name, get_primitive_data_type)
 
 
 #
@@ -156,7 +157,7 @@ def get_template_interfaces(context, presentation, 
type_name):
     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:
+    if interface_definitions:
         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.
@@ -177,8 +178,8 @@ def get_template_interfaces(context, presentation, 
type_name):
                                 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),
+                    u'interface definition "{0}" not declared at {1} "{2}" in 
"{3}"'
+                    .format(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
@@ -209,7 +210,7 @@ def 
convert_interface_definition_from_type_to_template(context, presentation, co
     return InterfaceAssignment(name=presentation._name, raw=raw, 
container=container)
 
 
-def convert_interface_definition_from_type_to_raw_template(context, 
presentation): # pylint: disable=invalid-name
+def convert_interface_definition_from_type_to_raw_template(context, 
presentation):                  # pylint: disable=invalid-name
     raw = OrderedDict()
 
     # Copy default values for inputs
@@ -236,7 +237,7 @@ def 
convert_interface_definition_from_type_to_raw_template(context, presentation
     return raw
 
 
-def 
convert_requirement_interface_definitions_from_type_to_raw_template(context, 
raw_requirement, # pylint: disable=invalid-name
+def 
convert_requirement_interface_definitions_from_type_to_raw_template(context, 
raw_requirement,   # pylint: disable=invalid-name
                                                                         
interface_definitions):
     if not interface_definitions:
         return
@@ -257,62 +258,71 @@ def merge_interface(context, presentation, 
interface_assignment, our_interface_a
     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
+    if our_operation_templates is None:
+        our_operation_templates = {}
+
     # 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
+    if operation_definitions is None:
+        operation_definitions = {}
 
-            our_input_assignments = our_operation_template.inputs
-            our_implementation = our_operation_template.implementation
+    # OperationAssignment:
+    for operation_name, our_operation_template in 
our_operation_templates.iteritems():
+        operation_definition = operation_definitions.get(operation_name) # 
OperationDefinition
 
-            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)
+        our_input_assignments = our_operation_template.inputs
+        our_implementation = our_operation_template.implementation
 
-            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 operation_definition is None:
+            context.validation.report(
+                u'interface definition "{0}" refers to an unknown operation 
"{1}" in "{2}"'
+                .format(interface_name, operation_name, 
presentation._fullname),
+                locator=our_operation_template._locator, 
level=Issue.BETWEEN_TYPES)
+
+        # 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)
+        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)
+        # 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:
+    input_type1_name = the_raw_input.get('type')
+    input_type1 = get_type_by_name(context, input_type1_name, 'data_types')
+    if input_type1 is None:
+        input_type1 = get_primitive_data_type(input_type1_name)
+    input_type2 = our_input._get_type(context)
+    if input_type1 is not input_type2 and \
+        (not hasattr(input_type1, '_is_descendant') or \
+         not input_type1._is_descendant(context, 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)
+                u'type "{0}" is not a descendant of overridden type "{1}" for 
input "{2}" of '
+                u'operation {3} "{4}.{5}" in {6}'
+                .format(our_input.type, input_type1_name, our_input._name, 
type_name,
+                        interface_name, operation_name, 
presentation._fullname),
+                locator=our_input._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)
+                u'type "{0}" is not a descendant of overridden type "{1}" for 
input "{2}" of '
+                u'interface {3} "{4}" in {5}'
+                .format(our_input.type, input_type1_name, our_input._name, 
type_name,
+                        interface_name, presentation._fullname),
+                locator=our_input._locator, level=Issue.BETWEEN_TYPES)
 
     # Merge
     merge(the_raw_input, our_input._raw)
@@ -405,8 +415,8 @@ def merge_interface_definition(context, interface, 
our_source, presentation, typ
 
         if (type2 is not None) and not type1._is_descendant(context, type2):
             context.validation.report(
-                'interface definition type "{0}" is not a descendant of 
overridden '
-                'interface definition type "{1}"' \
+                u'interface definition type "{0}" is not a descendant of 
overridden '
+                u'interface definition type "{1}"' \
                 .format(type1._name, type2._name),
                 locator=our_source._locator, level=Issue.BETWEEN_TYPES)
 
@@ -448,37 +458,42 @@ def merge_interface_definitions_from_their_types(context, 
interfaces, presentati
             merge_interface_definition(context, interface, the_type, 
presentation, 'type')
 
 
-def assign_raw_inputs(context, values, assignments, definitions, 
interface_name, operation_name,
+def assign_raw_inputs(context, raw, assignments, definitions, interface_name, 
operation_name,
                       presentation):
-    if not assignments:
-        return
+    if assignments is None:
+        assignments = {}
+    if definitions is None:
+        definitions = {}
 
     # Make sure we have the dict
-    if ('inputs' not in values) or (values['inputs'] is None):
-        values['inputs'] = OrderedDict()
+    if ('inputs' not in raw) or (raw['inputs'] is None):
+        raw['inputs'] = OrderedDict()
+
+    # Defaults
+    for input_name, definition in definitions.iteritems():
+        if ('default' in definition._raw) and (input_name not in 
raw['inputs']):
+            raw['inputs'][input_name] = coerce_parameter_value(context, 
definition, definition,
+                                                               
definition.default, 'default')
 
     # Assign inputs
     for input_name, assignment in assignments.iteritems():
-        if (definitions is not None) and (input_name not in definitions):
+        if (not context.presentation.configuration.get('tosca.adhoc_inputs', 
True)) 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),
+                    u'interface definition "{0}" assigns a value to an unknown 
operation input'
+                    u' "{1}.{2}" in "{3}"'
+                    .format(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),
+                    u'interface definition "{0}" assigns a value to an unknown 
input "{1}" in "{2}"'
+                    .format(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_parameter_value(context, 
assignment, definition,
-                                                              assignment.value)
+        definition = definitions.get(input_name) # Could be None!
+        raw['inputs'][input_name] = coerce_parameter_value(context, 
assignment, definition,
+                                                           assignment.value)
 
 
 def validate_required_inputs(context, presentation, assignment, definition, 
original_assignment,
@@ -487,7 +502,11 @@ def validate_required_inputs(context, presentation, 
assignment, definition, orig
     # (as opposed to topology template and workflow inputs) is done only in 
the parsing stage.
     # This reasoning follows the TOSCA spirit, where anything that is declared 
as required in the
     # type, must be assigned in the corresponding template.
-    input_definitions = definition.inputs
+
+    # Note: InterfaceDefinition need _get_inputs, but OperationDefinition 
doesn't
+    input_definitions = definition._get_inputs(context) \
+        if hasattr(definition, '_get_inputs') \
+        else definition.inputs
     if input_definitions:
         for input_name, input_definition in input_definitions.iteritems():
             if input_definition.required:
@@ -498,16 +517,17 @@ def validate_required_inputs(context, presentation, 
assignment, definition, orig
                 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),
+                            u'interface definition "{0}" does not assign a 
value to a required'
+                            u' operation input "{1}.{2}" in "{3}"'
+                            .format(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),
+                            u'interface definition "{0}" does not assign a 
value to a required'
+                            u' input "{1}" in "{2}"'
+                            .format(interface_name, input_name, 
presentation._fullname),
                             locator=get_locator(original_assignment, 
presentation._locator),
                             level=Issue.BETWEEN_TYPES)
 


Reply via email to