vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / parser / presentation / presentation.py
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/parser/presentation/presentation.py b/azure/aria/aria-extension-cloudify/src/aria/aria/parser/presentation/presentation.py
new file mode 100644 (file)
index 0000000..3f9f86d
--- /dev/null
@@ -0,0 +1,248 @@
+# 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 ...utils.caching import HasCachedMethods
+from ...utils.collections import deepcopy_with_locators
+from ...utils.formatting import safe_repr
+from ...utils.type import full_type_name
+from ...utils.console import puts
+from ..validation import Issue
+from .null import none_to_null
+from .utils import (get_locator, validate_no_short_form, validate_no_unknown_fields,
+                    validate_known_fields, validate_primitive)
+
+
+class Value(object):
+    """
+    Encapsulates a typed value assignment.
+    """
+
+    def __init__(self, type_name, value, description, required):
+        self.type = deepcopy_with_locators(type_name)
+        self.value = deepcopy_with_locators(value)
+        self.description = deepcopy_with_locators(description)
+        self.required = deepcopy_with_locators(required)
+
+    def _dump(self, context):
+        if self.type is not None:
+            puts(context.style.type_style(self.type))
+        if self.value is not None:
+            puts(context.style.literal_style(self.value))
+        if self.description is not None:
+            puts(context.style.meta_style(self.description))
+        if self.required is not None:
+            puts(context.style.required_style(self.required))
+
+
+class PresentationBase(HasCachedMethods):
+    """
+    Base class for ARIA presentation classes.
+    """
+
+    def __init__(self, name=None, raw=None, container=None):
+        self._name = name
+        self._raw = raw
+        self._container = container
+        super(PresentationBase, self).__init__()
+
+    @property
+    def as_raw(self):
+        return self._raw
+
+    def _validate(self, context):
+        """
+        Validates the presentation while reporting errors in the validation context but *not*
+        raising exceptions.
+
+        The base class does not thing, but subclasses may override this for specialized validation.
+        """
+
+    @property
+    def _fullname(self):
+        """
+        Always returns a usable full name of the presentation, whether it itself is named, or
+        recursing to its container, and finally defaulting to the class name.
+        """
+
+        if self._name is not None:
+            return self._name
+        elif self._container is not None:
+            return self._container._fullname
+        return full_type_name(self)
+
+    @property
+    def _locator(self):
+        """
+        Attempts to return the most relevant locator, whether we have one, or recursing to our
+        container.
+
+        :rtype: :class:`aria.parser.reading.Locator`
+        """
+
+        return get_locator(self._raw, self._container)
+
+    def _get(self, *names):
+        """
+        Gets attributes recursively.
+        """
+
+        obj = self
+        if (obj is not None) and names:
+            for name in names:
+                obj = getattr(obj, name, None)
+                if obj is None:
+                    break
+        return obj
+
+    def _get_from_dict(self, *names):
+        """
+        Gets attributes recursively, except for the last name which is used to get a value from the
+        last dict.
+        """
+
+        if names:
+            obj = self._get(*names[:-1])
+            if isinstance(obj, dict):
+                return obj.get(names[-1])  # pylint: disable=no-member
+        return None
+
+    def _get_child_locator(self, *names):
+        """
+        Attempts to return the locator of one our children. Will default to our locator if not
+        found.
+
+        :rtype: :class:`aria.parser.reading.Locator`
+        """
+
+        if hasattr(self._raw, '_locator'):
+            locator = self._raw._locator
+            if locator is not None:
+                return locator.get_child(*names)
+        return self._locator
+
+    def _dump(self, context):
+        """
+        Emits a colorized representation.
+
+        The base class will emit a sensible default representation of the fields, (by calling
+        ``_dump_content``), but subclasses may override this for specialized dumping.
+        """
+
+        if self._name:
+            puts(context.style.node(self._name))
+            with context.style.indent():
+                self._dump_content(context)
+        else:
+            self._dump_content(context)
+
+    def _dump_content(self, context, field_names=None):
+        """
+        Emits a colorized representation of the contents.
+
+        The base class will call ``_dump_field`` on all the fields, but subclasses may override
+        this for specialized dumping.
+        """
+
+        if field_names:
+            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
+                self._dump_field(context, field_name)
+        else:
+            puts(context.style.literal_style(self._raw))
+
+    def _dump_field(self, context, field_name):
+        """
+        Emits a colorized representation of the field.
+
+        According to the field type, this may trigger nested recursion. The nested types will
+        delegate to their ``_dump`` methods.
+        """
+
+        field = self.FIELDS[field_name]  # pylint: disable=no-member
+        field.dump(self, context)
+
+    def _clone(self, container=None):
+        """
+        Creates a clone of this presentation, optionally allowing for a new container.
+        """
+
+        raw = deepcopy_with_locators(self._raw)
+        if container is None:
+            container = self._container
+        return self.__class__(name=self._name, raw=raw, container=container)
+
+
+class Presentation(PresentationBase):
+    """
+    Base class for ARIA presentations. A presentation is a Pythonic wrapper around agnostic raw
+    data, adding the ability to read and modify the data with proper validation.
+
+    ARIA presentation classes will often be decorated with :func:`has_fields`, as that mechanism
+    automates a lot of field-specific validation. However, that is not a requirement.
+
+    Make sure that your utility property and method names begin with a ``_``, because those names
+    without a ``_`` prefix are normally reserved for fields.
+    """
+
+    def _validate(self, context):
+        validate_no_short_form(context, self)
+        validate_no_unknown_fields(context, self)
+        validate_known_fields(context, self)
+
+
+class AsIsPresentation(PresentationBase):
+    """
+    Base class for trivial ARIA presentations that provide the raw value as is.
+    """
+
+    def __init__(self, name=None, raw=None, container=None, cls=None):
+        super(AsIsPresentation, self).__init__(name, raw, container)
+        self.cls = cls
+
+    @property
+    def value(self):
+        return none_to_null(self._raw)
+
+    @value.setter
+    def value(self, value):
+        self._raw = value
+
+    @property
+    def _full_cls_name(self):
+        name = full_type_name(self.cls) if self.cls is not None else None
+        if name == 'unicode':
+            # For simplicity, display "unicode" as "str"
+            name = 'str'
+        return name
+
+    def _validate(self, context):
+        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)),
+                                      locator=self._locator,
+                                      level=Issue.FIELD,
+                                      exception=e)
+
+    def _dump(self, context):
+        if hasattr(self._raw, '_dump'):
+            puts(context.style.node(self._name))
+            with context.style.indent():
+                self._raw._dump(context)
+        else:
+            super(AsIsPresentation, self)._dump(context)