http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/topology/template_handler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/template_handler.py 
b/aria/orchestrator/topology/template_handler.py
index a84a988..3b1948a 100644
--- a/aria/orchestrator/topology/template_handler.py
+++ b/aria/orchestrator/topology/template_handler.py
@@ -69,7 +69,7 @@ class ServiceTemplate(common.TemplateHandlerBase):
                     plugin = plugin_specification.plugin
                     service.plugins[plugin.name] = plugin
                 else:
-                    self._topology.report('specified plugin not found: 
{0}'.format(
+                    self._topology.report(u'specified plugin not found: 
{0}'.format(
                         plugin_specification.name), 
level=self._topology.Issue.EXTERNAL)
         service.meta_data = self._topology.instantiate(self._model.meta_data)
 
@@ -108,17 +108,18 @@ class ServiceTemplate(common.TemplateHandlerBase):
     def _scaling(self, node_template):
         scaling = node_template.scaling
 
-        if any([scaling['min_instances'] < 0,
+        if any((scaling['min_instances'] < 0,
                 scaling['max_instances'] < scaling['min_instances'],
                 scaling['max_instances'] < 0,
 
                 scaling['default_instances'] < 0,
                 scaling['default_instances'] < scaling['min_instances'],
                 scaling['default_instances'] > scaling['max_instances']
-               ]):
+               )):
             self._topology.report(
-                'invalid scaling parameters for node template "{0}": 
min={min_instances}, max='
-                '{max_instances}, 
default={default_instances}'.format(self._model.name, **scaling),
+                u'invalid scaling parameters for node template "{0}": 
min={min_instances}, max='
+                u'{max_instances}, 
default={default_instances}'.format(node_template.name,
+                                                                       
**scaling),
                 level=self._topology.Issue.BETWEEN_TYPES)
 
         return scaling
@@ -150,18 +151,18 @@ class ArtifactTemplate(common.TemplateHandlerBase):
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
-            out_stream.write('Artifact type: {0}'.format(out_stream.type_style(
+            out_stream.write(u'Artifact type: 
{0}'.format(out_stream.type_style(
                 self._model.type.name)))
-            out_stream.write('Source path: 
{0}'.format(out_stream.literal_style(
+            out_stream.write(u'Source path: 
{0}'.format(out_stream.literal_style(
                 self._model.source_path)))
             if self._model.target_path is not None:
-                out_stream.write('Target path: 
{0}'.format(out_stream.literal_style(
+                out_stream.write(u'Target path: 
{0}'.format(out_stream.literal_style(
                     self._model.target_path)))
             if self._model.repository_url is not None:
-                out_stream.write('Repository URL: {0}'.format(
+                out_stream.write(u'Repository URL: {0}'.format(
                     out_stream.literal_style(self._model.repository_url)))
             if self._model.repository_credential:
-                out_stream.write('Repository credential: {0}'.format(
+                out_stream.write(u'Repository credential: {0}'.format(
                     
out_stream.literal_style(self._model.repository_credential)))
             self._topology.dump(self._model.properties, out_stream, 
title='Properties')
 
@@ -189,17 +190,17 @@ class CapabilityTemplate(common.TemplateHandlerBase):
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
-            out_stream.write('Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
+            out_stream.write(u'Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
             out_stream.write(
-                'Occurrences: {0:d}{1}'.format(
+                u'Occurrences: {0:d}{1}'.format(
                     self._model.min_occurrences or 0,
-                    ' to {0:d}'.format(self._model.max_occurrences)
+                    u' to {0:d}'.format(self._model.max_occurrences)
                     if self._model.max_occurrences is not None
                     else ' or more'))
             if self._model.valid_source_node_types:
-                out_stream.write('Valid source node types: {0}'.format(
-                    ', '.join((str(out_stream.type_style(v.name))
-                               for v in self._model.valid_source_node_types))))
+                out_stream.write(u'Valid source node types: {0}'.format(
+                    u', '.join((str(out_stream.type_style(v.name))
+                                for v in 
self._model.valid_source_node_types))))
             self._topology.dump(self._model.properties, out_stream, 
title='Properties')
 
     def coerce(self, **kwargs):
@@ -228,19 +229,19 @@ class RequirementTemplate(common.TemplateHandlerBase):
             out_stream.write('Requirement:')
         with out_stream.indent():
             if self._model.target_node_type is not None:
-                out_stream.write('Target node type: {0}'.format(
+                out_stream.write(u'Target node type: {0}'.format(
                     out_stream.type_style(self._model.target_node_type.name)))
             elif self._model.target_node_template is not None:
-                out_stream.write('Target node template: {0}'.format(
+                out_stream.write(u'Target node template: {0}'.format(
                     
out_stream.node_style(self._model.target_node_template.name)))
             if self._model.target_capability_type is not None:
-                out_stream.write('Target capability type: {0}'.format(
+                out_stream.write(u'Target capability type: {0}'.format(
                     
out_stream.type_style(self._model.target_capability_type.name)))
             elif self._model.target_capability_name is not None:
-                out_stream.write('Target capability name: {0}'.format(
+                out_stream.write(u'Target capability name: {0}'.format(
                     out_stream.node_style(self._model.target_capability_name)))
             if self._model.target_node_template_constraints:
-                out_stream.write('Target node template constraints:')
+                out_stream.write(u'Target node template constraints:')
                 with out_stream.indent():
                     for constraint in 
self._model.target_node_template_constraints:
                         out_stream.write(out_stream.literal_style(constraint))
@@ -261,16 +262,16 @@ class RequirementTemplate(common.TemplateHandlerBase):
 
 class GroupTemplate(common.TemplateHandlerBase):
     def dump(self, out_stream):
-        out_stream.write('Group template: 
{0}'.format(out_stream.node_style(self._model.name)))
+        out_stream.write(u'Group template: 
{0}'.format(out_stream.node_style(self._model.name)))
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
-            out_stream.write('Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
+            out_stream.write(u'Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
             self._topology.dump(self._model.properties, out_stream, 
title='Properties')
             self._topology.dump(self._model.interface_templates, out_stream,
                                 title='Interface Templates')
             if self._model.node_templates:
-                out_stream.write('Member node templates: {0}'.format(', '.join(
+                out_stream.write(u'Member node templates: {0}'.format(u', 
'.join(
                     (str(out_stream.node_style(v.name)) for v in 
self._model.node_templates))))
 
     def coerce(self, **kwargs):
@@ -303,7 +304,7 @@ class InterfaceTemplate(common.TemplateHandlerBase):
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
-            out_stream.write('Interface type: 
{0}'.format(out_stream.type_style(
+            out_stream.write(u'Interface type: 
{0}'.format(out_stream.type_style(
                 self._model.type.name)))
             self._topology.dump(self._model.inputs, out_stream, title='Inputs')
             self._topology.dump(self._model.operation_templates, out_stream,
@@ -332,11 +333,11 @@ class InterfaceTemplate(common.TemplateHandlerBase):
 
 class NodeTemplate(common.TemplateHandlerBase):
     def dump(self, out_stream):
-        out_stream.write('Node template: 
{0}'.format(out_stream.node_style(self._model.name)))
+        out_stream.write(u'Node template: 
{0}'.format(out_stream.node_style(self._model.name)))
         with out_stream.indent():
             if self._model.description:
                 
out_stream.write(out_stream.meta_style(self._model.description))
-            out_stream.write('Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
+            out_stream.write(u'Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
             self._topology.dump(self._model.properties, out_stream, 
title='Properties')
             self._topology.dump(self._model.attributes, out_stream, 
title='Attributes')
             self._topology.dump(
@@ -391,17 +392,17 @@ class NodeTemplate(common.TemplateHandlerBase):
 
 class PolicyTemplate(common.TemplateHandlerBase):
     def dump(self, out_stream):
-        out_stream.write('Policy template: 
{0}'.format(out_stream.node_style(self._model.name)))
+        out_stream.write(u'Policy template: 
{0}'.format(out_stream.node_style(self._model.name)))
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
-            out_stream.write('Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
+            out_stream.write(u'Type: 
{0}'.format(out_stream.type_style(self._model.type.name)))
             self._topology.dump(self._model.properties, out_stream, 
title='Properties')
             if self._model.node_templates:
-                out_stream.write('Target node templates: {0}'.format(', '.join(
+                out_stream.write(u'Target node templates: {0}'.format(u', 
'.join(
                     (str(out_stream.node_style(v.name)) for v in 
self._model.node_templates))))
             if self._model.group_templates:
-                out_stream.write('Target group templates: {0}'.format(', 
'.join(
+                out_stream.write(u'Target group templates: {0}'.format(u', 
'.join(
                     (str(out_stream.node_style(v.name)) for v in 
self._model.group_templates))))
 
     def coerce(self, **kwargs):
@@ -432,7 +433,7 @@ class SubstitutionTemplate(common.TemplateHandlerBase):
     def dump(self, out_stream):
         out_stream.write('Substitution template:')
         with out_stream.indent():
-            out_stream.write('Node type: {0}'.format(out_stream.type_style(
+            out_stream.write(u'Node type: {0}'.format(out_stream.type_style(
                 self._model.node_type.name)))
             self._topology.dump(self._model.mappings, out_stream, 
title='Mappings')
 
@@ -453,7 +454,7 @@ class 
SubstitutionTemplateMapping(common.TemplateHandlerBase):
             node_template = self._model.capability_template.node_template
         else:
             node_template = self._model.requirement_template.node_template
-        out_stream.write('{0} -> {1}.{2}'.format(
+        out_stream.write(u'{0} -> {1}.{2}'.format(
             out_stream.node_style(self._model.name),
             out_stream.node_style(node_template.name),
             out_stream.node_style(self._model.capability_template.name
@@ -475,7 +476,7 @@ class 
SubstitutionTemplateMapping(common.TemplateHandlerBase):
         nodes = node_template.nodes
         if len(nodes) == 0:
             self._topology.report(
-                'mapping "{0}" refers to node template "{1}" but there are no 
node instances'.
+                u'mapping "{0}" refers to node template "{1}" but there are no 
node instances'.
                 format(self._model.mapped_name, 
self._model.node_template.name),
                 level=self._topology.Issue.BETWEEN_INSTANCES)
             return None
@@ -493,8 +494,8 @@ class 
SubstitutionTemplateMapping(common.TemplateHandlerBase):
     def validate(self, **_):
         if self._model.capability_template is None and 
self._model.requirement_template is None:
             self._topology.report(
-                'mapping "{0}" refers to neither capability nor a requirement '
-                'in node template: {1}'.format(
+                u'mapping "{0}" refers to neither capability nor a requirement 
'
+                u'in node template: {1}'.format(
                     self._model.name, 
formatting.safe_repr(self._model.node_template.name)),
                 level=self._topology.Issue.BETWEEN_TYPES)
 
@@ -502,10 +503,10 @@ class 
SubstitutionTemplateMapping(common.TemplateHandlerBase):
 class RelationshipTemplate(common.TemplateHandlerBase):
     def dump(self, out_stream):
         if self._model.type is not None:
-            out_stream.write('Relationship type: 
{0}'.format(out_stream.type_style(
+            out_stream.write(u'Relationship type: 
{0}'.format(out_stream.type_style(
                 self._model.type.name)))
         else:
-            out_stream.write('Relationship template: {0}'.format(
+            out_stream.write(u'Relationship template: {0}'.format(
                 out_stream.node_style(self._model.name)))
         if self._model.description:
             out_stream.write(out_stream.meta_style(self._model.description))
@@ -539,27 +540,27 @@ class OperationTemplate(common.TemplateHandlerBase):
             out_stream.write(out_stream.meta_style(self._model.description))
         with out_stream.indent():
             if self._model.implementation is not None:
-                out_stream.write('Implementation: {0}'.format(
+                out_stream.write(u'Implementation: {0}'.format(
                     out_stream.literal_style(self._model.implementation)))
             if self._model.dependencies:
-                out_stream.write('Dependencies: {0}'.format(', '.join(
+                out_stream.write(u'Dependencies: {0}'.format(u', '.join(
                     (str(out_stream.literal_style(v)) for v in 
self._model.dependencies))))
             self._topology.dump(self._model.inputs, out_stream, title='Inputs')
             if self._model.executor is not None:
-                out_stream.write('Executor: {0}'.format(
+                out_stream.write(u'Executor: {0}'.format(
                     out_stream.literal_style(self._model.executor)))
             if self._model.max_attempts is not None:
-                out_stream.write('Max attempts: 
{0}'.format(out_stream.literal_style(
+                out_stream.write(u'Max attempts: 
{0}'.format(out_stream.literal_style(
                     self._model.max_attempts)))
             if self._model.retry_interval is not None:
-                out_stream.write('Retry interval: {0}'.format(
+                out_stream.write(u'Retry interval: {0}'.format(
                     out_stream.literal_style(self._model.retry_interval)))
             if self._model.plugin_specification is not None:
-                out_stream.write('Plugin specification: {0}'.format(
+                out_stream.write(u'Plugin specification: {0}'.format(
                     
out_stream.literal_style(self._model.plugin_specification.name)))
             self._topology.dump(self._model.configurations, out_stream, 
title='Configuration')
             if self._model.function is not None:
-                out_stream.write('Function: 
{0}'.format(out_stream.literal_style(
+                out_stream.write(u'Function: 
{0}'.format(out_stream.literal_style(
                     self._model.function)))
 
     def coerce(self, **kwargs):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/topology/topology.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/topology.py 
b/aria/orchestrator/topology/topology.py
index f86c9dd..ef5322e 100644
--- a/aria/orchestrator/topology/topology.py
+++ b/aria/orchestrator/topology/topology.py
@@ -104,7 +104,7 @@ class Topology(issue.ReporterMixin):
 
         # if model is empty, no need to print out the section name
         if model and title:
-            out_stream.write('{0}:'.format(title))
+            out_stream.write(u'{0}:'.format(title))
 
         if isinstance(model, dict):
             if str(out_stream):
@@ -133,18 +133,18 @@ class Topology(issue.ReporterMixin):
     def _dump_graph_node(self, out_stream, node, capability=None):
         out_stream.write(out_stream.node_style(node.name))
         if capability is not None:
-            out_stream.write('{0} 
({1})'.format(out_stream.property_style(capability.name),
-                                                
out_stream.type_style(capability.type.name)))
+            out_stream.write(u'{0} 
({1})'.format(out_stream.property_style(capability.name),
+                                                 
out_stream.type_style(capability.type.name)))
         if node.outbound_relationships:
             with out_stream.indent():
                 for relationship_model in node.outbound_relationships:
                     styled_relationship_name = 
out_stream.property_style(relationship_model.name)
                     if relationship_model.type is not None:
-                        out_stream.write('-> {0} ({1})'.format(
+                        out_stream.write(u'-> {0} ({1})'.format(
                             styled_relationship_name,
                             
out_stream.type_style(relationship_model.type.name)))
                     else:
-                        out_stream.write('-> 
{0}'.format(styled_relationship_name))
+                        out_stream.write(u'-> 
{0}'.format(styled_relationship_name))
                     with out_stream.indent(3):
                         self._dump_graph_node(out_stream,
                                               relationship_model.target_node,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py 
b/aria/orchestrator/workflows/api/task.py
index 6ce4a00..67adc0b 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -78,7 +78,7 @@ class OperationTask(BaseTask):
     :vartype retry_interval: float
     """
 
-    NAME_FORMAT = '{interface}:{operation}@{type}:{name}'
+    NAME_FORMAT = u'{interface}:{operation}@{type}:{name}'
 
     def __init__(self,
                  actor,
@@ -112,8 +112,8 @@ class OperationTask(BaseTask):
         # interface/operation.
         if not has_operation(actor, interface_name, operation_name):
             raise exceptions.OperationNotFoundException(
-                'Could not find operation "{operation_name}" on interface '
-                '"{interface_name}" for {actor_type} "{actor.name}"'.format(
+                u'Could not find operation "{operation_name}" on interface '
+                u'"{interface_name}" for {actor_type} "{actor.name}"'.format(
                     operation_name=operation_name,
                     interface_name=interface_name,
                     actor_type=type(actor).__name__.lower(),
@@ -149,8 +149,8 @@ class OperationTask(BaseTask):
         elif isinstance(actor, models.Relationship):
             self._context_cls = context.operation.RelationshipOperationContext
         else:
-            raise exceptions.TaskCreationException('Could not create valid 
context for '
-                                                   
'{actor.__class__}'.format(actor=actor))
+            raise exceptions.TaskCreationException(u'Could not create valid 
context for '
+                                                   
u'{actor.__class__}'.format(actor=actor))
 
     def __repr__(self):
         return self.name

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/api/task_graph.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task_graph.py 
b/aria/orchestrator/workflows/api/task_graph.py
index eb3967b..0debbb7 100644
--- a/aria/orchestrator/workflows/api/task_graph.py
+++ b/aria/orchestrator/workflows/api/task_graph.py
@@ -52,7 +52,7 @@ class TaskGraph(object):
         self._graph = DiGraph()
 
     def __repr__(self):
-        return '{name}(id={self._id}, name={self.name}, 
graph={self._graph!r})'.format(
+        return u'{name}(id={self._id}, name={self.name}, 
graph={self._graph!r})'.format(            # pylint: 
disable=redundant-keyword-arg
             name=self.__class__.__name__, self=self)
 
     @property
@@ -94,7 +94,7 @@ class TaskGraph(object):
          ``dependent_task`` is not in the graph
         """
         if not self.has_tasks(dependent_task):
-            raise TaskNotInGraphError('Task id: {0}'.format(dependent_task.id))
+            raise TaskNotInGraphError(u'Task id: 
{0}'.format(dependent_task.id))
         for _, dependency_id in self._graph.out_edges(dependent_task.id):
             yield self.get_task(dependency_id)
 
@@ -107,7 +107,7 @@ class TaskGraph(object):
          ``dependency_task`` is not in the graph
         """
         if not self.has_tasks(dependency_task):
-            raise TaskNotInGraphError('Task id: 
{0}'.format(dependency_task.id))
+            raise TaskNotInGraphError(u'Task id: 
{0}'.format(dependency_task.id))
         for dependent_id, _ in self._graph.in_edges(dependency_task.id):
             yield self.get_task(dependent_id)
 
@@ -122,7 +122,7 @@ class TaskGraph(object):
          the graph with the given ID
         """
         if not self._graph.has_node(task_id):
-            raise TaskNotInGraphError('Task id: {0}'.format(task_id))
+            raise TaskNotInGraphError(u'Task id: {0}'.format(task_id))
         data = self._graph.node[task_id]
         return data['task']
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/builtin/execute_operation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/builtin/execute_operation.py 
b/aria/orchestrator/workflows/builtin/execute_operation.py
index 949f864..256927c 100644
--- a/aria/orchestrator/workflows/builtin/execute_operation.py
+++ b/aria/orchestrator/workflows/builtin/execute_operation.py
@@ -60,7 +60,7 @@ def execute_operation(
         for node in ctx.nodes:
             if node.id not in filtered_node_ids:
                 subgraphs[node.id] = ctx.task_graph(
-                    name='execute_operation_stub_{0}'.format(node.id))
+                    name=u'execute_operation_stub_{0}'.format(node.id))
 
     # registering actual tasks to sequences
     for node in filtered_nodes:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/core/engine.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/engine.py 
b/aria/orchestrator/workflows/core/engine.py
index 0d7d2ae..5099041 100644
--- a/aria/orchestrator/workflows/core/engine.py
+++ b/aria/orchestrator/workflows/core/engine.py
@@ -28,7 +28,7 @@ from aria.orchestrator.context import operation
 from .. import exceptions
 from ..executor.base import StubTaskExecutor
 # Import required so all signals are registered
-from . import events_handler  # pylint: disable=unused-import
+from . import events_handler                                                   
                     # pylint: disable=unused-import
 
 
 class Engine(logger.LoggerMixin):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/core/events_handler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/events_handler.py 
b/aria/orchestrator/workflows/core/events_handler.py
index 473475e..067d0c3 100644
--- a/aria/orchestrator/workflows/core/events_handler.py
+++ b/aria/orchestrator/workflows/core/events_handler.py
@@ -166,5 +166,5 @@ def _update_node_state_if_necessary(ctx, 
is_transitional=False):
 
 def _log_tried_to_cancel_execution_but_it_already_ended(workflow_context, 
status):
     workflow_context.logger.info(
-        "'{workflow_name}' workflow execution {status} before the cancel 
request"
-        "was fully 
processed".format(workflow_name=workflow_context.workflow_name, status=status))
+        u"'{workflow_name}' workflow execution {status} before the cancel 
request"
+        u"was fully 
processed".format(workflow_name=workflow_context.workflow_name, status=status))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/core/graph_compiler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/graph_compiler.py 
b/aria/orchestrator/workflows/core/graph_compiler.py
index 81543d5..83fbfea 100644
--- a/aria/orchestrator/workflows/core/graph_compiler.py
+++ b/aria/orchestrator/workflows/core/graph_compiler.py
@@ -90,11 +90,11 @@ class GraphCompiler(object):
 
     @staticmethod
     def _start_graph_suffix(api_id):
-        return '{0}-Start'.format(api_id)
+        return u'{0}-Start'.format(api_id)
 
     @staticmethod
     def _end_graph_suffix(api_id):
-        return '{0}-End'.format(api_id)
+        return u'{0}-End'.format(api_id)
 
     @staticmethod
     def _get_non_dependent_tasks(execution):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/events_logging.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/events_logging.py 
b/aria/orchestrator/workflows/events_logging.py
index 9eee1e1..1099091 100644
--- a/aria/orchestrator/workflows/events_logging.py
+++ b/aria/orchestrator/workflows/events_logging.py
@@ -24,7 +24,7 @@ from ... import modeling
 
 def _get_task_name(task):
     if isinstance(task.actor, 
modeling.model_bases.service_instance.RelationshipBase):
-        return '{source_node.name}->{target_node.name}'.format(
+        return u'{source_node.name}->{target_node.name}'.format(
             source_node=task.actor.source_node, 
target_node=task.actor.target_node)
     else:
         return task.actor.name
@@ -40,7 +40,7 @@ def _start_task_handler(ctx, **kwargs):
         suffix = 'has no implementation'
         logger = ctx.logger.debug
 
-    logger('{name} {task.interface_name}.{task.operation_name} 
{suffix}'.format(
+    logger(u'{name} {task.interface_name}.{task.operation_name} 
{suffix}'.format(
         name=_get_task_name(ctx.task), task=ctx.task, suffix=suffix))
 
 
@@ -48,38 +48,38 @@ def _start_task_handler(ctx, **kwargs):
 def _success_task_handler(ctx, **kwargs):
     if not ctx.task.function:
         return
-    ctx.logger.info('{name} {task.interface_name}.{task.operation_name} 
successful'
+    ctx.logger.info(u'{name} {task.interface_name}.{task.operation_name} 
successful'
                     .format(name=_get_task_name(ctx.task), task=ctx.task))
 
 
 @events.on_failure_task_signal.connect
 def _failure_operation_handler(ctx, traceback, **kwargs):
     ctx.logger.error(
-        '{name} {task.interface_name}.{task.operation_name} failed'
+        u'{name} {task.interface_name}.{task.operation_name} failed'
         .format(name=_get_task_name(ctx.task), task=ctx.task), 
extra=dict(traceback=traceback)
     )
 
 
 @events.start_workflow_signal.connect
 def _start_workflow_handler(context, **kwargs):
-    context.logger.info("Starting '{ctx.workflow_name}' workflow 
execution".format(ctx=context))
+    context.logger.info(u"Starting '{ctx.workflow_name}' workflow 
execution".format(ctx=context))
 
 
 @events.on_failure_workflow_signal.connect
 def _failure_workflow_handler(context, **kwargs):
-    context.logger.info("'{ctx.workflow_name}' workflow execution 
failed".format(ctx=context))
+    context.logger.info(u"'{ctx.workflow_name}' workflow execution 
failed".format(ctx=context))
 
 
 @events.on_success_workflow_signal.connect
 def _success_workflow_handler(context, **kwargs):
-    context.logger.info("'{ctx.workflow_name}' workflow execution 
succeeded".format(ctx=context))
+    context.logger.info(u"'{ctx.workflow_name}' workflow execution 
succeeded".format(ctx=context))
 
 
 @events.on_cancelled_workflow_signal.connect
 def _cancel_workflow_handler(context, **kwargs):
-    context.logger.info("'{ctx.workflow_name}' workflow execution 
canceled".format(ctx=context))
+    context.logger.info(u"'{ctx.workflow_name}' workflow execution 
canceled".format(ctx=context))
 
 
 @events.on_cancelling_workflow_signal.connect
 def _cancelling_workflow_handler(context, **kwargs):
-    context.logger.info("Cancelling '{ctx.workflow_name}' workflow 
execution".format(ctx=context))
+    context.logger.info(u"Cancelling '{ctx.workflow_name}' workflow 
execution".format(ctx=context))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/exceptions.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/exceptions.py 
b/aria/orchestrator/workflows/exceptions.py
index 2a1d6b1..6fce81c 100644
--- a/aria/orchestrator/workflows/exceptions.py
+++ b/aria/orchestrator/workflows/exceptions.py
@@ -55,10 +55,10 @@ class ProcessException(ExecutorException):
         Describes the error in detail
         """
         return (
-            'Command "{error.command}" executed with an error.{0}'
-            'code: {error.return_code}{0}'
-            'error: {error.stderr}{0}'
-            'output: {error.stdout}'.format(os.linesep, error=self))
+            u'Command "{error.command}" executed with an error.{0}'
+            u'code: {error.return_code}{0}'
+            u'error: {error.stderr}{0}'
+            u'output: {error.stdout}'.format(os.linesep, error=self))
 
 
 class AriaEngineError(exceptions.AriaError):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/executor/celery.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/celery.py 
b/aria/orchestrator/workflows/executor/celery.py
index a2b3513..aab84ec 100644
--- a/aria/orchestrator/workflows/executor/celery.py
+++ b/aria/orchestrator/workflows/executor/celery.py
@@ -89,7 +89,7 @@ class CeleryExecutor(BaseExecutor):
             exception = async_result.result
         except BaseException as e:
             exception = RuntimeError(
-                'Could not de-serialize exception of task {0} --> {1}: {2}'
+                u'Could not de-serialize exception of task {0} --> {1}: {2}'
                 .format(task.name, type(e).__name__, str(e)))
         self._task_failed(task, exception=exception)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/executor/dry.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/dry.py 
b/aria/orchestrator/workflows/executor/dry.py
index 9314e5d..bdb0eaf 100644
--- a/aria/orchestrator/workflows/executor/dry.py
+++ b/aria/orchestrator/workflows/executor/dry.py
@@ -22,7 +22,7 @@ from datetime import datetime
 from . import base
 
 
-class DryExecutor(base.BaseExecutor):                                          
                          # pylint: disable=abstract-method
+class DryExecutor(base.BaseExecutor):                                          
                     # pylint: disable=abstract-method
     """
     Dry task executor: prints task information without causing any side 
effects.
     """
@@ -33,11 +33,11 @@ class DryExecutor(base.BaseExecutor):
             ctx.task.started_at = datetime.utcnow()
             ctx.task.status = ctx.task.STARTED
 
-            dry_msg = '<dry> {name} 
{task.interface_name}.{task.operation_name} {suffix}'
+            dry_msg = u'<dry> {name} 
{task.interface_name}.{task.operation_name} {suffix}'
             logger = ctx.logger.info if ctx.task.function else ctx.logger.debug
 
             if hasattr(ctx.task.actor, 'source_node'):
-                name = '{source_node.name}->{target_node.name}'.format(
+                name = u'{source_node.name}->{target_node.name}'.format(
                     source_node=ctx.task.actor.source_node, 
target_node=ctx.task.actor.target_node)
             else:
                 name = ctx.task.actor.name

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/executor/process.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/process.py 
b/aria/orchestrator/workflows/executor/process.py
index 185f15f..4143127 100644
--- a/aria/orchestrator/workflows/executor/process.py
+++ b/aria/orchestrator/workflows/executor/process.py
@@ -23,8 +23,8 @@ import os
 import sys
 
 # As part of the process executor implementation, subprocess are started with 
this module as their
-# entry point. We thus remove this module's directory from the python path if 
it happens to be
-# there
+# entry point. We thus remove this module's directory from the Python path if 
it happens to be
+# there.
 
 from collections import namedtuple
 
@@ -201,11 +201,11 @@ class ProcessExecutor(base.BaseExecutor):
                         break
                     request_handler = self._request_handlers.get(request_type)
                     if not request_handler:
-                        raise RuntimeError('Invalid request type: 
{0}'.format(request_type))
+                        raise RuntimeError(u'Invalid request type: 
{0}'.format(request_type))
                     task_id = request['task_id']
                     request_handler(task_id=task_id, request=request, 
response=response)
             except BaseException as e:
-                self.logger.debug('Error in process executor listener: 
{0}'.format(e))
+                self.logger.debug(u'Error in process executor listener: 
{0}'.format(e))
 
     @contextlib.contextmanager
     def _accept_request(self):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/orchestrator/workflows/executor/thread.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/thread.py 
b/aria/orchestrator/workflows/executor/thread.py
index 170620e..5786a04 100644
--- a/aria/orchestrator/workflows/executor/thread.py
+++ b/aria/orchestrator/workflows/executor/thread.py
@@ -43,7 +43,7 @@ class ThreadExecutor(BaseExecutor):
         self._queue = Queue.Queue()
         self._pool = []
         for i in range(pool_size):
-            name = 'ThreadExecutor-{index}'.format(index=i+1)
+            name = 'ThreadExecutor-{0:d}'.format(i+1)
             thread = threading.Thread(target=self._processor, name=name)
             thread.daemon = True
             thread.start()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/consumption/context.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/context.py 
b/aria/parser/consumption/context.py
index 9164984..91807a4 100644
--- a/aria/parser/consumption/context.py
+++ b/aria/parser/consumption/context.py
@@ -83,14 +83,14 @@ class ConsumptionContext(object):
         try:
             self.out.write(string)
         except UnicodeEncodeError:
-            self.out.write(string.encode('utf8'))
+            self.out.write(string.encode('utf-8'))
 
     def has_arg_switch(self, name):
-        name = '--%s' % name
+        name = '--{0}'.format(name)
         return name in self.args
 
     def get_arg_value(self, name, default=None):
-        name = '--%s=' % name
+        name = '--{0}='.format(name)
         for arg in self.args:
             if arg.startswith(name):
                 return arg[len(name):]

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/consumption/inputs.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/inputs.py 
b/aria/parser/consumption/inputs.py
index fe7e192..55f6e92 100644
--- a/aria/parser/consumption/inputs.py
+++ b/aria/parser/consumption/inputs.py
@@ -46,7 +46,7 @@ class Inputs(Consumer):
 
         if not isinstance(inputs, dict):
             self.context.validation.report(
-                'Inputs consumer: inputs are not a dict: %s' % 
safe_repr(inputs))
+                u'Inputs consumer: inputs are not a dict: 
{0}'.format(safe_repr(inputs)))
             return
 
         for name, value in inputs.iteritems():

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/consumption/presentation.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/presentation.py 
b/aria/parser/consumption/presentation.py
index 542b3f0..b1f943d 100644
--- a/aria/parser/consumption/presentation.py
+++ b/aria/parser/consumption/presentation.py
@@ -13,15 +13,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
-from ...utils.threading import FixedThreadPoolExecutor
-from ...utils.formatting import json_dumps, yaml_dumps
+from ...utils.formatting import (json_dumps, yaml_dumps)
 from ..loading import UriLocation
-from ..reading import AlreadyReadException
 from ..presentation import PresenterNotFoundError
 from .consumer import Consumer
 
 
+PRESENTATION_CACHE = {}
+CANONICAL_LOCATION_CACHE = {}
+
+
 class Read(Consumer):
     """
     Reads the presentation, handling imports recursively.
@@ -31,7 +32,7 @@ class Read(Consumer):
     instances.
 
     It supports agnostic raw data composition for presenters that have
-    ``_get_import_locations`` and ``_merge_import``.
+    ``_get_import_locations``, ``_validate_import``, and ``_merge_import``.
 
     To improve performance, loaders are called asynchronously on separate 
threads.
 
@@ -39,39 +40,25 @@ class Read(Consumer):
     cycle, for example if the agnostic raw data has dependencies that must 
also be parsed.
     """
 
-    def consume(self):
-        if self.context.presentation.location is None:
-            self.context.validation.report('Presentation consumer: missing 
location')
-            return
-
-        presenter = None
-        imported_presentations = None
+    def __init__(self, context):
+        super(Read, self).__init__(context)
+        self._cache = {}
 
-        executor = 
FixedThreadPoolExecutor(size=self.context.presentation.threads,
-                                           
timeout=self.context.presentation.timeout)
-        executor.print_exceptions = self.context.presentation.print_exceptions
-        try:
-            presenter = self._present(self.context.presentation.location, 
None, None, executor)
-            executor.drain()
-
-            # Handle exceptions
-            for e in executor.exceptions:
-                self._handle_exception(e)
+    def consume(self):
+        # Present the main location and all imports recursively
+        main, results = self._present_all()
 
-            imported_presentations = executor.returns
-        finally:
-            executor.close()
+        # Merge presentations
+        main.merge(results, self.context)
 
-        # Merge imports
-        if (imported_presentations is not None) and hasattr(presenter, 
'_merge_import'):
-            for imported_presentation in imported_presentations:
-                okay = True
-                if hasattr(presenter, '_validate_import'):
-                    okay = presenter._validate_import(self.context, 
imported_presentation)
-                if okay:
-                    presenter._merge_import(imported_presentation)
+        # Cache merged presentations
+        if self.context.presentation.cache:
+            for result in results:
+                result.cache()
 
-        self.context.presentation.presenter = presenter
+        self.context.presentation.presenter = main.presentation
+        if main.canonical_location is not None:
+            self.context.presentation.location = main.canonical_location
 
     def dump(self):
         if self.context.has_arg_switch('yaml'):
@@ -86,52 +73,193 @@ class Read(Consumer):
             self.context.presentation.presenter._dump(self.context)
 
     def _handle_exception(self, e):
-        if isinstance(e, AlreadyReadException):
+        if isinstance(e, _Skip):
             return
         super(Read, self)._handle_exception(e)
 
-    def _present(self, location, origin_location, presenter_class, executor):
+    def _present_all(self):
+        location = self.context.presentation.location
+
+        if location is None:
+            self.context.validation.report('Read consumer: missing location')
+            return
+
+        executor = self.context.presentation.create_executor()
+        try:
+            # This call may recursively submit tasks to the executor if there 
are imports
+            main = self._present(location, None, None, executor)
+
+            # Wait for all tasks to complete
+            executor.drain()
+
+            # Handle exceptions
+            for e in executor.exceptions:
+                self._handle_exception(e)
+
+            results = executor.returns or []
+        finally:
+            executor.close()
+
+        results.insert(0, main)
+
+        return main, results
+
+    def _present(self, location, origin_canonical_location, 
origin_presenter_class, executor):
         # Link the context to this thread
         self.context.set_thread_local()
 
-        raw = self._read(location, origin_location)
+        # Canonicalize the location
+        if self.context.reading.reader is None:
+            loader, canonical_location = self._create_loader(location, 
origin_canonical_location)
+        else:
+            # If a reader is specified in the context then we skip loading
+            loader = None
+            canonical_location = location
+
+        # Skip self imports
+        if canonical_location == origin_canonical_location:
+            raise _Skip()
+
+        if self.context.presentation.cache:
+            # Is the presentation in the global cache?
+            try:
+                presentation = PRESENTATION_CACHE[canonical_location]
+                return _Result(presentation, canonical_location, 
origin_canonical_location)
+            except KeyError:
+                pass
+
+        try:
+            # Is the presentation in the local cache?
+            presentation = self._cache[canonical_location]
+            return _Result(presentation, canonical_location, 
origin_canonical_location)
+        except KeyError:
+            pass
+
+        # Create and cache new presentation
+        presentation = self._create_presentation(canonical_location, loader, 
origin_presenter_class)
+        self._cache[canonical_location] = presentation
 
+        # Submit imports to executor
+        if hasattr(presentation, '_get_import_locations'):
+            import_locations = presentation._get_import_locations(self.context)
+            if import_locations:
+                for import_location in import_locations:
+                    import_location = UriLocation(import_location)
+                    executor.submit(self._present, import_location, 
canonical_location,
+                                    presentation.__class__, executor)
+
+        return _Result(presentation, canonical_location, 
origin_canonical_location)
+
+    def _create_loader(self, location, origin_canonical_location):
+        loader = 
self.context.loading.loader_source.get_loader(self.context.loading, location,
+                                                               
origin_canonical_location)
+
+        canonical_location = None
+
+        if origin_canonical_location is not None:
+            cache_key = (origin_canonical_location, location)
+            try:
+                canonical_location = CANONICAL_LOCATION_CACHE[cache_key]
+                return loader, canonical_location
+            except KeyError:
+                pass
+        else:
+            cache_key = None
+
+        canonical_location = loader.get_canonical_location()
+
+        # Because retrieving the canonical location can be costly, we will try 
to cache it
+        if cache_key is not None:
+            CANONICAL_LOCATION_CACHE[cache_key] = canonical_location
+
+        return loader, canonical_location
+
+    def _create_presentation(self, canonical_location, loader, 
default_presenter_class):
+        # The reader we specified in the context will override
+        reader = self.context.reading.reader
+
+        if reader is None:
+            # Read raw data from loader
+            reader = 
self.context.reading.reader_source.get_reader(self.context.reading,
+                                                                   
canonical_location, loader)
+
+        raw = reader.read()
+
+        # Wrap raw data in presenter class
         if self.context.presentation.presenter_class is not None:
-            # The presenter class we specified in the context overrides 
everything
+            # The presenter class we specified in the context will override
             presenter_class = self.context.presentation.presenter_class
         else:
             try:
                 presenter_class = 
self.context.presentation.presenter_source.get_presenter(raw)
             except PresenterNotFoundError:
-                if presenter_class is None:
+                if default_presenter_class is None:
                     raise
-            # We'll use the presenter class we were given (from the presenter 
that imported us)
-            if presenter_class is None:
-                raise PresenterNotFoundError('presenter not found')
+                else:
+                    presenter_class = default_presenter_class
+
+        if presenter_class is None:
+            raise PresenterNotFoundError(u'presenter not found: 
{0}'.format(canonical_location))
 
         presentation = presenter_class(raw=raw)
 
-        if presentation is not None and hasattr(presentation, 
'_link_locators'):
+        if hasattr(presentation, '_link_locators'):
             presentation._link_locators()
 
-        # Submit imports to executor
-        if hasattr(presentation, '_get_import_locations'):
-            import_locations = presentation._get_import_locations(self.context)
-            if import_locations:
-                for import_location in import_locations:
-                    # The imports inherit the parent presenter class and use 
the current location as
-                    # their origin location
-                    import_location = UriLocation(import_location)
-                    executor.submit(self._present, import_location, location, 
presenter_class,
-                                    executor)
-
         return presentation
 
-    def _read(self, location, origin_location):
-        if self.context.reading.reader is not None:
-            return self.context.reading.reader.read()
-        loader = 
self.context.loading.loader_source.get_loader(self.context.loading, location,
-                                                               origin_location)
-        reader = 
self.context.reading.reader_source.get_reader(self.context.reading, location,
-                                                               loader)
-        return reader.read()
+
+class _Result(object):
+    def __init__(self, presentation, canonical_location, 
origin_canonical_location):
+        self.presentation = presentation
+        self.canonical_location = canonical_location
+        self.origin_canonical_location = origin_canonical_location
+        self.merged = False
+
+    def get_imports(self, results):
+        imports = []
+
+        def has_import(result):
+            for i in imports:
+                if i.canonical_location == result.canonical_location:
+                    return True
+            return False
+
+        for result in results:
+            if result.origin_canonical_location == self.canonical_location:
+                if not has_import(result):
+                    imports.append(result)
+        return imports
+
+    def merge(self, results, context):
+        # Make sure to only merge each presentation once
+        if self.merged:
+            return
+        self.merged = True
+        for result in results:
+            if result.presentation == self.presentation:
+                result.merged = True
+
+        for result in self.get_imports(results):
+            # Make sure import is merged
+            result.merge(results, context)
+
+            # Validate import
+            if hasattr(self.presentation, '_validate_import'):
+                if not self.presentation._validate_import(context, 
result.presentation):
+                    # _validate_import will report an issue if invalid
+                    continue
+
+            # Merge import
+            if hasattr(self.presentation, '_merge_import'):
+                self.presentation._merge_import(result.presentation)
+
+    def cache(self):
+        if not self.merged:
+            raise RuntimeError(u'Only merged presentations can be cached: {0}'
+                               .format(self.canonical_location))
+        PRESENTATION_CACHE[self.canonical_location] = self.presentation
+
+
+class _Skip(Exception):
+    pass

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/consumption/validation.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/validation.py 
b/aria/parser/consumption/validation.py
index a7bc3b8..dd145ce 100644
--- a/aria/parser/consumption/validation.py
+++ b/aria/parser/consumption/validation.py
@@ -24,7 +24,7 @@ class Validate(Consumer):
 
     def consume(self):
         if self.context.presentation.presenter is None:
-            self.context.validation.report('Validation consumer: missing 
presenter')
+            self.context.validation.report('Validate consumer: missing 
presenter')
             return
 
         self.context.presentation.presenter._validate(self.context)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/file.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/file.py b/aria/parser/loading/file.py
index a02bd69..f6fd284 100644
--- a/aria/parser/loading/file.py
+++ b/aria/parser/loading/file.py
@@ -38,27 +38,28 @@ class FileTextLoader(Loader):
             self._file = codecs.open(self.path, mode='r', 
encoding=self.encoding, buffering=1)
         except IOError as e:
             if e.errno == 2:
-                raise DocumentNotFoundException('file not found: "%s"' % 
self.path, cause=e)
+                raise DocumentNotFoundException(u'file not found: 
"{0}"'.format(self.path), cause=e)
             else:
-                raise LoaderException('file I/O error: "%s"' % self.path, 
cause=e)
+                raise LoaderException(u'file I/O error: 
"{0}"'.format(self.path), cause=e)
         except Exception as e:
-            raise LoaderException('file error: "%s"' % self.path, cause=e)
+            raise LoaderException(u'file error: "{0}"'.format(self.path), 
cause=e)
 
     def close(self):
         if self._file is not None:
             try:
                 self._file.close()
             except IOError as e:
-                raise LoaderException('file I/O error: "%s"' % self.path, 
cause=e)
+                raise LoaderException(u'file I/O error: 
"{0}"'.format(self.path), cause=e)
             except Exception as e:
-                raise LoaderException('file error: "%s"' % self.path, cause=e)
+                raise LoaderException(u'file error: "{0}"'.format(self.path), 
cause=e)
+            self._file = None
 
     def load(self):
         if self._file is not None:
             try:
                 return self._file.read()
             except IOError as e:
-                raise LoaderException('file I/O error: "%s"' % self.path, 
cause=e)
+                raise LoaderException(u'file I/O error: 
"{0}"'.format(self.path), cause=e)
             except Exception as e:
-                raise LoaderException('file error %s' % self.path, cause=e)
+                raise LoaderException(u'file error {0}'.format(self.path), 
cause=e)
         return None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/literal.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/literal.py b/aria/parser/loading/literal.py
index 7865008..208ab53 100644
--- a/aria/parser/loading/literal.py
+++ b/aria/parser/loading/literal.py
@@ -29,3 +29,6 @@ class LiteralLoader(Loader):
 
     def load(self):
         return self.location.content
+
+    def get_canonical_location(self):
+        return self.location

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/loader.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/loader.py b/aria/parser/loading/loader.py
index e1abfbf..a1dc3c6 100644
--- a/aria/parser/loading/loader.py
+++ b/aria/parser/loading/loader.py
@@ -32,3 +32,6 @@ class Loader(object):
 
     def load(self):
         raise NotImplementedError
+
+    def get_canonical_location(self):                                          
                     # pylint: disable=no-self-use
+        return None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/location.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/location.py b/aria/parser/loading/location.py
index 902e856..255f650 100644
--- a/aria/parser/loading/location.py
+++ b/aria/parser/loading/location.py
@@ -27,9 +27,6 @@ class Location(object):
     an appropriate :class:`~aria.parser.loading.Loader`.
     """
 
-    def is_equivalent(self, location):
-        raise NotImplementedError
-
     @property
     def prefix(self):
         return None
@@ -47,15 +44,12 @@ class UriLocation(Location):
     def __init__(self, uri):
         self.uri = uri
 
-    def is_equivalent(self, location):
-        return isinstance(location, UriLocation) and (location.uri == self.uri)
-
     @property
     def prefix(self):
         prefix = os.path.dirname(self.uri)
         if prefix and (as_file(prefix) is None):
-            # Yes, it's weird, but dirname handles URIs,
-            # too: http://stackoverflow.com/a/35616478/849021
+            # Yes, it's weird, but dirname handles URIs, too:
+            # http://stackoverflow.com/a/35616478/849021
             # We just need to massage it with a trailing slash
             prefix += '/'
         return prefix
@@ -63,6 +57,12 @@ class UriLocation(Location):
     def __str__(self):
         return self.uri
 
+    def __eq__(self, other):
+        return isinstance(other, UriLocation) and (other.uri == self.uri)
+
+    def __hash__(self):
+        return hash(self.uri)
+
 
 class LiteralLocation(Location):
     """
@@ -75,8 +75,11 @@ class LiteralLocation(Location):
         self.content = content
         self.name = name
 
-    def is_equivalent(self, location):
-        return isinstance(location, LiteralLocation) and (location.content == 
self.content)
-
     def __str__(self):
-        return '<%s>' % self.name
+        return u'<{0}>'.format(self.name)
+
+    def __eq__(self, other):
+        return isinstance(other, LiteralLocation) and (other.content == 
self.content)
+
+    def __hash__(self):
+        return hash(self.content)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/request.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/request.py b/aria/parser/loading/request.py
index a809347..5f12055 100644
--- a/aria/parser/loading/request.py
+++ b/aria/parser/loading/request.py
@@ -57,19 +57,19 @@ class RequestLoader(Loader):
         try:
             self._response = SESSION.get(self.uri, headers=self.headers)
         except InvalidSchema as e:
-            raise DocumentNotFoundException('document not found: "%s"' % 
self.uri, cause=e)
+            raise DocumentNotFoundException(u'document not found: 
"{0}"'.format(self.uri), cause=e)
         except ConnectionError as e:
-            raise LoaderException('request connection error: "%s"' % self.uri, 
cause=e)
+            raise LoaderException(u'request connection error: 
"{0}"'.format(self.uri), cause=e)
         except Exception as e:
-            raise LoaderException('request error: "%s"' % self.uri, cause=e)
+            raise LoaderException(u'request error: "{0}"'.format(self.uri), 
cause=e)
 
         status = self._response.status_code
         if status == 404:
             self._response = None
-            raise DocumentNotFoundException('document not found: "%s"' % 
self.uri)
+            raise DocumentNotFoundException(u'document not found: 
"{0}"'.format(self.uri))
         elif status != 200:
             self._response = None
-            raise LoaderException('request error %d: "%s"' % (status, 
self.uri))
+            raise LoaderException(u'request error {0:d}: "{1}"'.format(status, 
self.uri))
 
 
 class RequestTextLoader(RequestLoader):
@@ -81,8 +81,8 @@ class RequestTextLoader(RequestLoader):
         if self._response is not None:
             try:
                 if self._response.encoding is None:
-                    self._response.encoding = 'utf8'
+                    self._response.encoding = 'utf-8'
                 return self._response.text
             except Exception as e:
-                raise LoaderException('request error: %s' % self.uri, cause=e)
+                raise LoaderException(u'request error: {0}'.format(self.uri), 
cause=e)
         return None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/loading/uri.py
----------------------------------------------------------------------
diff --git a/aria/parser/loading/uri.py b/aria/parser/loading/uri.py
index a5a18e6..83f5ced 100644
--- a/aria/parser/loading/uri.py
+++ b/aria/parser/loading/uri.py
@@ -20,6 +20,7 @@ from ...extension import parser
 from ...utils.collections import StrictList
 from ...utils.uris import as_file
 from .loader import Loader
+from .location import UriLocation
 from .file import FileTextLoader
 from .request import RequestTextLoader
 from .exceptions import DocumentNotFoundException
@@ -44,6 +45,7 @@ class UriTextLoader(Loader):
         self.location = location
         self._prefixes = StrictList(value_class=basestring)
         self._loader = None
+        self._canonical_location = None
 
         def add_prefix(prefix):
             if prefix and (prefix not in self._prefixes):
@@ -60,23 +62,27 @@ class UriTextLoader(Loader):
         add_prefixes(parser.uri_loader_prefix())
 
     def open(self):
-        try:
-            self._open(self.location.uri)
-            return
-        except DocumentNotFoundException:
-            # Try prefixes in order
-            for prefix in self._prefixes:
-                prefix_as_file = as_file(prefix)
-                if prefix_as_file is not None:
-                    uri = os.path.join(prefix_as_file, self.location.uri)
-                else:
-                    uri = urljoin(prefix, self.location.uri)
-                try:
-                    self._open(uri)
-                    return
-                except DocumentNotFoundException:
-                    pass
-        raise DocumentNotFoundException('document not found at URI: "%s"' % 
self.location)
+        if self._loader is not None:
+            self._loader.open()
+        else:
+            try:
+                self._open(self.location.uri)
+                return
+            except DocumentNotFoundException:
+                # Try prefixes in order
+                for prefix in self._prefixes:
+                    prefix_as_file = as_file(prefix)
+                    if prefix_as_file is not None:
+                        uri = os.path.join(prefix_as_file, self.location.uri)
+                    else:
+                        uri = urljoin(prefix, self.location.uri)
+                    try:
+                        self._open(uri)
+                        return
+                    except DocumentNotFoundException:
+                        pass
+            raise DocumentNotFoundException(u'document not found at URI: "{0}"'
+                                            .format(self.location))
 
     def close(self):
         if self._loader is not None:
@@ -85,6 +91,11 @@ class UriTextLoader(Loader):
     def load(self):
         return self._loader.load() if self._loader is not None else None
 
+    def get_canonical_location(self):
+        self.open()
+        self.close()
+        return self._canonical_location
+
     def _open(self, uri):
         the_file = as_file(uri)
         if the_file is not None:
@@ -94,4 +105,4 @@ class UriTextLoader(Loader):
             loader = RequestTextLoader(self.context, uri)
         loader.open() # might raise an exception
         self._loader = loader
-        self.location.uri = uri
+        self._canonical_location = UriLocation(uri)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/presentation/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/__init__.py 
b/aria/parser/presentation/__init__.py
index 5633e7b..aa5439c 100644
--- a/aria/parser/presentation/__init__.py
+++ b/aria/parser/presentation/__init__.py
@@ -69,6 +69,7 @@ Field validators
 .. autosummary::
    :nosignatures:
 
+   aria.parser.presentation.not_negative_validator
    aria.parser.presentation.type_validator
    aria.parser.presentation.list_type_validator
    aria.parser.presentation.list_length_validator
@@ -93,19 +94,19 @@ Utilities
    aria.parser.presentation.report_issue_for_circular_type_hierarchy
 """
 
-from .exceptions import PresenterException, PresenterNotFoundError
+from .exceptions import (PresenterException, PresenterNotFoundError)
 from .context import PresentationContext
 from .presenter import Presenter
-from .presentation import Value, PresentationBase, Presentation, 
AsIsPresentation
-from .source import PresenterSource, DefaultPresenterSource
-from .null import NULL, none_to_null, null_to_none
+from .presentation import (Value, PresentationBase, Presentation, 
AsIsPresentation)
+from .source import (PresenterSource, DefaultPresenterSource)
+from .null import (NULL, none_to_null, null_to_none)
 from .fields import (Field, has_fields, short_form_field, 
allow_unknown_fields, primitive_field,
                      primitive_list_field, primitive_dict_field, 
primitive_dict_unknown_fields,
                      object_field, object_list_field, object_dict_field,
                      object_sequenced_list_field, object_dict_unknown_fields, 
field_getter,
                      field_setter, field_validator)
-from .field_validators import (type_validator, list_type_validator, 
list_length_validator,
-                               derived_from_validator)
+from .field_validators import (not_negative_validator, type_validator, 
list_type_validator,
+                               list_length_validator, derived_from_validator)
 from .utils import (get_locator, parse_types_dict_names, validate_primitive, 
validate_no_short_form,
                     validate_no_unknown_fields, validate_known_fields, 
get_parent_presentation,
                     report_issue_for_unknown_type, 
report_issue_for_unknown_parent_type,
@@ -141,6 +142,7 @@ __all__ = (
     'field_getter',
     'field_setter',
     'field_validator',
+    'not_negative_validator',
     'type_validator',
     'list_type_validator',
     'list_length_validator',

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/presentation/context.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/context.py 
b/aria/parser/presentation/context.py
index 44a6f82..bf7123a 100644
--- a/aria/parser/presentation/context.py
+++ b/aria/parser/presentation/context.py
@@ -15,6 +15,7 @@
 
 
 from .source import DefaultPresenterSource
+from ...utils.threading import (BlockingExecutor, FixedThreadPoolExecutor)
 
 
 class PresentationContext(object):
@@ -29,11 +30,13 @@ class PresentationContext(object):
     :vartype presenter_source: ~aria.parser.presentation.PresenterSource
     :ivar presenter_class: overrides ``presenter_source`` with a specific class
     :vartype presenter_class: type
-    :ivar import_profile: whether to import the profile by default (defaults 
to ``True``)
-    :vartype import_profile: bool
-    :ivar threads: number of threads to use when reading data
+    :ivar configuration: custom configurations for the presenter
+    :vartype configuration: {}
+    :ivar cache: whether to cache presentations (defaults to ``True``)
+    :vartype cache: bool
+    :ivar threads: number of threads to use when reading data (defaults to 8)
     :vartype threads: int
-    :ivar timeout: timeout in seconds for loading data
+    :ivar timeout: timeout in seconds for loading data (defaults to 10)
     :vartype timeout: float
     :ivar print_exceptions: whether to print exceptions while reading data
     :vartype print_exceptions: bool
@@ -44,7 +47,8 @@ class PresentationContext(object):
         self.location = None
         self.presenter_source = DefaultPresenterSource()
         self.presenter_class = None  # overrides
-        self.import_profile = True
+        self.configuration = {}
+        self.cache = True
         self.threads = 8  # reasonable default for networking multithreading
         self.timeout = 10  # in seconds
         self.print_exceptions = False
@@ -63,3 +67,12 @@ class PresentationContext(object):
         """
 
         return self.presenter._get_from_dict(*names) if self.presenter is not 
None else None
+
+    def create_executor(self):
+        if self.threads == 1:
+            # BlockingExecutor is much faster for the single-threaded case
+            return BlockingExecutor(print_exceptions=self.print_exceptions)
+
+        return FixedThreadPoolExecutor(size=self.threads,
+                                       timeout=self.timeout,
+                                       print_exceptions=self.print_exceptions)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/presentation/field_validators.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/field_validators.py 
b/aria/parser/presentation/field_validators.py
index aa04913..bd7bfdd 100644
--- a/aria/parser/presentation/field_validators.py
+++ b/aria/parser/presentation/field_validators.py
@@ -14,12 +14,29 @@
 # limitations under the License.
 
 
+from ...utils.formatting import safe_repr
 from ..validation import Issue
 from .utils import (parse_types_dict_names, report_issue_for_unknown_type,
                     report_issue_for_parent_is_self, 
report_issue_for_unknown_parent_type,
                     report_issue_for_circular_type_hierarchy)
 
 
+def not_negative_validator(field, presentation, context):
+    """
+    Makes sure that the field is not negative.
+
+    Can be used with the :func:`field_validator` decorator.
+    """
+
+    field.default_validate(presentation, context)
+    value = getattr(presentation, field.name)
+    if (value is not None) and (value < 0):
+        context.validation.report(u'field "{0}" is negative: {1}'
+                                  .format(field.name, safe_repr(value)),
+                                  
locator=presentation._get_child_locator(field.name),
+                                  level=Issue.FIELD)
+
+
 def type_validator(type_name, *types_dict_names):
     """
     Makes sure that the field refers to an existing type defined in the root 
presenter.
@@ -101,8 +118,10 @@ def list_length_validator(length):
         values = getattr(presentation, field.name)
         if isinstance(values, list):
             if len(values) != length:
-                context.validation.report('field "%s" does not have exactly %d 
elements in "%s"'
-                                          % (field.name, length, 
presentation._fullname),
+                context.validation.report(u'field "{0}" does not have exactly 
{1:d} elements in '
+                                          u'"{2}": {3}'
+                                          .format(field.name, length, 
presentation._fullname,
+                                                  safe_repr(values)),
                                           
locator=presentation._get_child_locator(field.name),
                                           level=Issue.FIELD)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/presentation/fields.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/fields.py 
b/aria/parser/presentation/fields.py
index 5c3e074..27fb236 100644
--- a/aria/parser/presentation/fields.py
+++ b/aria/parser/presentation/fields.py
@@ -338,7 +338,7 @@ def has_fields_getitem(self, key):
     if not isinstance(key, basestring):
         raise TypeError('key must be a string')
     if key not in self.__class__.FIELDS:
-        raise KeyError('no \'%s\' property' % key)
+        raise KeyError('no \'{0}\' property'.format(key))
     return getattr(self, key)
 
 
@@ -346,7 +346,7 @@ def has_fields_setitem(self, key, value):
     if not isinstance(key, basestring):
         raise TypeError('key must be a string')
     if key not in self.__class__.FIELDS:
-        raise KeyError('no \'%s\' property' % key)
+        raise KeyError('no \'{0}\' property'.format(key))
     return setattr(self, key, value)
 
 
@@ -354,7 +354,7 @@ def has_fields_delitem(self, key):
     if not isinstance(key, basestring):
         raise TypeError('key must be a string')
     if key not in self.__class__.FIELDS:
-        raise KeyError('no \'%s\' property' % key)
+        raise KeyError('no \'{0}\' property'.format(key))
     return setattr(self, key, None)
 
 
@@ -389,7 +389,7 @@ class Field(object):
 
     @property
     def full_name(self):
-        return 'field "%s" in "%s"' % (self.name, 
full_type_name(self.container_cls))
+        return u'field "{0}" in "{1}"'.format(self.name, 
full_type_name(self.container_cls))
 
     @property
     def full_cls_name(self):
@@ -420,7 +420,7 @@ class Field(object):
         if value is None:
             return
 
-        dumper = getattr(self, '_dump_%s' % self.field_variant)
+        dumper = getattr(self, '_dump_{0}'.format(self.field_variant))
         dumper(context, value)
 
     def default_get(self, presentation, context):
@@ -457,8 +457,8 @@ class Field(object):
 
         if value is None:
             if self.required:
-                raise InvalidValueError('required %s does not have a value' % 
self.full_name,
-                                        locator=self.get_locator(raw))
+                raise InvalidValueError(u'required {0} does not have a value'
+                                        .format(self.full_name, 
locator=self.get_locator(raw)))
             else:
                 return None
 
@@ -466,21 +466,20 @@ class Field(object):
 
         if self.allowed is not None:
             if value not in self.allowed:
-                raise InvalidValueError('%s is not %s'
-                                        % (self.full_name, ' or 
'.join([safe_repr(v)
-                                                                        for v 
in self.allowed])),
+                raise InvalidValueError(u'{0} is not {1}'
+                                        .format(self.full_name,
+                                                u' or '.join([safe_repr(v) for 
v in self.allowed])),
                                         locator=self.get_locator(raw))
 
         # Handle get according to variant
 
-        getter = getattr(self, 
'_get_{field_variant}'.format(field_variant=self.field_variant),
-                         None)
+        getter = getattr(self, '_get_{0}'.format(self.field_variant), None)
 
         if getter is None:
             locator = self.get_locator(raw)
-            location = (' @%s' % locator) if locator is not None else ''
-            raise AttributeError('%s has unsupported field variant: "%s"%s'
-                                 % (self.full_name, self.field_variant, 
location))
+            location = (u' @{0}'.format(locator)) if locator is not None else 
''
+            raise AttributeError(u'{0} has unsupported field variant: "{1}"{2}'
+                                 .format(self.full_name, self.field_variant, 
location))
 
         return getter(presentation, raw, value, context)
 
@@ -489,6 +488,9 @@ class Field(object):
         if is_short_form_field and not is_dict:
             # Handle short form
             value = raw
+            if value is None:
+                # An explicit null
+                value = NULL
         elif is_dict:
             if self.name in raw:
                 value = raw[self.name]
@@ -559,26 +561,28 @@ class Field(object):
     # primitive
 
     def _get_primitive(self, presentation, raw, value, context):
-        if (self.cls is not None and not isinstance(value, self.cls)
-                and value is not None and value is not NULL):
+        if (self.cls is not None) and (not isinstance(value, self.cls)) \
+                and (value is not None):
             try:
                 return self._coerce_primitive(value, context)
             except ValueError as e:
-                raise InvalidValueError('%s is not a valid "%s": %s' %
-                                        (self.full_name, self.full_cls_name, 
safe_repr(value)),
+                raise InvalidValueError(u'{0} is not a valid "{1}": {2}'
+                                        .format(self.full_name, 
self.full_cls_name,
+                                                safe_repr(value)),
                                         locator=self.get_locator(raw), cause=e)
         return value
 
     def _dump_primitive(self, context, value):
         if hasattr(value, 'as_raw'):
             value = as_raw(value)
-        puts('%s: %s' % (self.name, context.style.literal_style(value)))
+        puts(u'{0}: {1}'.format(self.name, context.style.literal_style(value)))
 
     # primitive list
 
     def _get_primitive_list(self, presentation, raw, value, context):
         if not isinstance(value, list):
-            raise InvalidValueError('%s is not a list: %s' % (self.full_name, 
safe_repr(value)),
+            raise InvalidValueError(u'{0} is not a list: {1}'
+                                    .format(self.full_name, safe_repr(value)),
                                     locator=self.get_locator(raw))
         primitive_list = value
         if self.cls is not None:
@@ -587,26 +591,28 @@ class Field(object):
             primitive_list = []
             for i, _ in enumerate(value):
                 primitive = value[i]
+                if primitive is None:
+                    primitive = NULL
                 try:
                     primitive = self._coerce_primitive(primitive, context)
                 except ValueError as e:
-                    raise InvalidValueError('%s is not a list of "%s": element 
%d is %s'
-                                            % (self.full_name,
-                                               self.full_cls_name,
-                                               i,
-                                               safe_repr(primitive)),
+                    raise InvalidValueError(u'{0} is not a list of "{1}": 
element {2:d} is {3}'
+                                            .format(self.full_name,
+                                                    self.full_cls_name,
+                                                    i,
+                                                    safe_repr(primitive)),
                                             locator=self.get_locator(raw), 
cause=e)
                 if primitive in primitive_list:
-                    raise InvalidValueError('%s has a duplicate "%s": %s'
-                                            % (self.full_name,
-                                               self.full_cls_name,
-                                               safe_repr(primitive)),
+                    raise InvalidValueError(u'{0} has a duplicate "{1}": {2}'
+                                            .format(self.full_name,
+                                                    self.full_cls_name,
+                                                    safe_repr(primitive)),
                                             locator=self.get_locator(raw))
                 primitive_list.append(primitive)
         return FrozenList(primitive_list)
 
     def _dump_primitive_list(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         with context.style.indent():
             for primitive in value:
                 if hasattr(primitive, 'as_raw'):
@@ -617,7 +623,8 @@ class Field(object):
 
     def _get_primitive_dict(self, presentation, raw, value, context):
         if not isinstance(value, dict):
-            raise InvalidValueError('%s is not a dict: %s' % (self.full_name, 
safe_repr(value)),
+            raise InvalidValueError(u'{0} is not a dict: {1}'
+                                    .format(self.full_name, safe_repr(value)),
                                     locator=self.get_locator(raw))
         primitive_dict = value
         if self.cls is not None:
@@ -625,17 +632,21 @@ class Field(object):
                 context = Field._get_context()
             primitive_dict = OrderedDict()
             for k, v in value.iteritems():
+                if v is None:
+                    v = NULL
                 try:
                     primitive_dict[k] = self._coerce_primitive(v, context)
                 except ValueError as e:
-                    raise InvalidValueError('%s is not a dict of "%s" values: 
entry "%d" is %s'
-                                            % (self.full_name, 
self.full_cls_name, k, safe_repr(v)),
+                    raise InvalidValueError(u'{0} is not a dict of "{1}" 
values: entry "{2:d}" '
+                                            u'is {3}'
+                                            .format(self.full_name, 
self.full_cls_name, k,
+                                                    safe_repr(v)),
                                             locator=self.get_locator(raw),
                                             cause=e)
         return FrozenDict(primitive_dict)
 
     def _dump_primitive_dict(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         with context.style.indent():
             for v in value.itervalues():
                 if hasattr(v, 'as_raw'):
@@ -648,13 +659,13 @@ class Field(object):
         try:
             return self.cls(name=self.name, raw=value, container=presentation)
         except TypeError as e:
-            raise InvalidValueError('%s cannot not be initialized to an 
instance of "%s": %s'
-                                    % (self.full_name, self.full_cls_name, 
safe_repr(value)),
+            raise InvalidValueError(u'{0} cannot not be initialized to an 
instance of "{1}": {2}'
+                                    .format(self.full_name, 
self.full_cls_name, safe_repr(value)),
                                     cause=e,
                                     locator=self.get_locator(raw))
 
     def _dump_object(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         with context.style.indent():
             if hasattr(value, '_dump'):
                 value._dump(context)
@@ -663,13 +674,13 @@ class Field(object):
 
     def _get_object_list(self, presentation, raw, value, context):
         if not isinstance(value, list):
-            raise InvalidValueError('%s is not a list: %s'
-                                    % (self.full_name, safe_repr(value)),
+            raise InvalidValueError(u'{0} is not a list: {1}'
+                                    .format(self.full_name, safe_repr(value)),
                                     locator=self.get_locator(raw))
         return FrozenList((self.cls(name=self.name, raw=v, 
container=presentation) for v in value))
 
     def _dump_object_list(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         with context.style.indent():
             for v in value:
                 if hasattr(v, '_dump'):
@@ -679,13 +690,14 @@ class Field(object):
 
     def _get_object_dict(self, presentation, raw, value, context):
         if not isinstance(value, dict):
-            raise InvalidValueError('%s is not a dict: %s' % (self.full_name, 
safe_repr(value)),
+            raise InvalidValueError(u'{0} is not a dict: {1}'
+                                    .format(self.full_name, safe_repr(value)),
                                     locator=self.get_locator(raw))
         return FrozenDict(((k, self.cls(name=k, raw=v, container=presentation))
                            for k, v in value.iteritems()))
 
     def _dump_object_dict(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         with context.style.indent():
             for v in value.itervalues():
                 if hasattr(v, '_dump'):
@@ -695,26 +707,27 @@ class Field(object):
 
     def _get_sequenced_object_list(self, presentation, raw, value, context):
         if not isinstance(value, list):
-            raise InvalidValueError('%s is not a sequenced list (a list of 
dicts, '
-                                    'each with exactly one key): %s'
-                                    % (self.full_name, safe_repr(value)),
+            raise InvalidValueError(u'{0} is not a sequenced list (a list of 
dicts, '
+                                    u'each with exactly one key): {1}'
+                                    .format(self.full_name, safe_repr(value)),
                                     locator=self.get_locator(raw))
         sequence = []
         for v in value:
             if not isinstance(v, dict):
-                raise InvalidValueError('%s list elements are not all dicts 
with '
-                                        'exactly one key: %s' % 
(self.full_name, safe_repr(value)),
+                raise InvalidValueError(u'{0} list elements are not all dicts 
with '
+                                        u'exactly one key: {1}'
+                                        .format(self.full_name, 
safe_repr(value)),
                                         locator=self.get_locator(raw))
             if len(v) != 1:
-                raise InvalidValueError('%s list elements do not all have 
exactly one key: %s'
-                                        % (self.full_name, safe_repr(value)),
+                raise InvalidValueError(u'{0} list elements do not all have 
exactly one key: {1}'
+                                        .format(self.full_name, 
safe_repr(value)),
                                         locator=self.get_locator(raw))
             key, value = v.items()[0]
             sequence.append((key, self.cls(name=key, raw=value, 
container=presentation)))
         return FrozenList(sequence)
 
     def _dump_sequenced_object_list(self, context, value):
-        puts('%s:' % self.name)
+        puts(u'{0}:'.format(self.name))
         for _, v in value:
             if hasattr(v, '_dump'):
                 v._dump(context)
@@ -730,13 +743,15 @@ class Field(object):
                 primitive_dict = OrderedDict()
                 for k, v in raw.iteritems():
                     if k not in presentation.FIELDS:
+                        if v is None:
+                            v = NULL
                         try:
                             primitive_dict[k] = self._coerce_primitive(v, 
context)
                         except ValueError as e:
-                            raise InvalidValueError('%s is not a dict of "%s" 
values:'
-                                                    ' entry "%d" is %s'
-                                                    % (self.full_name, 
self.full_cls_name,
-                                                       k, safe_repr(v)),
+                            raise InvalidValueError(u'{0} is not a dict of 
"{1}" values:'
+                                                    u' entry "{2}" is {3}'
+                                                    .format(self.full_name, 
self.full_cls_name,
+                                                            k, safe_repr(v)),
                                                     
locator=self.get_locator(raw),
                                                     cause=e)
             return FrozenDict(primitive_dict)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/89b9f130/aria/parser/presentation/presentation.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/presentation.py 
b/aria/parser/presentation/presentation.py
index 3f9f86d..e1104e5 100644
--- a/aria/parser/presentation/presentation.py
+++ b/aria/parser/presentation/presentation.py
@@ -115,7 +115,7 @@ class PresentationBase(HasCachedMethods):
         if names:
             obj = self._get(*names[:-1])
             if isinstance(obj, dict):
-                return obj.get(names[-1])  # pylint: disable=no-member
+                return obj.get(names[-1])                                      
                     # pylint: disable=no-member
         return None
 
     def _get_child_locator(self, *names):
@@ -159,7 +159,7 @@ class PresentationBase(HasCachedMethods):
             for field_name in field_names:
                 self._dump_field(context, field_name)
         elif hasattr(self, '_iter_field_names'):
-            for field_name in self._iter_field_names():  # pylint: 
disable=no-member
+            for field_name in self._iter_field_names():                        
                     # pylint: disable=no-member
                 self._dump_field(context, field_name)
         else:
             puts(context.style.literal_style(self._raw))
@@ -172,7 +172,7 @@ class PresentationBase(HasCachedMethods):
         delegate to their ``_dump`` methods.
         """
 
-        field = self.FIELDS[field_name]  # pylint: disable=no-member
+        field = self.FIELDS[field_name]                                        
                     # pylint: disable=no-member
         field.dump(self, context)
 
     def _clone(self, container=None):
@@ -199,6 +199,9 @@ class Presentation(PresentationBase):
     """
 
     def _validate(self, context):
+        if (not context.presentation.configuration.get('validate_normative', 
True)) \
+            and self._get_extension('normative'):
+            return
         validate_no_short_form(context, self)
         validate_no_unknown_fields(context, self)
         validate_known_fields(context, self)
@@ -233,8 +236,9 @@ class AsIsPresentation(PresentationBase):
         try:
             validate_primitive(self._raw, self.cls, 
context.validation.allow_primitive_coersion)
         except ValueError as e:
-            context.validation.report('"%s" is not a valid "%s": %s'
-                                      % (self._fullname, self._full_cls_name, 
safe_repr(self._raw)),
+            context.validation.report(u'"{0}" is not a valid "{1}": {2}'
+                                      .format(self._fullname, 
self._full_cls_name,
+                                              safe_repr(self._raw)),
                                       locator=self._locator,
                                       level=Issue.FIELD,
                                       exception=e)


Reply via email to