class ExceptionCollector(object):

    exceptions = []
    collecting = False

    @staticmethod
    def clear():
        del ExceptionCollector.exceptions[:]

    @staticmethod
    def start():
        ExceptionCollector.clear()
        ExceptionCollector.collecting = True

    @staticmethod
    def stop():
        ExceptionCollector.collecting = False

    @staticmethod
    def contains(exception):
        for ex in ExceptionCollector.exceptions:
            if str(ex) == str(exception):
                return True
        return False

    @staticmethod
    def appendException(exception):
        if ExceptionCollector.collecting:
            if not ExceptionCollector.contains(exception):
                exception.trace = traceback.extract_stack()[:-1]
                ExceptionCollector.exceptions.append(exception)
        else:
            raise exception

    @staticmethod
    def exceptionsCaught():
        return len(ExceptionCollector.exceptions) > 0

    @staticmethod
    def getTraceString(traceList):
        traceString = ''
        for entry in traceList:
            f, l, m, c = entry[0], entry[1], entry[2], entry[3]
            traceString += (_('\t\tFile %(file)s, line %(line)s, in '
                              '%(method)s\n\t\t\t%(call)s\n')
                            % {'file': f, 'line': l, 'method': m, 'call': c})
        return traceString

    @staticmethod
    def getExceptionReportEntry(exception, full=True):
        entry = exception.__class__.__name__ + ': ' + str(exception)
        if full:
            entry += '\n' + ExceptionCollector.getTraceString(exception.trace)
        return entry

    @staticmethod
    def getExceptions():
        return ExceptionCollector.exceptions

    @staticmethod
    def getExceptionsReport(full=True):
        report = []
        for exception in ExceptionCollector.exceptions:
            report.append(
                ExceptionCollector.getExceptionReportEntry(exception, full))
        return report

    @staticmethod
    def assertExceptionMessage(exception, message):
        err_msg = exception.__name__ + ': ' + message
        report = ExceptionCollector.getExceptionsReport(False)
        assert err_msg in report, (_('Could not find "%(msg)s" in "%(rep)s".')
                                   % {'rep': report.__str__(), 'msg': err_msg}) class MissingRequiredFieldError(TOSCAException):
    msg_fmt = _('%(what)s is missing required field "%(required)s".') class TypeMismatchError(TOSCAException):
    msg_fmt = _('%(what)s must be of type "%(type)s".') class UnknownFieldError(TOSCAException):
    msg_fmt = _('%(what)s contains unknown field "%(field)s". Refer to the '
                'definition to verify valid values.') class Schema(collections.abc.Mapping):

    KEYS = (
        TYPE, REQUIRED, DESCRIPTION,
        DEFAULT, CONSTRAINTS, ENTRYSCHEMA, STATUS
    ) = (
        'type', 'required', 'description',
        'default', 'constraints', 'entry_schema', 'status'
    )

    PROPERTY_TYPES = (
        INTEGER, STRING, BOOLEAN, FLOAT, RANGE,
        NUMBER, TIMESTAMP, LIST, MAP,
        SCALAR_UNIT_SIZE, SCALAR_UNIT_FREQUENCY, SCALAR_UNIT_TIME,
        VERSION, PORTDEF, PORTSPEC
    ) = (
        'integer', 'string', 'boolean', 'float', 'range',
        'number', 'timestamp', 'list', 'map',
        'scalar-unit.size', 'scalar-unit.frequency', 'scalar-unit.time',
        'version', 'PortDef', PortSpec.SHORTNAME
    )

    SCALAR_UNIT_SIZE_DEFAULT = 'B'
    SCALAR_UNIT_SIZE_DICT = {'B': 1, 'KB': 1000, 'KIB': 1024, 'MB': 1000000,
                             'MIB': 1048576, 'GB': 1000000000,
                             'GIB': 1073741824, 'TB': 1000000000000,
                             'TIB': 1099511627776}

    def __init__(self, name, schema_dict):
        self.name = name
        if not isinstance(schema_dict, collections.abc.Mapping):
            msg = (_('Schema definition of "%(pname)s" must be a dict.')
                   % dict(pname=name))
            ExceptionCollector.appendException(InvalidSchemaError(message=msg))

        try:
            schema_dict['type']
        except KeyError:
            msg = (_('Schema definition of "%(pname)s" must have a "type" '
                     'attribute.') % dict(pname=name))
            ExceptionCollector.appendException(InvalidSchemaError(message=msg))

        self.schema = schema_dict
        self._len = None
        self.constraints_list = []

    @property
    def type(self):
        return self.schema[self.TYPE]

    @property
    def required(self):
        return self.schema.get(self.REQUIRED, True)

    @property
    def description(self):
        return self.schema.get(self.DESCRIPTION, '')

    @property
    def default(self):
        return self.schema.get(self.DEFAULT)

    @property
    def status(self):
        return self.schema.get(self.STATUS, '')

    @property
    def constraints(self):
        if not self.constraints_list:
            constraint_schemata = self.schema.get(self.CONSTRAINTS)
            if constraint_schemata:
                self.constraints_list = [Constraint(self.name,
                                                    self.type,
                                                    cschema)
                                         for cschema in constraint_schemata]
        return self.constraints_list

    @property
    def entry_schema(self):
        return self.schema.get(self.ENTRYSCHEMA)

    def __getitem__(self, key):
        return self.schema[key]

    def __iter__(self):
        for k in self.KEYS:
            try:
                self.schema[k]
            except KeyError:
                pass
            else:
                yield k

    def __len__(self):
        if self._len is None:
            self._len = len(list(iter(self)))
        return self._len class DataType(StatefulEntityType):
    '''TOSCA built-in and user defined complex data type.'''

    def __init__(self, datatypename, custom_def=None):
        super(DataType, self).__init__(datatypename,
                                       self.DATATYPE_NETWORK_PREFIX,
                                       custom_def)
        self.custom_def = custom_def

    @property
    def parent_type(self):
        '''Return a datatype this datatype is derived from.'''
        ptype = self.derived_from(self.defs)
        if ptype:
            return DataType(ptype, self.custom_def)
        return None

    @property
    def value_type(self):
        '''Return 'type' section in the datatype schema.'''
        return self.entity_value(self.defs, 'type')

    def get_all_properties_objects(self):
        '''Return all properties objects defined in type and parent type.'''
        props_def = self.get_properties_def_objects()
        ptype = self.parent_type
        while ptype:
            props_def.extend(ptype.get_properties_def_objects())
            ptype = ptype.parent_type
        return props_def

    def get_all_properties(self):
        '''Return a dictionary of all property definition name-object pairs.'''
        return {prop.name: prop
                for prop in self.get_all_properties_objects()}

    def get_all_property_value(self, name):
        '''Return the value of a given property name.'''
        props_def = self.get_all_properties()
        if props_def and name in props_def.key():
            return props_def[name].value class PortSpec(object):
    '''Parent class for tosca.datatypes.network.PortSpec type.'''

    SHORTNAME = 'PortSpec'
    TYPE_URI = 'tosca.datatypes.network.' + SHORTNAME

    PROPERTY_NAMES = (
        PROTOCOL, SOURCE, SOURCE_RANGE,
        TARGET, TARGET_RANGE
    ) = (
        'protocol', 'source', 'source_range',
        'target', 'target_range'
    )

    # TODO(TBD) May want to make this a subclass of DataType
    # and change init method to set PortSpec's properties
    def __init__(self):
        pass

    # The following additional requirements MUST be tested:
    # 1) A valid PortSpec MUST have at least one of the following properties:
    #   target, target_range, source or source_range.
    # 2) A valid PortSpec MUST have a value for the source property that
    #    is within the numeric range specified by the property source_range
    #    when source_range is specified.
    # 3) A valid PortSpec MUST have a value for the target property that is
    #    within the numeric range specified by the property target_range
    #    when target_range is specified.
    @staticmethod
    def validate_additional_req(properties, prop_name, custom_def=None, ):
        try:
            source = properties.get(PortSpec.SOURCE)
            source_range = properties.get(PortSpec.SOURCE_RANGE)
            target = properties.get(PortSpec.TARGET)
            target_range = properties.get(PortSpec.TARGET_RANGE)

            # verify one of the specified values is set
            if source is None and source_range is None and \
                    target is None and target_range is None:
                ExceptionCollector.appendException(
                    InvalidTypeAdditionalRequirementsError(
                        type=PortSpec.TYPE_URI))
            # Validate source value is in specified range
            if source and source_range:
                validateutils.validate_value_in_range(source, source_range,
                                                      PortSpec.SOURCE)
            else:
                from toscaparser.dataentity import DataEntity
                portdef = DataEntity('PortDef', source, None, PortSpec.SOURCE)
                portdef.validate()
            # Validate target value is in specified range
            if target and target_range:
                validateutils.validate_value_in_range(target, target_range,
                                                      PortSpec.TARGET)
            else:
                from toscaparser.dataentity import DataEntity
                portdef = DataEntity('PortDef', source, None, PortSpec.TARGET)
                portdef.validate()
        except Exception:
            msg = _('"%(value)s" do not meet requirements '
                    'for type "%(type)s".') \
                % {'value': properties, 'type': PortSpec.SHORTNAME}
            ExceptionCollector.appendException(
                ValueError(msg)) class ScalarUnit_Frequency(ScalarUnit):

    SCALAR_UNIT_DEFAULT = 'GHz'
    SCALAR_UNIT_DICT = {'Hz': 1, 'kHz': 1000,
                        'MHz': 1000000, 'GHz': 1000000000} class ScalarUnit_Size(ScalarUnit):

    SCALAR_UNIT_DEFAULT = 'B'
    SCALAR_UNIT_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000,
                        'MiB': 1048576, 'GB': 1000000000,
                        'GiB': 1073741824, 'TB': 1000000000000,
                        'TiB': 1099511627776} class ScalarUnit_Time(ScalarUnit):

    SCALAR_UNIT_DEFAULT = 'ms'
    SCALAR_UNIT_DICT = {'d': 86400, 'h': 3600, 'm': 60, 's': 1,
                        'ms': 0.001, 'us': 0.000001, 'ns': 0.000000001} def _(msg):
    # type: (object) -> object
    return _t.gettext(msg) RANGE_UNBOUNDED = 'UNBOUNDED'
    VERSION_RE = re.compile(r'^(?P<major_version>([0-9][0-9]*))'
                            r'(\.(?P<minor_version>([0-9][0-9]*)))?'
                            r'(\.(?P<fix_version>([0-9][0-9]*)))?'
                            r'(\.(?P<qualifier>([0-9A-Za-z]+)))?'
                            r'(\-(?P<build_version>[0-9])*)?$')
def str_to_num(value):
def validate_numeric(value):
def validate_integer(value):
def validate_float(value):
def validate_string(value):
def validate_list(value):
def validate_range(range):
def validate_value_in_range(value, range, prop_name):
def validate_map(value):
def validate_boolean(value):
def validate_timestamp(value):
    def __init__(self, version):
    def _validate_major_version(self, value):
    def _validate_qualifier(self, value):
    def _validate_build(self, value):
    def get_version(self):
class TOSCAVersionProperty(object):
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import MissingRequiredFieldError
from toscaparser.common.exception import TypeMismatchError
from toscaparser.common.exception import UnknownFieldError
from toscaparser.elements.constraints import Schema
from toscaparser.elements.datatype import DataType
from toscaparser.elements.portspectype import PortSpec
from toscaparser.elements.scalarunit import ScalarUnit_Frequency
from toscaparser.elements.scalarunit import ScalarUnit_Size
from toscaparser.elements.scalarunit import ScalarUnit_Time
from toscaparser.utils.gettextutils import _
from toscaparser.utils import validateutils
        from toscaparser.functions import is_function
#    Licensed 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.



class DataEntity(object):
    '''A complex data value entity.'''

    def __init__(self, datatypename, value_dict, custom_def=None,
                 prop_name=None):
        self.custom_def = custom_def
        self.datatype = DataType(datatypename, custom_def)
        self.schema = self.datatype.get_all_properties()
        self.value = value_dict
        self.property_name = prop_name

    def validate(self):
        '''Validate the value by the definition of the datatype.'''

        # A datatype can not have both 'type' and 'properties' definitions.
        # If the datatype has 'type' definition
        if self.datatype.value_type:
            self.value = DataEntity.validate_datatype(self.datatype.value_type,
                                                      self.value,
                                                      None,
                                                      self.custom_def)
            schema = Schema(self.property_name, self.datatype.defs)
            for constraint in schema.constraints:
                constraint.validate(self.value)
        # If the datatype has 'properties' definition
        else:
            if not isinstance(self.value, dict):
                ExceptionCollector.appendException(

                    TypeMismatchError(what=self.value,