added slice filter for dicts

also minor exception optimization
This commit is contained in:
Brian Coca 2017-12-15 22:32:56 -05:00 committed by Brian Coca
parent 107934241e
commit 73a003aa50

View file

@ -47,7 +47,7 @@ try:
except: except:
HAS_PASSLIB = False HAS_PASSLIB = False
from ansible import errors from ansible.errors import AnsibleFilterError
from ansible.module_utils.six import iteritems, string_types, integer_types from ansible.module_utils.six import iteritems, string_types, integer_types
from ansible.module_utils.six.moves import reduce, shlex_quote from ansible.module_utils.six.moves import reduce, shlex_quote
from ansible.module_utils._text import to_bytes, to_text from ansible.module_utils._text import to_bytes, to_text
@ -135,7 +135,7 @@ def strftime(string_format, second=None):
try: try:
second = int(second) second = int(second)
except: except:
raise errors.AnsibleFilterError('Invalid value for epoch value (%s)' % second) raise AnsibleFilterError('Invalid value for epoch value (%s)' % second)
return time.strftime(string_format, time.localtime(second)) return time.strftime(string_format, time.localtime(second))
@ -184,7 +184,7 @@ def regex_search(value, regex, *args, **kwargs):
match = int(re.match(r'\\(\d+)', arg).group(1)) match = int(re.match(r'\\(\d+)', arg).group(1))
groups.append(match) groups.append(match)
else: else:
raise errors.AnsibleFilterError('Unknown argument') raise AnsibleFilterError('Unknown argument')
flags = 0 flags = 0
if kwargs.get('ignorecase'): if kwargs.get('ignorecase'):
@ -236,10 +236,10 @@ def rand(environment, end, start=None, step=None, seed=None):
return r.randrange(start, end, step) return r.randrange(start, end, step)
elif hasattr(end, '__iter__'): elif hasattr(end, '__iter__'):
if start or step: if start or step:
raise errors.AnsibleFilterError('start and step can only be used with integer values') raise AnsibleFilterError('start and step can only be used with integer values')
return r.choice(end) return r.choice(end)
else: else:
raise errors.AnsibleFilterError('random can only be used on sequences and integers') raise AnsibleFilterError('random can only be used on sequences and integers')
def randomize_list(mylist, seed=None): def randomize_list(mylist, seed=None):
@ -288,7 +288,7 @@ def get_encrypted_password(password, hashtype='sha512', salt=None):
if not HAS_PASSLIB: if not HAS_PASSLIB:
if sys.platform.startswith('darwin'): if sys.platform.startswith('darwin'):
raise errors.AnsibleFilterError('|password_hash requires the passlib python module to generate password hashes on Mac OS X/Darwin') raise AnsibleFilterError('|password_hash requires the passlib python module to generate password hashes on Mac OS X/Darwin')
saltstring = "$%s$%s" % (cryptmethod[hashtype], salt) saltstring = "$%s$%s" % (cryptmethod[hashtype], salt)
encrypted = crypt.crypt(password, saltstring) encrypted = crypt.crypt(password, saltstring)
else: else:
@ -313,14 +313,14 @@ def mandatory(a):
''' Make a variable mandatory ''' ''' Make a variable mandatory '''
if isinstance(a, Undefined): if isinstance(a, Undefined):
raise errors.AnsibleFilterError('Mandatory variable not defined.') raise AnsibleFilterError('Mandatory variable not defined.')
return a return a
def combine(*terms, **kwargs): def combine(*terms, **kwargs):
recursive = kwargs.get('recursive', False) recursive = kwargs.get('recursive', False)
if len(kwargs) > 1 or (len(kwargs) == 1 and 'recursive' not in kwargs): if len(kwargs) > 1 or (len(kwargs) == 1 and 'recursive' not in kwargs):
raise errors.AnsibleFilterError("'recursive' is the only valid keyword argument") raise AnsibleFilterError("'recursive' is the only valid keyword argument")
dicts = [] dicts = []
for t in terms: for t in terms:
@ -329,7 +329,7 @@ def combine(*terms, **kwargs):
elif isinstance(t, list): elif isinstance(t, list):
dicts.append(combine(*t, **kwargs)) dicts.append(combine(*t, **kwargs))
else: else:
raise errors.AnsibleFilterError("|combine expects dictionaries, got " + repr(t)) raise AnsibleFilterError("|combine expects dictionaries, got " + repr(t))
if recursive: if recursive:
return reduce(merge_hash, dicts) return reduce(merge_hash, dicts)
@ -486,6 +486,22 @@ def flatten(mylist, levels=None):
return ret return ret
def dict_slice(mydict, keys):
''' takes a dictionary and a list of keys and returns a list of values corresponding to those keys, if they exist '''
if not isinstance(mydict, MutableMapping):
raise AnsibleFilterError("The slice filter requires a mapping to operate on, got a %s." % type(mydict))
if not isinstance(keys, MutableSequence):
if isinstance(keys, string_types):
keys = [keys]
else:
AnsibleFilterError("The slice filter requires a key or list of keys, got %s instead." % type(keys))
return [mydict[key] for key in keys if key in mydict]
class FilterModule(object): class FilterModule(object):
''' Ansible core jinja2 filters ''' ''' Ansible core jinja2 filters '''
@ -493,7 +509,6 @@ class FilterModule(object):
return { return {
# jinja2 overrides # jinja2 overrides
'groupby': do_groupby, 'groupby': do_groupby,
'flatten': flatten,
# base 64 # base 64
'b64decode': b64decode, 'b64decode': b64decode,
@ -512,9 +527,6 @@ class FilterModule(object):
'to_nice_yaml': to_nice_yaml, 'to_nice_yaml': to_nice_yaml,
'from_yaml': from_yaml, 'from_yaml': from_yaml,
# date
'to_datetime': to_datetime,
# path # path
'basename': partial(unicode_wrap, os.path.basename), 'basename': partial(unicode_wrap, os.path.basename),
'dirname': partial(unicode_wrap, os.path.dirname), 'dirname': partial(unicode_wrap, os.path.dirname),
@ -526,8 +538,12 @@ class FilterModule(object):
'win_dirname': partial(unicode_wrap, ntpath.dirname), 'win_dirname': partial(unicode_wrap, ntpath.dirname),
'win_splitdrive': partial(unicode_wrap, ntpath.splitdrive), 'win_splitdrive': partial(unicode_wrap, ntpath.splitdrive),
# value as boolean # file glob
'fileglob': fileglob,
# types
'bool': to_bool, 'bool': to_bool,
'to_datetime': to_datetime,
# date formating # date formating
'strftime': strftime, 'strftime': strftime,
@ -546,9 +562,6 @@ class FilterModule(object):
'password_hash': get_encrypted_password, 'password_hash': get_encrypted_password,
'hash': get_hash, 'hash': get_hash,
# file glob
'fileglob': fileglob,
# regex # regex
'regex_replace': regex_replace, 'regex_replace': regex_replace,
'regex_escape': regex_escape, 'regex_escape': regex_escape,
@ -558,22 +571,22 @@ class FilterModule(object):
# ? : ; # ? : ;
'ternary': ternary, 'ternary': ternary,
# list
# random stuff # random stuff
'random': rand, 'random': rand,
'shuffle': randomize_list, 'shuffle': randomize_list,
# undefined # undefined
'mandatory': mandatory, 'mandatory': mandatory,
# merge dicts
'combine': combine,
# comment-style decoration # comment-style decoration
'comment': comment, 'comment': comment,
# array and dict lookups
'extract': extract,
# debug # debug
'type_debug': lambda o: o.__class__.__name__, 'type_debug': lambda o: o.__class__.__name__,
# Data structures
'combine': combine,
'extract': extract,
'flatten': flatten,
'slice': dict_slice,
} }