| from .utils import _toposort, groupby | |
| class AmbiguityWarning(Warning): | |
| pass | |
| def supercedes(a, b): | |
| """ A is consistent and strictly more specific than B """ | |
| return len(a) == len(b) and all(map(issubclass, a, b)) | |
| def consistent(a, b): | |
| """ It is possible for an argument list to satisfy both A and B """ | |
| return (len(a) == len(b) and | |
| all(issubclass(aa, bb) or issubclass(bb, aa) | |
| for aa, bb in zip(a, b))) | |
| def ambiguous(a, b): | |
| """ A is consistent with B but neither is strictly more specific """ | |
| return consistent(a, b) and not (supercedes(a, b) or supercedes(b, a)) | |
| def ambiguities(signatures): | |
| """ All signature pairs such that A is ambiguous with B """ | |
| signatures = list(map(tuple, signatures)) | |
| return {(a, b) for a in signatures for b in signatures | |
| if hash(a) < hash(b) | |
| and ambiguous(a, b) | |
| and not any(supercedes(c, a) and supercedes(c, b) | |
| for c in signatures)} | |
| def super_signature(signatures): | |
| """ A signature that would break ambiguities """ | |
| n = len(signatures[0]) | |
| assert all(len(s) == n for s in signatures) | |
| return [max([type.mro(sig[i]) for sig in signatures], key=len)[0] | |
| for i in range(n)] | |
| def edge(a, b, tie_breaker=hash): | |
| """ A should be checked before B | |
| Tie broken by tie_breaker, defaults to ``hash`` | |
| """ | |
| if supercedes(a, b): | |
| if supercedes(b, a): | |
| return tie_breaker(a) > tie_breaker(b) | |
| else: | |
| return True | |
| return False | |
| def ordering(signatures): | |
| """ A sane ordering of signatures to check, first to last | |
| Topoological sort of edges as given by ``edge`` and ``supercedes`` | |
| """ | |
| signatures = list(map(tuple, signatures)) | |
| edges = [(a, b) for a in signatures for b in signatures if edge(a, b)] | |
| edges = groupby(lambda x: x[0], edges) | |
| for s in signatures: | |
| if s not in edges: | |
| edges[s] = [] | |
| edges = {k: [b for a, b in v] for k, v in edges.items()} | |
| return _toposort(edges) | |