vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / utils / type.py
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """
17 Type utilities.
18 """
19
20 import datetime
21
22 from .specification import implements_specification
23
24
25 BASE_TYPES_TO_CANONICAL_NAMES = {
26     # TOSCA aliases:
27     None.__class__: 'null',
28     basestring: 'string',
29     int: 'integer',
30     float: 'float',
31     bool: 'boolean',
32     list: 'list',
33     tuple: 'list',
34     dict: 'map',
35     datetime.datetime: 'timestamp'
36 }
37
38 NAMES_TO_CANONICAL_TYPES = {
39     # Python:
40     'none': None.__class__,
41     'basestring': unicode,
42     'str': unicode,
43     'unicode': unicode,
44     'int': int,
45     'float': float, # also a TOSCA alias
46     'bool': bool,
47     'list': list, # also a TOSCA alias
48     'tuple': list,
49     'dict': dict,
50     'datetime': datetime.datetime,
51
52     # YAML 1.2:
53     'tag:yaml.org,2002:null': None.__class__,
54     'tag:yaml.org,2002:str': unicode,
55     'tag:yaml.org,2002:integer': int,
56     'tag:yaml.org,2002:float': float,
57     'tag:yaml.org,2002:bool': bool,
58
59     # TOSCA aliases:
60     'null': None.__class__,
61     'string': unicode,
62     'integer': int,
63     'boolean': bool,
64
65     # TOSCA custom types:
66     'map': dict,
67     'timestamp': datetime.datetime
68 }
69
70
71 def full_type_name(value):
72     """
73     The full class name of a type or instance.
74     """
75
76     if not isinstance(value, type):
77         value = value.__class__
78     module = str(value.__module__)
79     name = str(value.__name__)
80     return name if module == '__builtin__' else '{0}.{1}'.format(module, name)
81
82
83 @implements_specification('3.2.1-1', 'tosca-simple-1.0')
84 def canonical_type_name(value):
85     """
86     Returns the canonical TOSCA type name of a primitive value, or ``None`` if unknown.
87
88     For a list of TOSCA type names, see the `TOSCA Simple Profile v1.0
89     cos01 specification <http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01
90     /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__
91     """
92
93     for the_type, name in BASE_TYPES_TO_CANONICAL_NAMES.iteritems():
94         if isinstance(value, the_type):
95             return name
96     return None
97
98
99 @implements_specification('3.2.1-2', 'tosca-simple-1.0')
100 def canonical_type(type_name):
101     """
102     Return the canonical type for any Python, YAML, or TOSCA type name or alias, or ``None`` if
103     unsupported.
104
105     :param type_name: Type name (case insensitive)
106     """
107
108     return NAMES_TO_CANONICAL_TYPES.get(type_name.lower())
109
110
111 def validate_value_type(value, type_name):
112     """
113     Validate that a value is of a specific type. Supports Python, YAML, and TOSCA type names and
114     aliases.
115
116     :param type_name: type name (case insensitive)
117     :raises ~exceptions.ValueError: on type mismatch
118     """
119
120     the_type = canonical_type(type_name)
121     if the_type is None:
122         raise RuntimeError('Unsupported type name: {0}'.format(type_name))
123
124     # The following Python types do not inherit from the canonical type, but are considered valid
125     if (the_type is unicode) and isinstance(value, str):
126         return
127     if (the_type is list) and isinstance(value, tuple):
128         return
129
130     if not isinstance(value, the_type):
131         raise ValueError('Value {0} is not of type {1}'.format(value, type_name))
132
133
134 def convert_value_to_type(str_value, python_type_name):
135     """
136     Converts a value to a specific Python primitive type.
137
138     :param python_type_name: Python primitive type name (case insensitive)
139     :raises ~exceptions.ValueError: for unsupported types or conversion failure
140     """
141
142     python_type_name = python_type_name.lower()
143     try:
144         if python_type_name in ('str', 'unicode'):
145             return str_value.decode('utf-8')
146         elif python_type_name == 'int':
147             return int(str_value)
148         elif python_type_name == 'bool':
149             return bool(str_value)
150         elif python_type_name == 'float':
151             return float(str_value)
152         else:
153             raise ValueError('Unsupported Python type name: {0}'.format(python_type_name))
154     except ValueError:
155         raise ValueError('Failed to to convert {0} to {1}'.format(str_value,
156                                                                   python_type_name))