123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- __all__ = ["hashable", "transitive_get", "raises", "reverse_dict", "xfail", "freeze"]
- def hashable(x):
- try:
- hash(x)
- return True
- except TypeError:
- return False
- def transitive_get(key, d):
- """ Transitive dict.get
- >>> d = {1: 2, 2: 3, 3: 4}
- >>> d.get(1)
- 2
- >>> transitive_get(1, d)
- 4
- """
- while hashable(key) and key in d:
- key = d[key]
- return key
- def raises(err, lamda):
- try:
- lamda()
- return False
- except err:
- return True
- # Taken from theano/theano/gof/sched.py
- # Avoids licensing issues because this was written by Matthew Rocklin
- def _toposort(edges):
- """ Topological sort algorithm by Kahn [1] - O(nodes + vertices)
- inputs:
- edges - a dict of the form {a: {b, c}} where b and c depend on a
- outputs:
- L - an ordered list of nodes that satisfy the dependencies of edges
- >>> # xdoctest: +SKIP
- >>> _toposort({1: (2, 3), 2: (3, )})
- [1, 2, 3]
- Closely follows the wikipedia page [2]
- [1] Kahn, Arthur B. (1962), "Topological sorting of large networks",
- Communications of the ACM
- [2] http://en.wikipedia.org/wiki/Toposort#Algorithms
- """
- incoming_edges = reverse_dict(edges)
- incoming_edges = {k: set(val) for k, val in incoming_edges.items()}
- S = ({v for v in edges if v not in incoming_edges})
- L = []
- while S:
- n = S.pop()
- L.append(n)
- for m in edges.get(n, ()):
- assert n in incoming_edges[m]
- incoming_edges[m].remove(n)
- if not incoming_edges[m]:
- S.add(m)
- if any(incoming_edges.get(v, None) for v in edges):
- raise ValueError("Input has cycles")
- return L
- def reverse_dict(d):
- """Reverses direction of dependence dict
- >>> d = {'a': (1, 2), 'b': (2, 3), 'c':()}
- >>> reverse_dict(d) # doctest: +SKIP
- {1: ('a',), 2: ('a', 'b'), 3: ('b',)}
- :note: dict order are not deterministic. As we iterate on the
- input dict, it make the output of this function depend on the
- dict order. So this function output order should be considered
- as undeterministic.
- """
- result = {} # type: ignore[var-annotated]
- for key in d:
- for val in d[key]:
- result[val] = result.get(val, tuple()) + (key, )
- return result
- def xfail(func):
- try:
- func()
- raise Exception("XFailed test passed") # pragma:nocover
- except Exception:
- pass
- def freeze(d):
- """ Freeze container to hashable form
- >>> freeze(1)
- 1
- >>> freeze([1, 2])
- (1, 2)
- >>> freeze({1: 2}) # doctest: +SKIP
- frozenset([(1, 2)])
- """
- if isinstance(d, dict):
- return frozenset(map(freeze, d.items()))
- if isinstance(d, set):
- return frozenset(map(freeze, d))
- if isinstance(d, (tuple, list)):
- return tuple(map(freeze, d))
- return d
|