py3k.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. """
  2. Python 3.X compatibility tools.
  3. While this file was originally intented 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. try:
  19. from pathlib import Path, PurePath
  20. except ImportError:
  21. Path = PurePath = None
  22. if sys.version_info[0] >= 3:
  23. import io
  24. try:
  25. import pickle5 as pickle
  26. except ImportError:
  27. import pickle
  28. long = int
  29. integer_types = (int,)
  30. basestring = str
  31. unicode = str
  32. bytes = bytes
  33. def asunicode(s):
  34. if isinstance(s, bytes):
  35. return s.decode('latin1')
  36. return str(s)
  37. def asbytes(s):
  38. if isinstance(s, bytes):
  39. return s
  40. return str(s).encode('latin1')
  41. def asstr(s):
  42. if isinstance(s, bytes):
  43. return s.decode('latin1')
  44. return str(s)
  45. def isfileobj(f):
  46. return isinstance(f, (io.FileIO, io.BufferedReader, io.BufferedWriter))
  47. def open_latin1(filename, mode='r'):
  48. return open(filename, mode=mode, encoding='iso-8859-1')
  49. def sixu(s):
  50. return s
  51. strchar = 'U'
  52. else:
  53. import cpickle as pickle
  54. bytes = str
  55. long = long
  56. basestring = basestring
  57. unicode = unicode
  58. integer_types = (int, long)
  59. asbytes = str
  60. asstr = str
  61. strchar = 'S'
  62. def isfileobj(f):
  63. return isinstance(f, file)
  64. def asunicode(s):
  65. if isinstance(s, unicode):
  66. return s
  67. return str(s).decode('ascii')
  68. def open_latin1(filename, mode='r'):
  69. return open(filename, mode=mode)
  70. def sixu(s):
  71. return unicode(s, 'unicode_escape')
  72. def getexception():
  73. return sys.exc_info()[1]
  74. def asbytes_nested(x):
  75. if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
  76. return [asbytes_nested(y) for y in x]
  77. else:
  78. return asbytes(x)
  79. def asunicode_nested(x):
  80. if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
  81. return [asunicode_nested(y) for y in x]
  82. else:
  83. return asunicode(x)
  84. def is_pathlib_path(obj):
  85. """
  86. Check whether obj is a pathlib.Path object.
  87. Prefer using `isinstance(obj, os_PathLike)` instead of this function.
  88. """
  89. return Path is not None and isinstance(obj, Path)
  90. # from Python 3.7
  91. class contextlib_nullcontext(object):
  92. """Context manager that does no additional processing.
  93. Used as a stand-in for a normal context manager, when a particular
  94. block of code is only sometimes used with a normal context manager:
  95. cm = optional_cm if condition else nullcontext()
  96. with cm:
  97. # Perform operation, using optional_cm if condition is True
  98. """
  99. def __init__(self, enter_result=None):
  100. self.enter_result = enter_result
  101. def __enter__(self):
  102. return self.enter_result
  103. def __exit__(self, *excinfo):
  104. pass
  105. if sys.version_info[0] >= 3 and sys.version_info[1] >= 4:
  106. def npy_load_module(name, fn, info=None):
  107. """
  108. Load a module.
  109. .. versionadded:: 1.11.2
  110. Parameters
  111. ----------
  112. name : str
  113. Full module name.
  114. fn : str
  115. Path to module file.
  116. info : tuple, optional
  117. Only here for backward compatibility with Python 2.*.
  118. Returns
  119. -------
  120. mod : module
  121. """
  122. import importlib.machinery
  123. return importlib.machinery.SourceFileLoader(name, fn).load_module()
  124. else:
  125. def npy_load_module(name, fn, info=None):
  126. """
  127. Load a module.
  128. .. versionadded:: 1.11.2
  129. Parameters
  130. ----------
  131. name : str
  132. Full module name.
  133. fn : str
  134. Path to module file.
  135. info : tuple, optional
  136. Information as returned by `imp.find_module`
  137. (suffix, mode, type).
  138. Returns
  139. -------
  140. mod : module
  141. """
  142. import imp
  143. if info is None:
  144. path = os.path.dirname(fn)
  145. fo, fn, info = imp.find_module(name, [path])
  146. else:
  147. fo = open(fn, info[1])
  148. try:
  149. mod = imp.load_module(name, fo, fn, info)
  150. finally:
  151. fo.close()
  152. return mod
  153. # backport abc.ABC
  154. import abc
  155. if sys.version_info[:2] >= (3, 4):
  156. abc_ABC = abc.ABC
  157. else:
  158. abc_ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})
  159. # Backport os.fs_path, os.PathLike, and PurePath.__fspath__
  160. if sys.version_info[:2] >= (3, 6):
  161. os_fspath = os.fspath
  162. os_PathLike = os.PathLike
  163. else:
  164. def _PurePath__fspath__(self):
  165. return str(self)
  166. class os_PathLike(abc_ABC):
  167. """Abstract base class for implementing the file system path protocol."""
  168. @abc.abstractmethod
  169. def __fspath__(self):
  170. """Return the file system path representation of the object."""
  171. raise NotImplementedError
  172. @classmethod
  173. def __subclasshook__(cls, subclass):
  174. if PurePath is not None and issubclass(subclass, PurePath):
  175. return True
  176. return hasattr(subclass, '__fspath__')
  177. def os_fspath(path):
  178. """Return the path representation of a path-like object.
  179. If str or bytes is passed in, it is returned unchanged. Otherwise the
  180. os.PathLike interface is used to get the path representation. If the
  181. path representation is not str or bytes, TypeError is raised. If the
  182. provided path is not str, bytes, or os.PathLike, TypeError is raised.
  183. """
  184. if isinstance(path, (str, bytes)):
  185. return path
  186. # Work from the object's type to match method resolution of other magic
  187. # methods.
  188. path_type = type(path)
  189. try:
  190. path_repr = path_type.__fspath__(path)
  191. except AttributeError:
  192. if hasattr(path_type, '__fspath__'):
  193. raise
  194. elif PurePath is not None and issubclass(path_type, PurePath):
  195. return _PurePath__fspath__(path)
  196. else:
  197. raise TypeError("expected str, bytes or os.PathLike object, "
  198. "not " + path_type.__name__)
  199. if isinstance(path_repr, (str, bytes)):
  200. return path_repr
  201. else:
  202. raise TypeError("expected {}.__fspath__() to return str or bytes, "
  203. "not {}".format(path_type.__name__,
  204. type(path_repr).__name__))