Mercurial > p > roundup > code
diff roundup/anypy/cmp_.py @ 5481:9a09719b0d8e
helper to allow comparing dicts and None values in Python 3
| author | Christof Meerwald <cmeerw@cmeerw.org> |
|---|---|
| date | Wed, 01 Aug 2018 22:03:50 +0100 |
| parents | |
| children | 142553f58694 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/roundup/anypy/cmp_.py Wed Aug 01 22:03:50 2018 +0100 @@ -0,0 +1,95 @@ +try: + None < 0 + def NoneAndDictComparable(v): + return v +except TypeError: + # comparator to allow comparisons against None and dict + # comparisons (these were allowed in Python 2, but aren't allowed + # in Python 3 any more) + class NoneAndDictComparable(object): + def __init__(self, value): + self.value = value + + def __cmp__(self, other): + if not isinstance(other, self.__class__): + raise TypeError('not comparable') + + if self.value == other.value: + return 0 + + elif self.value is None: + return -1 + + elif other.value is None: + return 1 + + elif type(self.value) == tuple and type(other.value) == tuple: + for lhs, rhs in zip(self.value, other.value): + lhsCmp = NoneAndDictComparable(lhs) + rhsCmp = NoneAndDictComparable(rhs) + result = lhsCmp.__cmp__(rhsCmp) + if result != 0: + return result + + return len(self.value) - len(other.value) + + elif type(self.value) == dict and type(other.value) == dict: + diff = len(self.value) - len(other.value) + if diff == 0: + lhsItems = tuple(sorted(self.value.items(), + key=NoneAndDictComparable)) + rhsItems = tuple(sorted(other.value.items(), + key=NoneAndDictComparable)) + return -1 if NoneAndDictComparable(lhsItems) < NoneAndDictComparable(rhsItems) else 1 + else: + return diff + + elif self.value < other.value: + return -1 + + else: + return 1 + + def __eq__(self, other): + return self.__cmp__(other) == 0 + def __ne__(self, other): + return self.__cmp__(other) != 0 + def __lt__(self, other): + return self.__cmp__(other) < 0 + def __le__(self, other): + return self.__cmp__(other) <= 0 + def __ge__(self, other): + return self.__cmp__(other) >= 0 + def __gt__(self, other): + return self.__cmp__(other) > 0 + +def _test(): + Comp = NoneAndDictComparable + + assert Comp(None) < Comp(0) + assert Comp(None) < Comp('') + assert Comp(None) < Comp({}) + assert Comp((0, None)) < Comp((0, 0)) + assert not Comp(0) < Comp(None) + assert not Comp('') < Comp(None) + assert not Comp({}) < Comp(None) + assert not Comp((0, 0)) < Comp((0, None)) + + assert Comp((0, 0)) < Comp((0, 0, None)) + assert Comp((0, None, None)) < Comp((0, 0, 0)) + + assert Comp(0) < Comp(1) + assert Comp(1) > Comp(0) + assert not Comp(1) < Comp(0) + assert not Comp(0) > Comp(0) + + assert Comp({ 0: None }) < Comp({ 0: 0 }) + assert Comp({ 0: 0 }) < Comp({ 0: 1 }) + + assert Comp({ 0: 0 }) == Comp({ 0: 0 }) + assert Comp({ 0: 0 }) != Comp({ 0: 1 }) + assert Comp({ 0: 0, 1: 1 }) > Comp({ 0: 1 }) + assert Comp({ 0: 0, 1: 1 }) < Comp({ 0: 0, 2: 2 }) + +if __name__ == '__main__': + _test()
