diff options
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/utils/type.py')
-rw-r--r-- | azure/aria/aria-extension-cloudify/src/aria/aria/utils/type.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/utils/type.py b/azure/aria/aria-extension-cloudify/src/aria/aria/utils/type.py new file mode 100644 index 0000000..fe88a62 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/aria/utils/type.py @@ -0,0 +1,156 @@ +# 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. + +""" +Type utilities. +""" + +import datetime + +from .specification import implements_specification + + +BASE_TYPES_TO_CANONICAL_NAMES = { + # TOSCA aliases: + None.__class__: 'null', + basestring: 'string', + int: 'integer', + float: 'float', + bool: 'boolean', + list: 'list', + tuple: 'list', + dict: 'map', + datetime.datetime: 'timestamp' +} + +NAMES_TO_CANONICAL_TYPES = { + # Python: + 'none': None.__class__, + 'basestring': unicode, + 'str': unicode, + 'unicode': unicode, + 'int': int, + 'float': float, # also a TOSCA alias + 'bool': bool, + 'list': list, # also a TOSCA alias + 'tuple': list, + 'dict': dict, + 'datetime': datetime.datetime, + + # YAML 1.2: + 'tag:yaml.org,2002:null': None.__class__, + 'tag:yaml.org,2002:str': unicode, + 'tag:yaml.org,2002:integer': int, + 'tag:yaml.org,2002:float': float, + 'tag:yaml.org,2002:bool': bool, + + # TOSCA aliases: + 'null': None.__class__, + 'string': unicode, + 'integer': int, + 'boolean': bool, + + # TOSCA custom types: + 'map': dict, + 'timestamp': datetime.datetime +} + + +def full_type_name(value): + """ + The full class name of a type or instance. + """ + + if not isinstance(value, type): + value = value.__class__ + module = str(value.__module__) + name = str(value.__name__) + return name if module == '__builtin__' else '{0}.{1}'.format(module, name) + + +@implements_specification('3.2.1-1', 'tosca-simple-1.0') +def canonical_type_name(value): + """ + Returns the canonical TOSCA type name of a primitive value, or ``None`` if unknown. + + For a list of TOSCA type names, see the `TOSCA Simple Profile v1.0 + cos01 specification <http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01 + /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__ + """ + + for the_type, name in BASE_TYPES_TO_CANONICAL_NAMES.iteritems(): + if isinstance(value, the_type): + return name + return None + + +@implements_specification('3.2.1-2', 'tosca-simple-1.0') +def canonical_type(type_name): + """ + Return the canonical type for any Python, YAML, or TOSCA type name or alias, or ``None`` if + unsupported. + + :param type_name: Type name (case insensitive) + """ + + return NAMES_TO_CANONICAL_TYPES.get(type_name.lower()) + + +def validate_value_type(value, type_name): + """ + Validate that a value is of a specific type. Supports Python, YAML, and TOSCA type names and + aliases. + + :param type_name: type name (case insensitive) + :raises ~exceptions.ValueError: on type mismatch + """ + + the_type = canonical_type(type_name) + if the_type is None: + raise RuntimeError('Unsupported type name: {0}'.format(type_name)) + + # The following Python types do not inherit from the canonical type, but are considered valid + if (the_type is unicode) and isinstance(value, str): + return + if (the_type is list) and isinstance(value, tuple): + return + + if not isinstance(value, the_type): + raise ValueError('Value {0} is not of type {1}'.format(value, type_name)) + + +def convert_value_to_type(str_value, python_type_name): + """ + Converts a value to a specific Python primitive type. + + :param python_type_name: Python primitive type name (case insensitive) + :raises ~exceptions.ValueError: for unsupported types or conversion failure + """ + + python_type_name = python_type_name.lower() + try: + if python_type_name in ('str', 'unicode'): + return str_value.decode('utf-8') + elif python_type_name == 'int': + return int(str_value) + elif python_type_name == 'bool': + return bool(str_value) + elif python_type_name == 'float': + return float(str_value) + else: + raise ValueError('Unsupported Python type name: {0}'.format(python_type_name)) + except ValueError: + raise ValueError('Failed to to convert {0} to {1}'.format(str_value, + python_type_name)) |