compat.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 Joshua Bronson. All Rights Reserved.
  3. #
  4. # This Source Code Form is subject to the terms of the Mozilla Public
  5. # License, v. 2.0. If a copy of the MPL was not distributed with this
  6. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. u"""Compatibility helpers.
  8. .. py:attribute:: PY2
  9. True iff running on Python < 3.
  10. .. py:attribute:: PYPY
  11. True iff running on PyPy.
  12. .. py:attribute:: viewkeys
  13. ``viewkeys(x) → x.viewkeys() if PY2 else x.keys()``
  14. .. py:attribute:: viewvalues
  15. ``viewvalues(x) → x.viewvalues() if PY2 else x.values()``
  16. .. py:attribute:: viewitems
  17. ``viewitems(x) → x.viewitems() if PY2 else x.items()``
  18. .. py:attribute:: iterkeys
  19. ``iterkeys(x) → x.iterkeys() if PY2 else iter(x.keys())``
  20. .. py:attribute:: itervalues
  21. ``itervalues(x) → x.itervalues() if PY2 else iter(x.values())``
  22. .. py:attribute:: iteritems
  23. ``iteritems(x) → x.iteritems() if PY2 else iter(x.items())``
  24. .. py:attribute:: izip
  25. ``itertools.izip() if PY2 else zip``
  26. """
  27. from operator import methodcaller
  28. from platform import python_implementation
  29. from sys import version_info
  30. from warnings import warn
  31. PYMAJOR, PYMINOR = version_info[:2]
  32. PY2 = PYMAJOR == 2
  33. PYIMPL = python_implementation()
  34. CPY = PYIMPL == 'CPython'
  35. PYPY = PYIMPL == 'PyPy'
  36. DICTS_ORDERED = PYPY or (CPY and (PYMAJOR, PYMINOR) >= (3, 6))
  37. # Without the following, pylint gives lots of false positives.
  38. # pylint: disable=invalid-name,unused-import,ungrouped-imports
  39. if PY2:
  40. if PYMINOR < 7: # pragma: no cover
  41. warn('Python < 2.7 is unsupported.')
  42. viewkeys = methodcaller('viewkeys')
  43. viewvalues = methodcaller('viewvalues')
  44. viewitems = methodcaller('viewitems')
  45. iterkeys = methodcaller('iterkeys')
  46. itervalues = methodcaller('itervalues')
  47. iteritems = methodcaller('iteritems')
  48. # abstractproperty deprecated in Python 3.3 in favor of using @property with @abstractmethod.
  49. # Before 3.3, this silently fails to detect when an abstract property has not been overridden.
  50. from abc import abstractproperty
  51. from itertools import izip # pylint: disable=no-name-in-module
  52. # In Python 3, the collections ABCs were moved into collections.abc, which does not exist in
  53. # Python 2. Support for importing them directly from collections is dropped in Python 3.8.
  54. from collections import ( # noqa: F401 (imported but unused)
  55. Mapping, MutableMapping, KeysView, ItemsView)
  56. else:
  57. # Assume Python 3 when not PY2, but explicitly check before showing this warning.
  58. if PYMAJOR == 3 and PYMINOR < 3: # pragma: no cover
  59. warn('Python3 < 3.3 is unsupported.')
  60. viewkeys = methodcaller('keys')
  61. viewvalues = methodcaller('values')
  62. viewitems = methodcaller('items')
  63. def _compose(f, g):
  64. return lambda x: f(g(x))
  65. iterkeys = _compose(iter, viewkeys)
  66. itervalues = _compose(iter, viewvalues)
  67. iteritems = _compose(iter, viewitems)
  68. from abc import abstractmethod
  69. abstractproperty = _compose(property, abstractmethod)
  70. izip = zip
  71. from collections.abc import ( # noqa: F401 (imported but unused)
  72. Mapping, MutableMapping, KeysView, ItemsView)