py3k.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. """
  2. Python 3.X compatibility tools.
  3. While this file was originally intended for Python 2 -> 3 transition,
  4. it is now used to create a compatibility layer between different
  5. minor versions of Python 3.
  6. While the active version of numpy may not support a given version of python, we
  7. allow downstream libraries to continue to use these shims for forward
  8. compatibility with numpy while they transition their code to newer versions of
  9. Python.
  10. """
  11. __all__ = ['bytes', 'asbytes', 'isfileobj', 'getexception', 'strchar',
  12. 'unicode', 'asunicode', 'asbytes_nested', 'asunicode_nested',
  13. 'asstr', 'open_latin1', 'long', 'basestring', 'sixu',
  14. 'integer_types', 'is_pathlib_path', 'npy_load_module', 'Path',
  15. 'pickle', 'contextlib_nullcontext', 'os_fspath', 'os_PathLike']
  16. import sys
  17. import os
  18. from pathlib import Path, PurePath
  19. import io
  20. import abc
  21. from abc import ABC as abc_ABC
  22. try:
  23. import pickle5 as pickle
  24. except ImportError:
  25. import pickle
  26. long = int
  27. integer_types = (int,)
  28. basestring = str
  29. unicode = str
  30. bytes = bytes
  31. def asunicode(s):
  32. if isinstance(s, bytes):
  33. return s.decode('latin1')
  34. return str(s)
  35. def asbytes(s):
  36. if isinstance(s, bytes):
  37. return s
  38. return str(s).encode('latin1')
  39. def asstr(s):
  40. if isinstance(s, bytes):
  41. return s.decode('latin1')
  42. return str(s)
  43. def isfileobj(f):
  44. return isinstance(f, (io.FileIO, io.BufferedReader, io.BufferedWriter))
  45. def open_latin1(filename, mode='r'):
  46. return open(filename, mode=mode, encoding='iso-8859-1')
  47. def sixu(s):
  48. return s
  49. strchar = 'U'
  50. def getexception():
  51. return sys.exc_info()[1]
  52. def asbytes_nested(x):
  53. if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
  54. return [asbytes_nested(y) for y in x]
  55. else:
  56. return asbytes(x)
  57. def asunicode_nested(x):
  58. if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
  59. return [asunicode_nested(y) for y in x]
  60. else:
  61. return asunicode(x)
  62. def is_pathlib_path(obj):
  63. """
  64. Check whether obj is a pathlib.Path object.
  65. Prefer using `isinstance(obj, os_PathLike)` instead of this function.
  66. """
  67. return Path is not None and isinstance(obj, Path)
  68. # from Python 3.7
  69. class contextlib_nullcontext:
  70. """Context manager that does no additional processing.
  71. Used as a stand-in for a normal context manager, when a particular
  72. block of code is only sometimes used with a normal context manager:
  73. cm = optional_cm if condition else nullcontext()
  74. with cm:
  75. # Perform operation, using optional_cm if condition is True
  76. """
  77. def __init__(self, enter_result=None):
  78. self.enter_result = enter_result
  79. def __enter__(self):
  80. return self.enter_result
  81. def __exit__(self, *excinfo):
  82. pass
  83. def npy_load_module(name, fn, info=None):
  84. """
  85. Load a module.
  86. .. versionadded:: 1.11.2
  87. Parameters
  88. ----------
  89. name : str
  90. Full module name.
  91. fn : str
  92. Path to module file.
  93. info : tuple, optional
  94. Only here for backward compatibility with Python 2.*.
  95. Returns
  96. -------
  97. mod : module
  98. """
  99. # Explicitly lazy import this to avoid paying the cost
  100. # of importing importlib at startup
  101. from importlib.machinery import SourceFileLoader
  102. return SourceFileLoader(name, fn).load_module()
  103. # Backport os.fs_path, os.PathLike, and PurePath.__fspath__
  104. if sys.version_info[:2] >= (3, 6):
  105. os_fspath = os.fspath
  106. os_PathLike = os.PathLike
  107. else:
  108. def _PurePath__fspath__(self):
  109. return str(self)
  110. class os_PathLike(abc_ABC):
  111. """Abstract base class for implementing the file system path protocol."""
  112. @abc.abstractmethod
  113. def __fspath__(self):
  114. """Return the file system path representation of the object."""
  115. raise NotImplementedError
  116. @classmethod
  117. def __subclasshook__(cls, subclass):
  118. if PurePath is not None and issubclass(subclass, PurePath):
  119. return True
  120. return hasattr(subclass, '__fspath__')
  121. def os_fspath(path):
  122. """Return the path representation of a path-like object.
  123. If str or bytes is passed in, it is returned unchanged. Otherwise the
  124. os.PathLike interface is used to get the path representation. If the
  125. path representation is not str or bytes, TypeError is raised. If the
  126. provided path is not str, bytes, or os.PathLike, TypeError is raised.
  127. """
  128. if isinstance(path, (str, bytes)):
  129. return path
  130. # Work from the object's type to match method resolution of other magic
  131. # methods.
  132. path_type = type(path)
  133. try:
  134. path_repr = path_type.__fspath__(path)
  135. except AttributeError:
  136. if hasattr(path_type, '__fspath__'):
  137. raise
  138. elif PurePath is not None and issubclass(path_type, PurePath):
  139. return _PurePath__fspath__(path)
  140. else:
  141. raise TypeError("expected str, bytes or os.PathLike object, "
  142. "not " + path_type.__name__)
  143. if isinstance(path_repr, (str, bytes)):
  144. return path_repr
  145. else:
  146. raise TypeError("expected {}.__fspath__() to return str or bytes, "
  147. "not {}".format(path_type.__name__,
  148. type(path_repr).__name__))