| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| # | |
| # Copyright (C) 2017-2020 The Project X-Ray Authors. | |
| # | |
| # Use of this source code is governed by a ISC-style | |
| # license that can be found in the LICENSE file or at | |
| # https://opensource.org/licenses/ISC | |
| # | |
| # SPDX-License-Identifier: ISC | |
| """ | |
| Python 3 removed the 'cmp' function and raises a Type error when you try to | |
| compare different types. This module recreates Python 2 style 'cmp' function | |
| which produces a "total ordering" for mixed type lists. | |
| """ | |
| import functools | |
| import itertools | |
| def cmp(a, b): | |
| """ | |
| >>> cmp(1, 1) | |
| 0 | |
| >>> cmp('A', 'A') | |
| 0 | |
| >>> cmp(None, None) | |
| 0 | |
| >>> cmp(('A', 'B'), ('A', 'B')) | |
| 0 | |
| >>> cmp(['A', 'B'], ('A', 'B')) | |
| 0 | |
| >>> cmp((1, 2), (1, 2)) | |
| 0 | |
| >>> cmp((1, 2), [1, 2]) | |
| 0 | |
| >>> cmp(1, 2) | |
| -1 | |
| >>> cmp('A', 'B') | |
| -1 | |
| >>> cmp(('A', 'B'), ('A', 'C')) | |
| -1 | |
| >>> cmp(['A', 'B'], ('A', 'C')) | |
| -1 | |
| >>> cmp((1, 2), (1, 3)) | |
| -1 | |
| >>> cmp((1, 2), [1, 3]) | |
| -1 | |
| >>> cmp(2, 1) | |
| 1 | |
| >>> cmp('B', 'A') | |
| 1 | |
| >>> cmp(('A', 'C'), ('A', 'B')) | |
| 1 | |
| >>> cmp(['A', 'C'], ('A', 'B')) | |
| 1 | |
| >>> cmp((1, 3), (1, 2)) | |
| 1 | |
| >>> cmp((1, 3), [1, 2]) | |
| 1 | |
| >>> cmp(1, None) | |
| 1 | |
| >>> cmp('A', None) | |
| 1 | |
| >>> cmp(('A', 'B'), None) | |
| 1 | |
| >>> cmp(['A', 'B'], None) | |
| 1 | |
| >>> cmp((1, 2), None) | |
| 1 | |
| >>> cmp((1, 2), None) | |
| 1 | |
| >>> cmp(None, 2) | |
| -1 | |
| >>> cmp(None, 'B') | |
| -1 | |
| >>> cmp(None, ('A', 'B')) | |
| -1 | |
| >>> cmp(None, ('A', 'C')) | |
| -1 | |
| >>> cmp(None, (1, 2)) | |
| -1 | |
| >>> cmp(None, [1, 3]) | |
| -1 | |
| >>> cmp(1, 'A') | |
| -1 | |
| >>> cmp('A', 1) | |
| 1 | |
| >>> cmp(('A', 'B'), 1) | |
| 1 | |
| >>> cmp(1, ['A', 'B']) | |
| -1 | |
| >>> cmp((1, 2), 1) | |
| 1 | |
| >>> cmp(1, (1, 2)) | |
| -1 | |
| >>> cmp('A', 'AA') | |
| -1 | |
| >>> cmp('AA', 'A') | |
| 1 | |
| >>> cmp(b'A', b'A') | |
| 0 | |
| >>> cmp(b'A', b'AA') | |
| -1 | |
| >>> cmp(b'AA', b'A') | |
| 1 | |
| >>> def bit(*args): | |
| ... return args | |
| >>> a = ('CLBLL', 'L', 'SLICEL', ('X', 0), 'AFFMUX', 'XOR') | |
| >>> b = ('CLBLL', 'L', 'SLICEL', ('X', 0), 'AFFMUX', ('F', 7)) | |
| >>> cmp(a, b) | |
| -1 | |
| >>> cmp(b, a) | |
| 1 | |
| """ | |
| if not isinstance(a, (str, bytes)) and not isinstance(b, (str, bytes)): | |
| try: | |
| for i, j in itertools.zip_longest(iter(a), iter(b)): | |
| r = cmp(i, j) | |
| if r != 0: | |
| return r | |
| return 0 | |
| except TypeError: | |
| pass | |
| if type(a) == type(b): | |
| if a == b: | |
| return 0 | |
| elif a < b: | |
| return -1 | |
| elif a > b: | |
| return 1 | |
| else: | |
| raise SystemError | |
| return cmp(a.__class__.__name__, b.__class__.__name__) | |
| cmp_key = functools.cmp_to_key(cmp) | |
| if __name__ == "__main__": | |
| import doctest | |
| doctest.testmod() |