Rebase, work to use models

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

Branch: refs/heads/ARIA-139-attributes
Commit: 9de5d9799d2e5119a4b081993a02abf1f65f79a2
Parents: 8e5a1ec
Author: Tal Liron <[email protected]>
Authored: Wed Apr 19 20:07:33 2017 -0500
Committer: Tal Liron <[email protected]>
Committed: Wed Apr 19 20:07:33 2017 -0500

----------------------------------------------------------------------
 aria/modeling/service_common.py                 | 32 ++++++--
 aria/modeling/service_instance.py               |  8 ++
 aria/modeling/service_template.py               | 16 ++++
 .../simple_v1_0/functions.py                    | 80 +++++++++++++-------
 .../simple_v1_0/modeling/__init__.py            |  2 +
 .../simple_v1_0/modeling/data_types.py          |  6 +-
 .../simple_v1_0/modeling/properties.py          | 17 +++--
 .../simple_v1_0/templates.py                    |  7 +-
 8 files changed, 123 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 1188f34..0a7df4d 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -15,6 +15,8 @@
 
 # pylint: disable=no-self-argument, no-member, abstract-method
 
+import datetime
+
 from sqlalchemy import (
     Column,
     Text,
@@ -22,6 +24,7 @@ from sqlalchemy import (
 )
 from sqlalchemy.ext.declarative import declared_attr
 
+from ..parser import dsl_specification
 from ..parser.consumption import ConsumptionContext
 from ..utils import collections, formatting, console
 from .mixins import InstanceModelMixin, TemplateModelMixin
@@ -90,22 +93,41 @@ class ParameterBase(TemplateModelMixin):
     def unwrap(self):
         return self.name, self.value
 
+    @dsl_specification('3.2.1-2', 'tosca-simple-1.0')
     @classmethod
     def wrap(cls, name, value, description=None):
         """
         Wraps an arbitrary value as a parameter. The type will be guessed via 
introspection.
 
+        For primitive types, we will prefer their TOSCA aliases. See the 
`TOSCA Simple Profile v1.0
+        cos01 specification 
<http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01
+        /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__
+
         :param name: Parameter name
         :type name: basestring
         :param value: Parameter value
         :param description: Description (optional)
         :type description: basestring
         """
-        return cls(name=name,
-                   type_name=formatting.full_type_name(value)
-                   if value is not None else None,
-                   value=value,
-                   description=description)
+        from . import models
+        if value is None:
+            type_name = 'null'
+        elif isinstance(value, basestring):
+            type_name = 'string'
+        elif isinstance(value, int):
+            type_name = 'integer'
+        elif isinstance(value, float):
+            type_name = 'float'
+        elif isinstance(value, bool):
+            type_name = 'boolean'
+        elif isinstance(value, datetime.datetime):
+            type_name = 'timestamp'
+        else:
+            type_name = formatting.full_type_name(value)
+        return models.Parameter(name=name,
+                                type_name=type_name,
+                                value=value,
+                                description=description)
 
 
 class TypeBase(InstanceModelMixin):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py 
b/aria/modeling/service_instance.py
index 6d8f3fe..b293535 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -515,6 +515,10 @@ class NodeBase(InstanceModelMixin):
     def properties(cls):
         return relationship.many_to_many(cls, 'parameter', 
prefix='properties', dict_key='name')
 
+    @declared_attr
+    def attributes(cls):
+        return relationship.many_to_many(cls, 'parameter', 
prefix='attributes', dict_key='name')
+
     # endregion
 
     description = Column(Text)
@@ -649,6 +653,7 @@ class NodeBase(InstanceModelMixin):
             ('name', self.name),
             ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties)),
+            ('attributes', formatting.as_raw_dict(self.properties)),
             ('interfaces', formatting.as_raw_list(self.interfaces)),
             ('artifacts', formatting.as_raw_list(self.artifacts)),
             ('capabilities', formatting.as_raw_list(self.capabilities)),
@@ -667,6 +672,7 @@ class NodeBase(InstanceModelMixin):
         # TODO: validate that node template is of type?
 
         utils.validate_dict_values(self.properties)
+        utils.validate_dict_values(self.attributes)
         utils.validate_dict_values(self.interfaces)
         utils.validate_dict_values(self.artifacts)
         utils.validate_dict_values(self.capabilities)
@@ -674,6 +680,7 @@ class NodeBase(InstanceModelMixin):
 
     def coerce_values(self, container, report_issues):
         utils.coerce_dict_values(self, self.properties, report_issues)
+        utils.coerce_dict_values(self, self.attributes, report_issues)
         utils.coerce_dict_values(self, self.interfaces, report_issues)
         utils.coerce_dict_values(self, self.artifacts, report_issues)
         utils.coerce_dict_values(self, self.capabilities, report_issues)
@@ -686,6 +693,7 @@ class NodeBase(InstanceModelMixin):
             console.puts('Type: 
{0}'.format(context.style.type(self.type.name)))
             console.puts('Template: 
{0}'.format(context.style.node(self.node_template.name)))
             utils.dump_dict_values(self.properties, 'Properties')
+            utils.dump_dict_values(self.attributes, 'Attributes')
             utils.dump_interfaces(self.interfaces)
             utils.dump_dict_values(self.artifacts, 'Artifacts')
             utils.dump_dict_values(self.capabilities, 'Capabilities')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py 
b/aria/modeling/service_template.py
index f1c2bcb..48eeb83 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -503,6 +503,10 @@ class NodeTemplateBase(TemplateModelMixin):
         return relationship.many_to_many(cls, 'parameter', 
prefix='properties', dict_key='name')
 
     @declared_attr
+    def attributes(cls):
+        return relationship.many_to_many(cls, 'parameter', 
prefix='attributes', dict_key='name')
+
+    @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', 
dict_key='name')
 
@@ -543,6 +547,7 @@ class NodeTemplateBase(TemplateModelMixin):
             ('min_instances', self.min_instances),
             ('max_instances', self.max_instances),
             ('properties', formatting.as_raw_dict(self.properties)),
+            ('attributes', formatting.as_raw_dict(self.properties)),
             ('interface_templates', 
formatting.as_raw_list(self.interface_templates)),
             ('artifact_templates', 
formatting.as_raw_list(self.artifact_templates)),
             ('capability_templates', 
formatting.as_raw_list(self.capability_templates)),
@@ -559,13 +564,22 @@ class NodeTemplateBase(TemplateModelMixin):
                            runtime_properties={},
                            node_template=self)
         utils.instantiate_dict(node, node.properties, self.properties)
+        utils.instantiate_dict(node, node.attributes, self.attributes)
         utils.instantiate_dict(node, node.interfaces, self.interface_templates)
         utils.instantiate_dict(node, node.artifacts, self.artifact_templates)
         utils.instantiate_dict(node, node.capabilities, 
self.capability_templates)
+
+        # Default attributes
+        if 'tosca_name' in node.attributes:
+            node.attributes['tosca_name'].value = self.name
+        if 'tosca_id' in node.attributes:
+            node.attributes['tosca_id'].value = name
+
         return node
 
     def validate(self):
         utils.validate_dict_values(self.properties)
+        utils.validate_dict_values(self.attributes)
         utils.validate_dict_values(self.interface_templates)
         utils.validate_dict_values(self.artifact_templates)
         utils.validate_dict_values(self.capability_templates)
@@ -573,6 +587,7 @@ class NodeTemplateBase(TemplateModelMixin):
 
     def coerce_values(self, container, report_issues):
         utils.coerce_dict_values(self, self.properties, report_issues)
+        utils.coerce_dict_values(self, self.attributes, report_issues)
         utils.coerce_dict_values(self, self.interface_templates, report_issues)
         utils.coerce_dict_values(self, self.artifact_templates, report_issues)
         utils.coerce_dict_values(self, self.capability_templates, 
report_issues)
@@ -592,6 +607,7 @@ class NodeTemplateBase(TemplateModelMixin):
                 if self.max_instances is not None
                 else ' or more'))
             utils.dump_dict_values(self.properties, 'Properties')
+            utils.dump_dict_values(self.attributes, 'Attributes')
             utils.dump_interfaces(self.interface_templates)
             utils.dump_dict_values(self.artifact_templates, 'Artifact 
templates')
             utils.dump_dict_values(self.capability_templates, 'Capability 
templates')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/extensions/aria_extension_tosca/simple_v1_0/functions.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/functions.py 
b/extensions/aria_extension_tosca/simple_v1_0/functions.py
index 405aa8f..5057e44 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/functions.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/functions.py
@@ -23,6 +23,7 @@ from aria.parser.validation import Issue
 from aria.modeling.exceptions import CannotEvaluateFunctionException
 from aria.modeling.functions import Function
 
+
 #
 # Intrinsic
 #
@@ -39,8 +40,8 @@ class Concat(Function):
 
         if not isinstance(argument, list):
             raise InvalidValueError(
-                'function "concat" argument must be a list of string 
expressions: %s'
-                % safe_repr(argument),
+                'function "concat" argument must be a list of string 
expressions: {0}'
+                .format(safe_repr(argument)),
                 locator=self.locator)
 
         string_expressions = []
@@ -66,6 +67,7 @@ class Concat(Function):
             value.write(str(e))
         return value.getvalue()
 
+
 @dsl_specification('4.3.2', 'tosca-simple-1.0')
 class Token(Function):
     """
@@ -77,8 +79,8 @@ 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: %s'
-                                    % safe_repr(argument),
+            raise InvalidValueError('function "token" argument must be a list 
of 3 parameters: {0}'
+                                    .format(safe_repr(argument)),
                                     locator=self.locator)
 
         self.string_with_tokens = parse_string_expression(context, 
presentation, 'token', 0,
@@ -104,6 +106,7 @@ class Token(Function):
         if hasattr(string_with_tokens, '_evaluate'):
             string_with_tokens = string_with_tokens._evaluate(context, 
container) # pylint: disable=no-member
 
+
 #
 # Property
 #
@@ -127,8 +130,8 @@ 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: 
%s'
-                    % safe_repr(argument),
+                    'function "get_input" argument is not a valid input name: 
{0}'
+                    .format(safe_repr(argument)),
                     locator=self.locator)
 
     @property
@@ -143,6 +146,7 @@ class GetInput(Function):
             context.modeling.template.inputs.get(self.input_property_name))
         return as_raw(the_input.value) if the_input is not None else None
 
+
 @dsl_specification('4.4.2', 'tosca-simple-1.0')
 class GetProperty(Function):
     """
@@ -156,8 +160,7 @@ 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: '
-                '%s'
-                % safe_repr(argument),
+                '{0}'.format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_modelable_entity_name(context, 
presentation,
@@ -213,10 +216,11 @@ class GetProperty(Function):
                     return as_raw(value)
 
         raise InvalidValueError(
-            'function "get_property" could not find "%s" in modelable entity 
"%s"' \
-            % ('.'.join(self.nested_property_name_or_index), 
self.modelable_entity_name),
+            'function "get_property" could not find "{0}" in modelable entity 
"{1}"'
+            .format('.'.join(self.nested_property_name_or_index), 
self.modelable_entity_name),
             locator=self.locator)
 
+
 #
 # Attribute
 #
@@ -234,8 +238,7 @@ 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:'
-                ' %s'
-                % safe_repr(argument),
+                ' {0}'.format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_modelable_entity_name(context, 
presentation,
@@ -250,6 +253,7 @@ class GetAttribute(Function):
     def _evaluate(self, context, container): # pylint: 
disable=no-self-use,unused-argument
         raise CannotEvaluateFunctionException()
 
+
 #
 # Operation
 #
@@ -266,8 +270,8 @@ 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: %s'
-                % safe_repr(argument),
+                'function "get_operation_output" argument must be a list of 4 
parameters: {0}'
+                .format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_string_expression(context, 
presentation,
@@ -295,6 +299,7 @@ class GetOperationOutput(Function):
         return {'get_operation_output': [self.modelable_entity_name, 
interface_name, operation_name,
                                          output_variable_name]}
 
+
 #
 # Navigation
 #
@@ -316,8 +321,8 @@ 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: %s'
-                    % safe_repr(argument),
+                    'function "get_nodes_of_type" argument is not a valid node 
type name: {0}'
+                    .format(safe_repr(argument)),
                     locator=self.locator)
 
     @property
@@ -330,6 +335,7 @@ class GetNodesOfType(Function):
     def _evaluate(self, context, container):
         pass
 
+
 #
 # Artifact
 #
@@ -346,8 +352,8 @@ 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: %s'
-                % safe_repr(argument),
+                'function "get_artifact" argument must be a list of 2 to 4 
parameters: {0}'
+                .format(safe_repr(argument)),
                 locator=self.locator)
 
         self.modelable_entity_name = parse_string_expression(context, 
presentation, 'get_artifact',
@@ -370,6 +376,7 @@ class GetArtifact(Function):
             location = as_raw(location)
         return {'get_artifacts': [self.modelable_entity_name, artifact_name, 
location, self.remove]}
 
+
 #
 # Utils
 #
@@ -386,6 +393,7 @@ def get_function(context, presentation, value):
                 return True, None
     return False, None
 
+
 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:
@@ -394,6 +402,7 @@ def parse_string_expression(context, presentation, name, 
index, explanation, val
         value = str(value)
     return value
 
+
 def parse_int(context, presentation, name, index, explanation, value): # 
pylint: disable=unused-argument
     if not isinstance(value, int):
         try:
@@ -403,11 +412,13 @@ def parse_int(context, presentation, name, index, 
explanation, value): # pylint:
                                 presentation._locator)
     return value
 
+
 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
 
+
 def parse_modelable_entity_name(context, presentation, name, index, value):
     value = parse_string_expression(context, presentation, name, index, 'the 
modelable entity name',
                                     value)
@@ -436,11 +447,12 @@ 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 "%s" parameter %d is not a valid modelable entity 
name: %s'
-                % (name, index + 1, safe_repr(value)),
+                '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
 
+
 def parse_self(presentation):
     from .templates import NodeTemplate, RelationshipTemplate
     from .types import NodeType, RelationshipType
@@ -455,6 +467,7 @@ def parse_self(presentation):
     else:
         return parse_self(presentation._container)
 
+
 @dsl_specification('4.1', 'tosca-simple-1.0')
 def get_modelable_entities(context, container, locator, modelable_entity_name):
     """
@@ -465,7 +478,7 @@ def get_modelable_entities(context, container, locator, 
modelable_entity_name):
     if modelable_entity_name == 'SELF':
         return get_self(context, container)
     elif modelable_entity_name == 'HOST':
-        return get_host(context, container)
+        return get_hosts(context, container)
     elif modelable_entity_name == 'SOURCE':
         return get_source(context, container)
     elif modelable_entity_name == 'TARGET':
@@ -483,10 +496,11 @@ def get_modelable_entities(context, container, locator, 
modelable_entity_name):
         if modelable_entity_name in relationship_templates:
             return [relationship_templates[modelable_entity_name]]
 
-    raise InvalidValueError('function "get_property" could not find modelable 
entity "%s"'
-                            % modelable_entity_name,
+    raise InvalidValueError('function "get_property" could not find modelable 
entity "{0}"'
+                            .format(modelable_entity_name),
                             locator=locator)
 
+
 def get_self(context, container): # pylint: disable=unused-argument
     """
     A TOSCA orchestrator will interpret this keyword as the Node or 
Relationship Template instance
@@ -495,7 +509,8 @@ def get_self(context, container): # pylint: 
disable=unused-argument
 
     return [container]
 
-def get_host(context, container): # pylint: disable=unused-argument
+
+def get_hosts(context, container): # pylint: disable=unused-argument
     """
     A TOSCA orchestrator will interpret this keyword to refer to the all nodes 
that "host" the node
     using this reference (i.e., as identified by its HostedOn relationship).
@@ -509,6 +524,7 @@ def get_host(context, container): # pylint: 
disable=unused-argument
 
     return []
 
+
 def get_source(context, container): # pylint: disable=unused-argument
     """
     A TOSCA orchestrator will interpret this keyword as the Node Template 
instance that is at the
@@ -517,20 +533,26 @@ def get_source(context, container): # pylint: 
disable=unused-argument
 
     return []
 
+
 def get_target(context, container): # pylint: disable=unused-argument
     """
     A TOSCA orchestrator will interpret this keyword as the Node Template 
instance that is at the
     target end of the relationship that contains the referencing function.
     """
 
+
 def invalid_modelable_entity_name(name, index, value, locator, contexts):
-    return InvalidValueError('function "%s" parameter %d can be "%s" only in 
%s'
-                             % (name, index + 1, value, contexts),
+    return InvalidValueError('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 "%s" %s is not %s%s: %s'
-        % (name, ('parameter %d' % (index + 1)) if index is not None else 
'argument',
-           the_type, (', %s' % explanation) if explanation is not None else 
'', safe_repr(value)),
+        'function "{0}" {1} is not {2}{3}: {4}'
+        .format(name,
+                'parameter {0:d}'.format(index + 1) if index is not None else 
'argument',
+                the_type,
+                ', {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/9de5d979/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 9576260..945f795 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -164,6 +164,8 @@ def create_node_template_model(context, service_template, 
node_template):
 
     create_parameter_models_from_values(model.properties,
                                         
node_template._get_property_values(context))
+    create_parameter_models_from_values(model.attributes,
+                                        
node_template._get_attribute_default_values(context))
     create_interface_template_models(context, service_template, 
model.interface_templates,
                                      node_template._get_interfaces(context))
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/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 99dcfea..6c7b780 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
@@ -327,20 +327,20 @@ def get_data_type_value(context, presentation, 
field_name, type_name):
 
 PRIMITIVE_DATA_TYPES = {
     # YAML 1.2:
-    'tag:yaml.org,2002:str': str,
+    'tag:yaml.org,2002:str': unicode,
     'tag:yaml.org,2002:integer': int,
     'tag:yaml.org,2002:float': float,
     'tag:yaml.org,2002:bool': bool,
     'tag:yaml.org,2002:null': None.__class__,
 
     # TOSCA aliases:
-    'string': str,
+    'string': unicode,
     'integer': int,
     'float': float,
     'boolean': bool,
     'null': None.__class__}
 
-@dsl_specification('3.2.1', 'tosca-simple-1.0')
+@dsl_specification('3.2.1-1', 'tosca-simple-1.0')
 def get_primitive_data_type(type_name):
     """
     Many of the types we use in this profile are built-in types from the YAML 
1.2 specification

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
index f61cb99..9c3ea42 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/properties.py
@@ -58,7 +58,8 @@ def get_inherited_property_definitions(context, presentation, 
field_name, for_pr
 # NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate
 #
 
-def get_assigned_and_defined_property_values(context, presentation):
+def get_assigned_and_defined_property_values(context, presentation, 
field_name='property',
+                                             field_name_plural='properties'):
     """
     Returns the assigned property values while making sure they are defined in 
our type.
 
@@ -70,8 +71,9 @@ def get_assigned_and_defined_property_values(context, 
presentation):
     values = OrderedDict()
 
     the_type = presentation._get_type(context)
-    assignments = presentation.properties
-    definitions = the_type._get_properties(context) if the_type is not None 
else None
+    assignments = getattr(presentation, field_name_plural)
+    get_fn_name = '_get_{0}'.format(field_name_plural)
+    definitions = getattr(the_type, get_fn_name)(context) if the_type is not 
None else None
 
     # Fill in our assignments, but make sure they are defined
     if assignments:
@@ -80,14 +82,14 @@ def get_assigned_and_defined_property_values(context, 
presentation):
                 definition = definitions[name]
                 values[name] = coerce_property_value(context, value, 
definition, value.value)
             else:
-                context.validation.report('assignment to undefined property 
"%s" in "%s"'
-                                          % (name, presentation._fullname),
+                context.validation.report('assignment to undefined {0} "{1}" 
in "{2}"'
+                                          .format(field_name, name, 
presentation._fullname),
                                           locator=value._locator, 
level=Issue.BETWEEN_TYPES)
 
     # Fill in defaults from the definitions
     if definitions:
         for name, definition in definitions.iteritems():
-            if (values.get(name) is None) and (definition.default is not None):
+            if values.get(name) is None:
                 values[name] = coerce_property_value(context, presentation, 
definition,
                                                      definition.default)
 
@@ -181,7 +183,8 @@ def merge_property_definitions(context, presentation, 
property_definitions,
 def coerce_property_value(context, presentation, definition, value, 
aspect=None):
     the_type = definition._get_type(context) if definition is not None else 
None
     entry_schema = definition.entry_schema if definition is not None else None
-    constraints = definition._get_constraints(context) if definition is not 
None else None
+    constraints = definition._get_constraints(context) \
+        if ((definition is not None) and hasattr(definition, 
'_get_constraints')) else None
     value = coerce_value(context, presentation, the_type, entry_schema, 
constraints, value, aspect)
     if (the_type is not None) and hasattr(the_type, '_name'):
         type_name = the_type._name

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9de5d979/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 6860b72..c0f9f23 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/templates.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/templates.py
@@ -26,7 +26,7 @@ from .assignments import (PropertyAssignment, 
AttributeAssignment, RequirementAs
 from .definitions import ParameterDefinition
 from .filters import NodeFilter
 from .misc import (Description, MetaData, Repository, Import, 
SubstitutionMappings)
-from .modeling.properties import get_assigned_and_defined_property_values, 
get_parameter_values
+from .modeling.properties import (get_assigned_and_defined_property_values, 
get_parameter_values)
 from .modeling.interfaces import get_template_interfaces
 from .modeling.requirements import get_template_requirements
 from .modeling.capabilities import get_template_capabilities
@@ -160,6 +160,11 @@ class NodeTemplate(ExtensiblePresentation):
         return FrozenDict(get_assigned_and_defined_property_values(context, 
self))
 
     @cachedmethod
+    def _get_attribute_default_values(self, context):
+        return FrozenDict(get_assigned_and_defined_property_values(context, 
self,
+                                                                   
'attribute', 'attributes'))
+
+    @cachedmethod
     def _get_requirements(self, context):
         return FrozenList(get_template_requirements(context, self))
 

Reply via email to