You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/05/09 21:03:30 UTC

[1/2] incubator-ariatosca git commit: ARIA-140 Version utils [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-148-extra-cli-commands 7442a7661 -> 7e75948fb (forced update)


ARIA-140 Version utils

Provided mainly to support version comparisons for plugins in order to
select the highest version of available plugins that would match a
plugin specification. In the future may be useful for other version
comparisons.


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

Branch: refs/heads/ARIA-148-extra-cli-commands
Commit: eae44d0b0d051fd50cadf94d734bdf7a3b8d3171
Parents: d0411d3
Author: Tal Liron <ta...@gmail.com>
Authored: Fri Apr 14 13:39:02 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Tue May 9 15:37:46 2017 -0500

----------------------------------------------------------------------
 aria/modeling/service_template.py |  17 ++--
 aria/utils/versions.py            | 162 +++++++++++++++++++++++++++++++++
 tests/utils/test_versions.py      |  85 +++++++++++++++++
 3 files changed, 257 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eae44d0b/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index f721b64..e3320fa 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -33,7 +33,8 @@ from sqlalchemy.ext.associationproxy import association_proxy
 from ..parser import validation
 from ..parser.consumption import ConsumptionContext
 from ..parser.reading import deepcopy_with_locators
-from ..utils import collections, formatting, console
+from ..utils import (collections, formatting, console)
+from ..utils.versions import VersionString
 from .mixins import TemplateModelMixin
 from . import (
     relationship,
@@ -2135,13 +2136,15 @@ class PluginSpecificationBase(TemplateModelMixin):
         # moved to.
         plugins = model_storage.plugin.list()
         matching_plugins = []
-        for plugin in plugins:
-            # TODO: we need to use a version comparator
-            if (plugin.name == self.name) and \
-                    ((self.version is None) or (plugin.package_version >= self.version)):
-                matching_plugins.append(plugin)
+        if plugins:
+            for plugin in plugins:
+                if (plugin.name == self.name) and \
+                    ((self.version is None) or \
+                     (VersionString(plugin.package_version) >= self.version)):
+                    matching_plugins.append(plugin)
         self.plugin = None
         if matching_plugins:
             # Return highest version of plugin
-            self.plugin = sorted(matching_plugins, key=lambda plugin: plugin.package_version)[-1]
+            key = lambda plugin: VersionString(plugin.package_version).key
+            self.plugin = sorted(matching_plugins, key=key)[-1]
         return self.plugin is not None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eae44d0b/aria/utils/versions.py
----------------------------------------------------------------------
diff --git a/aria/utils/versions.py b/aria/utils/versions.py
new file mode 100644
index 0000000..925f59e
--- /dev/null
+++ b/aria/utils/versions.py
@@ -0,0 +1,162 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+General-purpose version string handling
+"""
+
+import re
+
+
+_INF = float('inf')
+
+_NULL = (), _INF
+
+_DIGITS_RE = re.compile(r'^\d+$')
+
+_PREFIXES = {
+    'dev':   0.0001,
+    'alpha': 0.001,
+    'beta':  0.01,
+    'rc':    0.1
+}
+
+
+class VersionString(unicode):
+    """
+    Version string that can be compared, sorted, made unique in a set, and used as a unique dict
+    key.
+
+    The primary part of the string is one or more dot-separated natural numbers. Trailing zeroes
+    are treated as redundant, e.g. "1.0.0" == "1.0" == "1".
+
+    An optional qualifier can be added after a "-". The qualifier can be a natural number or a
+    specially treated prefixed natural number, e.g. "1.1-beta1" > "1.1-alpha2". The case of the
+    prefix is ignored.
+
+    Numeric qualifiers will always be greater than prefixed integer qualifiers, e.g. "1.1-1" >
+    "1.1-beta1".
+
+    Versions without a qualifier will always be greater than their equivalents with a qualifier,
+    e.g. e.g. "1.1" > "1.1-1".
+
+    Any value that does not conform to this format will be treated as a zero version, which would
+    be lesser than any non-zero version.
+
+    For efficient list sorts use the ``key`` property, e.g.:
+    ``sorted(versions, key=lambda x: x.key)``
+    """
+
+    NULL = None # initialized below
+
+    def __init__(self, value=None):
+        if value is not None:
+            super(VersionString, self).__init__(value)
+        self.key = parse_version_string(self)
+
+    def __eq__(self, version):
+        if not isinstance(version, VersionString):
+            version = VersionString(version)
+        return self.key == version.key
+
+    def __lt__(self, version):
+        if not isinstance(version, VersionString):
+            version = VersionString(version)
+        return self.key < version.key
+
+    def __hash__(self):
+        return self.key.__hash__()
+
+
+def parse_version_string(version): # pylint: disable=too-many-branches
+    """
+    Parses a version string.
+
+    :param version: The version string
+    :returns: The primary tuple and qualifier float
+    :rtype: ((int), float)
+    """
+
+    if version is None:
+        return _NULL
+    version = unicode(version)
+
+    # Split to primary and qualifier on '-'
+    split = version.split('-', 1)
+    if len(split) == 2:
+        primary, qualifier = split
+    else:
+        primary = split[0]
+        qualifier = None
+
+    # Parse primary
+    split = primary.split('.')
+    primary = []
+    for element in split:
+        if _DIGITS_RE.match(element) is None:
+            # Invalid version string
+            return _NULL
+        try:
+            element = int(element)
+        except ValueError:
+            # Invalid version string
+            return _NULL
+        primary.append(element)
+
+    # Remove redundant zeros
+    for element in reversed(primary):
+        if element == 0:
+            primary.pop()
+        else:
+            break
+    primary = tuple(primary)
+
+    # Parse qualifier
+    if qualifier is not None:
+        if _DIGITS_RE.match(qualifier) is not None:
+            # Integer qualifier
+            try:
+                qualifier = float(int(qualifier))
+            except ValueError:
+                # Invalid version string
+                return _NULL
+        else:
+            # Prefixed integer qualifier
+            value = None
+            qualifier = qualifier.lower()
+            for prefix, factor in _PREFIXES.iteritems():
+                if qualifier.startswith(prefix):
+                    value = qualifier[len(prefix):]
+                    if _DIGITS_RE.match(value) is None:
+                        # Invalid version string
+                        return _NULL
+                    try:
+                        value = float(int(value)) * factor
+                    except ValueError:
+                        # Invalid version string
+                        return _NULL
+                    break
+            if value is None:
+                # Invalid version string
+                return _NULL
+            qualifier = value
+    else:
+        # Version strings with no qualifiers are higher
+        qualifier = _INF
+
+    return primary, qualifier
+
+
+VersionString.NULL = VersionString()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eae44d0b/tests/utils/test_versions.py
----------------------------------------------------------------------
diff --git a/tests/utils/test_versions.py b/tests/utils/test_versions.py
new file mode 100644
index 0000000..222949c
--- /dev/null
+++ b/tests/utils/test_versions.py
@@ -0,0 +1,85 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from aria.utils.versions import (VersionString, parse_version_string)
+
+
+def test_version_string():
+    # No qualifiers
+    assert VersionString('20') == VersionString('20')
+    assert VersionString('20') == VersionString('20.0')
+    assert VersionString('20') == VersionString('20.0.0')
+    assert VersionString('20') < VersionString('20.0.1')
+
+    # With numeric qualifiers
+    assert VersionString('20.0.1-1') < VersionString('20.0.1-2')
+    assert VersionString('20.0.1-0') < VersionString('20.0.1')
+    assert VersionString('20.0.1-1') < VersionString('20.0.1')
+
+    # With prefixed qualifiers
+    assert VersionString('20.0.1-beta1') < VersionString('20.0.1-beta2')
+    assert VersionString('20.0.1-beta1') < VersionString('20.0.1-1')
+    assert VersionString('20.0.1-beta1') < VersionString('20.0.1')
+    assert VersionString('20.0.1-beta2') < VersionString('20.0.1-rc2')
+    assert VersionString('20.0.1-alpha2') < VersionString('20.0.1-beta1')
+    assert VersionString('20.0.1-dev2') < VersionString('20.0.1-alpha1')
+    assert VersionString('20.0.1-DEV2') < VersionString('20.0.1-ALPHA1')
+
+    # Coercive comparisons
+    assert VersionString('20.0.0') == VersionString(10 * 2)
+    assert VersionString('20.0.0') == VersionString(20.0)
+
+    # Non-VersionString comparisons
+    assert VersionString('20.0.0') == 20
+    assert VersionString('20.0.0') < '20.0.1'
+
+    # Nulls
+    assert VersionString() == VersionString()
+    assert VersionString() == VersionString.NULL
+    assert VersionString(None) == VersionString.NULL
+    assert VersionString.NULL == None # pylint: disable=singleton-comparison
+    assert VersionString.NULL == 0
+
+    # Invalid version strings
+    assert VersionString('maxim is maxim') == VersionString.NULL
+    assert VersionString('20.maxim.0') == VersionString.NULL
+    assert VersionString('20.0.0-maxim1') == VersionString.NULL
+    assert VersionString('20.0.1-1.1') == VersionString.NULL
+
+    # Sorts
+    v1 = VersionString('20.0.0')
+    v2 = VersionString('20.0.1-beta1')
+    v3 = VersionString('20.0.1')
+    v4 = VersionString('20.0.2')
+    assert [v1, v2, v3, v4] == sorted([v4, v3, v2, v1], key=lambda v: v.key)
+
+    # Sets
+    v1 = VersionString('20.0.0')
+    v2 = VersionString('20.0')
+    v3 = VersionString('20')
+    assert set([v1]) == set([v1, v2, v3])
+
+    # Dicts
+    the_dict = {v1: 'test'}
+    assert the_dict.get(v2) == 'test'
+
+def test_parse_version_string():
+    # One test of each type from the groups above should be enough
+    assert parse_version_string('20') < parse_version_string('20.0.1')
+    assert parse_version_string('20.0.1-1') < parse_version_string('20.0.1-2')
+    assert parse_version_string('20.0.1-beta1') < parse_version_string('20.0.1-beta2')
+    assert parse_version_string('20.0.0') == parse_version_string(10 * 2)
+    assert parse_version_string(None) == parse_version_string(0)
+    assert parse_version_string(None) == parse_version_string('maxim is maxim')


[2/2] incubator-ariatosca git commit: ARIA-148 Enhance CLI show commands

Posted by em...@apache.org.
ARIA-148 Enhance CLI show commands

* Allow "--all" flag to provide a complete dump
* Allow "--json" and "--yaml" flags for dump in those formats
* Support for node graph and type hierarchies
* Some fixes for YAML dump for our custom types
* Also closes ARIA-186: "aria services show" command


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

Branch: refs/heads/ARIA-148-extra-cli-commands
Commit: 7e75948fb7aaf60c48cf2be4763ccbba0463f4bd
Parents: eae44d0
Author: Tal Liron <ta...@gmail.com>
Authored: Thu Apr 20 17:54:47 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Tue May 9 15:50:59 2017 -0500

----------------------------------------------------------------------
 aria/cli/commands/service_templates.py | 71 +++++++++++++++++++----------
 aria/cli/commands/services.py          | 52 ++++++++++++++++++++-
 aria/cli/core/aria.py                  | 34 +++++++++++++-
 aria/cli/helptexts.py                  |  8 +++-
 aria/cli/table.py                      |  2 +-
 aria/modeling/service_instance.py      |  4 +-
 aria/modeling/service_template.py      |  2 +-
 aria/modeling/types.py                 |  5 ++
 aria/utils/collections.py              |  2 +-
 9 files changed, 146 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/cli/commands/service_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py
index e459871..9feaded 100644
--- a/aria/cli/commands/service_templates.py
+++ b/aria/cli/commands/service_templates.py
@@ -23,11 +23,13 @@ from .. import utils
 from ..core import aria
 from ...core import Core
 from ...storage import exceptions as storage_exceptions
+from ...parser import consumption
+from ...utils import (formatting, collections, console)
 
 
 DESCRIPTION_FIELD_LENGTH_LIMIT = 20
 SERVICE_TEMPLATE_COLUMNS = \
-    ['id', 'name', 'description', 'main_file_name', 'created_at', 'updated_at']
+    ('id', 'name', 'description', 'main_file_name', 'created_at', 'updated_at')
 
 
 @aria.group(name='service-templates')
@@ -43,32 +45,51 @@ def service_templates():
 @aria.argument('service-template-name')
 @aria.options.verbose()
 @aria.pass_model_storage
+@aria.options.show_all
+@aria.options.show_types
+@aria.options.show_json
+@aria.options.show_yaml
 @aria.pass_logger
-def show(service_template_name, model_storage, logger):
-    """Show information for a specific service templates
+def show(service_template_name, model_storage, all, types, json, yaml, logger):
+    """Show information for a specific service template
 
     `SERVICE_TEMPLATE_NAME` is the name of the service template to show information on.
     """
-    logger.info('Showing service template {0}...'.format(service_template_name))
     service_template = model_storage.service_template.get_by_name(service_template_name)
-    service_template_dict = service_template.to_dict()
-    service_template_dict['#services'] = len(service_template.services)
 
-    column_formatters = \
-        dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
-    columns = SERVICE_TEMPLATE_COLUMNS + ['#services']
-    table.print_data(columns, service_template_dict, 'Service-template:',
-                     column_formatters=column_formatters, col_max_width=50)
-
-    if service_template_dict['description'] is not None:
-        logger.info('Description:')
-        logger.info('{0}{1}'.format(service_template_dict['description'].encode('UTF-8') or '',
-                                    os.linesep))
-
-    if service_template.services:
-        logger.info('Existing services:')
-        for service in service_template.services:
-            logger.info('\t{0}'.format(service.name))
+    if json or yaml:
+        all = True
+
+    if all:
+        consumption.ConsumptionContext()
+        if json:
+            console.puts(formatting.json_dumps(collections.prune(service_template.as_raw)))
+        elif yaml:
+            console.puts(formatting.yaml_dumps(collections.prune(service_template.as_raw)))
+        else:
+            service_template.dump()
+    elif types:
+        consumption.ConsumptionContext()
+        service_template.dump_types()
+    else:
+        logger.info('Showing service template {0}...'.format(service_template_name))
+        service_template_dict = service_template.to_dict()
+        service_template_dict['#services'] = len(service_template.services)
+        columns = SERVICE_TEMPLATE_COLUMNS + ('#services',)
+        column_formatters = \
+            dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
+        table.print_data(columns, service_template_dict, 'Service-template:',
+                         column_formatters=column_formatters, col_max_width=50)
+
+        if service_template_dict['description'] is not None:
+            logger.info('Description:')
+            logger.info('{0}{1}'.format(service_template_dict['description'].encode('UTF-8') or '',
+                                        os.linesep))
+
+        if service_template.services:
+            logger.info('Existing services:')
+            for service in service_template.services:
+                logger.info('\t{0}'.format(service.name))
 
 
 @service_templates.command(name='list',
@@ -135,6 +156,7 @@ def store(service_template_path, service_template_name, service_template_filenam
 @aria.pass_logger
 def delete(service_template_name, model_storage, resource_storage, plugin_manager, logger):
     """Delete a service template
+
     `SERVICE_TEMPLATE_NAME` is the name of the service template to delete.
     """
     logger.info('Deleting service template {0}...'.format(service_template_name))
@@ -172,7 +194,7 @@ def validate(service_template, service_template_filename,
              model_storage, resource_storage, plugin_manager, logger):
     """Validate a service template
 
-    `SERVICE_TEMPLATE` is the path or url of the service template or archive to validate.
+    `SERVICE_TEMPLATE` is the path or URL of the service template or archive to validate.
     """
     logger.info('Validating service template: {0}'.format(service_template))
     service_template_path = service_template_utils.get(service_template, service_template_filename)
@@ -188,11 +210,10 @@ def validate(service_template, service_template_filename,
 @aria.options.verbose()
 @aria.pass_logger
 def create_archive(service_template_path, destination, logger):
-    """Create a csar archive on the local file system
+    """Create a CSAR archive
 
     `service_template_path` is the path of the service template to create the archive from
-
-    `destination` is the path of the output CSAR archive file
+    `destination` is the path of the output CSAR archive
     """
     logger.info('Creating a CSAR archive')
     if not destination.endswith(csar.CSAR_FILE_EXTENSION):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index 50b530a..ece065d 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -25,9 +25,12 @@ from ..core import aria
 from ...core import Core
 from ...modeling import exceptions as modeling_exceptions
 from ...storage import exceptions as storage_exceptions
+from ...parser import consumption
+from ...utils import (formatting, collections, console)
 
 
-SERVICE_COLUMNS = ['id', 'name', 'service_template_name', 'created_at', 'updated_at']
+DESCRIPTION_FIELD_LENGTH_LIMIT = 20
+SERVICE_COLUMNS = ('id', 'name', 'description', 'service_template_name', 'created_at', 'updated_at')
 
 
 @aria.group(name='services')
@@ -38,6 +41,53 @@ def services():
     pass
 
 
+@services.command(name='show',
+                  short_help='Display service information')
+@aria.argument('service-name')
+@aria.options.verbose()
+@aria.options.show_all
+@aria.options.show_graph
+@aria.options.show_json
+@aria.options.show_yaml
+@aria.pass_model_storage
+@aria.pass_logger
+def show(service_name, model_storage, all, graph, json, yaml, logger):
+    """Show information for a specific service template
+
+    `SERVICE_NAME` is the name of the service to display information on.
+    """
+    logger.info('Showing service {0}...'.format(service_name))
+    service = model_storage.service.get_by_name(service_name)
+
+    if json or yaml:
+        all = True
+
+    if all:
+        consumption.ConsumptionContext()
+        if json:
+            console.puts(formatting.json_dumps(collections.prune(service.as_raw)))
+        elif yaml:
+            console.puts(formatting.yaml_dumps(collections.prune(service.as_raw)))
+        else:
+            service.dump()
+    elif graph:
+        consumption.ConsumptionContext()
+        service.dump_graph()
+    else:
+        logger.info('Showing service {0}...'.format(service_name))
+        service_dict = service.to_dict()
+        columns = SERVICE_COLUMNS
+        column_formatters = \
+            dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
+        table.print_data(columns, service_dict, 'Service:',
+                         column_formatters=column_formatters, col_max_width=50)
+
+        if service_dict['description'] is not None:
+            logger.info('Description:')
+            logger.info('{0}{1}'.format(service_dict['description'].encode('UTF-8') or '',
+                                        os.linesep))
+
+
 @services.command(name='list', short_help='List services')
 @aria.options.service_template_name()
 @aria.options.sort_by()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/cli/core/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/aria.py b/aria/cli/core/aria.py
index ed6afa1..d303e16 100644
--- a/aria/cli/core/aria.py
+++ b/aria/cli/core/aria.py
@@ -281,12 +281,12 @@ def argument(*args, **kwargs):
 
 class Options(object):
     def __init__(self):
-        """The options api is nicer when you use each option by calling
+        """The options API is nicer when you use each option by calling
         `@aria.options.some_option` instead of `@aria.some_option`.
 
         Note that some options are attributes and some are static methods.
         The reason for that is that we want to be explicit regarding how
-        a developer sees an option. It it can receive arguments, it's a
+        a developer sees an option. If it can receive arguments, it's a
         method - if not, it's an attribute.
         """
         self.version = click.option(
@@ -325,6 +325,36 @@ class Options(object):
             default=defaults.SERVICE_TEMPLATE_FILENAME,
             help=helptexts.SERVICE_TEMPLATE_FILENAME)
 
+        self.show_all = click.option(
+            '-a',
+            '--all',
+            is_flag=True,
+            help=helptexts.SHOW_ALL)
+
+        self.show_json = click.option(
+            '-j',
+            '--json',
+            is_flag=True,
+            help=helptexts.SHOW_JSON)
+
+        self.show_yaml = click.option(
+            '-y',
+            '--yaml',
+            is_flag=True,
+            help=helptexts.SHOW_YAML)
+
+        self.show_types = click.option(
+            '-t',
+            '--types',
+            is_flag=True,
+            help=helptexts.SHOW_TYPES)
+
+        self.show_graph = click.option(
+            '-g',
+            '--graph',
+            is_flag=True,
+            help=helptexts.SHOW_GRAPH)
+
     @staticmethod
     def verbose(expose_value=False):
         return click.option(

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/helptexts.py b/aria/cli/helptexts.py
index 8641822..f46bee0 100644
--- a/aria/cli/helptexts.py
+++ b/aria/cli/helptexts.py
@@ -29,7 +29,7 @@ EXECUTION_ID = "The unique identifier for the execution"
 SERVICE_TEMPLATE_PATH = "The path to the application's service template file"
 SERVICE_TEMPLATE_FILENAME = (
     "The name of the archive's main service template file. "
-    "This is only relevant if uploading a (non-csar) archive")
+    "This is only relevant if uploading a (non-CSAR) archive")
 INPUTS_PARAMS_USAGE = (
     '(Can be provided as wildcard based paths '
     '(*.yaml, /my_inputs/, etc..) to YAML files, a JSON string or as '
@@ -48,3 +48,9 @@ SORT_BY = "Key for sorting the list"
 DESCENDING = "Sort list in descending order [default: False]"
 JSON_OUTPUT = "Output logs in a consumable JSON format"
 MARK_PATTERN = "Mark a regex pattern in the logs"
+
+SHOW_ALL = "Show all information"
+SHOW_JSON = "Show in JSON format (implies --all)"
+SHOW_YAML = "Show in YAML format (implies --all)"
+SHOW_TYPES = "Show only the type hierarchies"
+SHOW_GRAPH = "Show only the node graph"

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/cli/table.py
----------------------------------------------------------------------
diff --git a/aria/cli/table.py b/aria/cli/table.py
index 408f81e..abc673e 100644
--- a/aria/cli/table.py
+++ b/aria/cli/table.py
@@ -85,7 +85,7 @@ def _generate(cols, data, column_formatters=None, defaults=None):
 
             return val
         else:
-            return defaults[column]
+            return defaults.get(column) if defaults is not None else None
 
     column_formatters = column_formatters or dict()
     pretty_table = PrettyTable(list(cols))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index ad8e7ed..915f0f6 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -1011,7 +1011,7 @@ class SubstitutionBase(InstanceModelMixin):
     @property
     def as_raw(self):
         return collections.OrderedDict((
-            ('node_type_name', self.node_type_name),
+            ('node_type_name', self.node_type.name),
             ('mappings', formatting.as_raw_dict(self.mappings))))
 
     def validate(self):
@@ -1119,7 +1119,7 @@ class SubstitutionMappingBase(InstanceModelMixin):
     @property
     def as_raw(self):
         return collections.OrderedDict((
-            ('name', self.name)))
+            ('name', self.name),))
 
     def coerce_values(self, container, report_issues):
         pass

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index e3320fa..918a629 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -1047,7 +1047,7 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     @property
     def as_raw(self):
         return collections.OrderedDict((
-            ('name', self.name)))
+            ('name', self.name),))
 
     def coerce_values(self, container, report_issues):
         pass

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/modeling/types.py
----------------------------------------------------------------------
diff --git a/aria/modeling/types.py b/aria/modeling/types.py
index 06f171c..7460f47 100644
--- a/aria/modeling/types.py
+++ b/aria/modeling/types.py
@@ -22,6 +22,7 @@ from sqlalchemy import (
     event
 )
 from sqlalchemy.ext import mutable
+from ruamel import yaml
 
 from . import exceptions
 
@@ -206,6 +207,8 @@ class _StrictDict(object):
                 (_StrictDictMixin, _MutableDict),
                 {'_key_cls': key_cls, '_value_cls': value_cls}
             )
+            yaml.representer.RoundTripRepresenter.add_representer(
+                listener_cls, yaml.representer.RoundTripRepresenter.represent_list)
             self._strict_map[strict_dict_map_key] = _StrictValue(type_cls=strict_dict_cls,
                                                                  listener_cls=listener_cls)
 
@@ -242,6 +245,8 @@ class _StrictList(object):
                 (_StrictListMixin, _MutableList),
                 {'_item_cls': item_cls}
             )
+            yaml.representer.RoundTripRepresenter.add_representer(
+                listener_cls, yaml.representer.RoundTripRepresenter.represent_list)
             self._strict_map[item_cls] = _StrictValue(type_cls=strict_list_cls,
                                                       listener_cls=listener_cls)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/7e75948f/aria/utils/collections.py
----------------------------------------------------------------------
diff --git a/aria/utils/collections.py b/aria/utils/collections.py
index 03feabd..1e732aa 100644
--- a/aria/utils/collections.py
+++ b/aria/utils/collections.py
@@ -249,7 +249,7 @@ def prune(value, is_removable_function=is_removable):
             else:
                 prune(v, is_removable_function)
     elif isinstance(value, dict):
-        for k, v in value.iteritems():
+        for k, v in value.items():
             if is_removable_function(value, k, v):
                 del value[k]
             else: