in src/cfnlint/decode/node.py [0:0]
def create_dict_node_class(cls):
"""
Create dynamic node class
"""
class node_class(cls):
"""Node class created based on the input class"""
def __init__(self, x, start_mark, end_mark):
try:
cls.__init__(self, x)
except TypeError:
cls.__init__(self)
self.start_mark = start_mark
self.end_mark = end_mark
self.condition_functions = ['Fn::If']
def __deepcopy__(self, memo):
result = dict_node(self, self.start_mark, self.end_mark)
memo[id(self)] = result
for k, v in self.items():
result[deepcopy(k)] = deepcopy(v, memo)
return result
def __copy__(self):
return self
def is_function_returning_object(self, mappings=None):
"""
Check if an object is using a function that could return an object
Return True when
Fn::Select:
- 0 # or any number
- !FindInMap [mapname, key, value] # or any mapname, key, value
Otherwise False
"""
mappings = mappings or {}
if len(self) == 1:
for k, v in self.items():
if k in ['Fn::Select']:
if isinstance(v, list):
if len(v) == 2:
p_v = v[1]
if isinstance(p_v, dict):
if len(p_v) == 1:
for l_k in p_v.keys():
if l_k == 'Fn::FindInMap':
return True
return False
def get(self, key, default=None):
""" Override the default get """
if isinstance(default, dict):
default = dict_node(default, self.start_mark, self.end_mark)
return super(node_class, self).get(key, default)
def get_safe(self, key, default=None, path=None, type_t=()):
"""
Get values in format
"""
path = path or []
if default == {}:
default = dict_node({}, self.start_mark, self.end_mark)
value = self.get(key, default)
if value is None and default is None:
# if default is None and value is None return empty list
return []
# if the value is the default make sure that the default value is of type_t when specified
if bool(type_t) and value == default and not isinstance(default, type_t):
raise ValueError('"default" type should be of "type_t"')
# when not a dict see if if the value is of the right type
results = []
if not isinstance(value, (dict)):
if isinstance(value, type_t) or not type_t:
return [(value, (path[:] + [key]))]
else:
for sub_v, sub_path in value.items_safe(path + [key]):
if isinstance(sub_v, type_t) or not type_t:
results.append((sub_v, sub_path))
return results
def clean(self):
"""Clean object to remove any Ref AWS::NoValue"""
result = dict_node({}, self.start_mark, self.end_mark)
for k, v in self.items():
if isinstance(v, dict) and len(v) == 1:
if v.get('Ref') == 'AWS::NoValue':
continue
result[k] = v
return result
def items_safe(self, path=None, type_t=()):
"""Get items while handling IFs"""
path = path or []
if len(self) == 1:
for k, v in self.items():
if k == 'Fn::If':
if isinstance(v, list):
if len(v) == 3:
for i, if_v in enumerate(v[1:]):
if isinstance(if_v, dict):
# yield from if_v.items_safe(path[:] + [k, i - 1])
# Python 2.7 support
for items, p in if_v.items_safe(path[:] + [k, i + 1]):
if isinstance(items, type_t) or not type_t:
yield items, p
elif isinstance(if_v, list):
if isinstance(if_v, type_t) or not type_t:
yield if_v, path[:] + [k, i + 1]
else:
if isinstance(if_v, type_t) or not type_t:
yield if_v, path[:] + [k, i + 1]
elif not (k == 'Ref' and v == 'AWS::NoValue'):
if isinstance(self, type_t) or not type_t:
yield self.clean(), path[:]
else:
if isinstance(self, type_t) or not type_t:
yield self.clean(), path[:]
def __getattr__(self, name):
raise TemplateAttributeError('%s.%s is invalid' % (self.__class__.__name__, name))
node_class.__name__ = '%s_node' % cls.__name__
return node_class