summaryrefslogtreecommitdiffstats
path: root/lib/ansible/module_utils/common/collections.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/module_utils/common/collections.py')
-rw-r--r--lib/ansible/module_utils/common/collections.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/ansible/module_utils/common/collections.py b/lib/ansible/module_utils/common/collections.py
new file mode 100644
index 0000000..fdb9108
--- /dev/null
+++ b/lib/ansible/module_utils/common/collections.py
@@ -0,0 +1,112 @@
+# Copyright: (c) 2018, Sviatoslav Sydorenko <ssydoren@redhat.com>
+# Copyright: (c) 2018, Ansible Project
+# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
+"""Collection of low-level utility functions."""
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+from ansible.module_utils.six import binary_type, text_type
+from ansible.module_utils.common._collections_compat import Hashable, Mapping, MutableMapping, Sequence
+
+
+class ImmutableDict(Hashable, Mapping):
+ """Dictionary that cannot be updated"""
+ def __init__(self, *args, **kwargs):
+ self._store = dict(*args, **kwargs)
+
+ def __getitem__(self, key):
+ return self._store[key]
+
+ def __iter__(self):
+ return self._store.__iter__()
+
+ def __len__(self):
+ return self._store.__len__()
+
+ def __hash__(self):
+ return hash(frozenset(self.items()))
+
+ def __eq__(self, other):
+ try:
+ if self.__hash__() == hash(other):
+ return True
+ except TypeError:
+ pass
+
+ return False
+
+ def __repr__(self):
+ return 'ImmutableDict({0})'.format(repr(self._store))
+
+ def union(self, overriding_mapping):
+ """
+ Create an ImmutableDict as a combination of the original and overriding_mapping
+
+ :arg overriding_mapping: A Mapping of replacement and additional items
+ :return: A copy of the ImmutableDict with key-value pairs from the overriding_mapping added
+
+ If any of the keys in overriding_mapping are already present in the original ImmutableDict,
+ the overriding_mapping item replaces the one in the original ImmutableDict.
+ """
+ return ImmutableDict(self._store, **overriding_mapping)
+
+ def difference(self, subtractive_iterable):
+ """
+ Create an ImmutableDict as a combination of the original minus keys in subtractive_iterable
+
+ :arg subtractive_iterable: Any iterable containing keys that should not be present in the
+ new ImmutableDict
+ :return: A copy of the ImmutableDict with keys from the subtractive_iterable removed
+ """
+ remove_keys = frozenset(subtractive_iterable)
+ keys = (k for k in self._store.keys() if k not in remove_keys)
+ return ImmutableDict((k, self._store[k]) for k in keys)
+
+
+def is_string(seq):
+ """Identify whether the input has a string-like type (inclding bytes)."""
+ # AnsibleVaultEncryptedUnicode inherits from Sequence, but is expected to be a string like object
+ return isinstance(seq, (text_type, binary_type)) or getattr(seq, '__ENCRYPTED__', False)
+
+
+def is_iterable(seq, include_strings=False):
+ """Identify whether the input is an iterable."""
+ if not include_strings and is_string(seq):
+ return False
+
+ try:
+ iter(seq)
+ return True
+ except TypeError:
+ return False
+
+
+def is_sequence(seq, include_strings=False):
+ """Identify whether the input is a sequence.
+
+ Strings and bytes are not sequences here,
+ unless ``include_string`` is ``True``.
+
+ Non-indexable things are never of a sequence type.
+ """
+ if not include_strings and is_string(seq):
+ return False
+
+ return isinstance(seq, Sequence)
+
+
+def count(seq):
+ """Returns a dictionary with the number of appearances of each element of the iterable.
+
+ Resembles the collections.Counter class functionality. It is meant to be used when the
+ code is run on Python 2.6.* where collections.Counter is not available. It should be
+ deprecated and replaced when support for Python < 2.7 is dropped.
+ """
+ if not is_iterable(seq):
+ raise Exception('Argument provided is not an iterable')
+ counters = dict()
+ for elem in seq:
+ counters[elem] = counters.get(elem, 0) + 1
+ return counters