Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1from __future__ import absolute_import 

2 

3import io 

4import abc 

5import sys 

6import email 

7 

8 

9if sys.version_info > (3,): # pragma: nocover 

10 import builtins 

11 from configparser import ConfigParser 

12 from contextlib import suppress 

13 FileNotFoundError = builtins.FileNotFoundError 

14 IsADirectoryError = builtins.IsADirectoryError 

15 NotADirectoryError = builtins.NotADirectoryError 

16 PermissionError = builtins.PermissionError 

17 map = builtins.map 

18else: # pragma: nocover 

19 from backports.configparser import ConfigParser 

20 from itertools import imap as map # type: ignore 

21 from contextlib2 import suppress # noqa 

22 FileNotFoundError = IOError, OSError 

23 IsADirectoryError = IOError, OSError 

24 NotADirectoryError = IOError, OSError 

25 PermissionError = IOError, OSError 

26 

27if sys.version_info > (3, 5): # pragma: nocover 

28 import pathlib 

29else: # pragma: nocover 

30 import pathlib2 as pathlib 

31 

32try: 

33 ModuleNotFoundError = builtins.FileNotFoundError 

34except (NameError, AttributeError): # pragma: nocover 

35 ModuleNotFoundError = ImportError # type: ignore 

36 

37 

38if sys.version_info >= (3,): # pragma: nocover 

39 from importlib.abc import MetaPathFinder 

40else: # pragma: nocover 

41 class MetaPathFinder(object): 

42 __metaclass__ = abc.ABCMeta 

43 

44 

45__metaclass__ = type 

46__all__ = [ 

47 'install', 'NullFinder', 'MetaPathFinder', 'ModuleNotFoundError', 

48 'pathlib', 'ConfigParser', 'map', 'suppress', 'FileNotFoundError', 

49 'NotADirectoryError', 'email_message_from_string', 

50 ] 

51 

52 

53def install(cls): 

54 """ 

55 Class decorator for installation on sys.meta_path. 

56 

57 Adds the backport DistributionFinder to sys.meta_path and 

58 attempts to disable the finder functionality of the stdlib 

59 DistributionFinder. 

60 """ 

61 sys.meta_path.append(cls()) 

62 disable_stdlib_finder() 

63 return cls 

64 

65 

66def disable_stdlib_finder(): 

67 """ 

68 Give the backport primacy for discovering path-based distributions 

69 by monkey-patching the stdlib O_O. 

70 

71 See #91 for more background for rationale on this sketchy 

72 behavior. 

73 """ 

74 def matches(finder): 

75 return ( 

76 finder.__module__ == '_frozen_importlib_external' 

77 and hasattr(finder, 'find_distributions') 

78 ) 

79 for finder in filter(matches, sys.meta_path): # pragma: nocover 

80 del finder.find_distributions 

81 

82 

83class NullFinder: 

84 """ 

85 A "Finder" (aka "MetaClassFinder") that never finds any modules, 

86 but may find distributions. 

87 """ 

88 @staticmethod 

89 def find_spec(*args, **kwargs): 

90 return None 

91 

92 # In Python 2, the import system requires finders 

93 # to have a find_module() method, but this usage 

94 # is deprecated in Python 3 in favor of find_spec(). 

95 # For the purposes of this finder (i.e. being present 

96 # on sys.meta_path but having no other import 

97 # system functionality), the two methods are identical. 

98 find_module = find_spec 

99 

100 

101def py2_message_from_string(text): # nocoverpy3 

102 # Work around https://bugs.python.org/issue25545 where 

103 # email.message_from_string cannot handle Unicode on Python 2. 

104 io_buffer = io.StringIO(text) 

105 return email.message_from_file(io_buffer) 

106 

107 

108email_message_from_string = ( 

109 py2_message_from_string 

110 if sys.version_info < (3,) else 

111 email.message_from_string 

112 ) 

113 

114# https://bitbucket.org/pypy/pypy/issues/3021/ioopen-directory-leaks-a-file-descriptor 

115PYPY_OPEN_BUG = getattr(sys, 'pypy_version_info', (9, 9, 9))[:3] <= (7, 1, 1) 

116 

117 

118def ensure_is_path(ob): 

119 """Construct a Path from ob even if it's already one. 

120 Specialized for Python 3.4. 

121 """ 

122 if (3,) < sys.version_info < (3, 5): 

123 ob = str(ob) # pragma: nocover 

124 return pathlib.Path(ob) 

125 

126 

127class PyPy_repr: 

128 """ 

129 Override repr for EntryPoint objects on PyPy to avoid __iter__ access. 

130 Ref #97, #102. 

131 """ 

132 affected = hasattr(sys, 'pypy_version_info') 

133 

134 def __compat_repr__(self): # pragma: nocover 

135 def make_param(name): 

136 value = getattr(self, name) 

137 return '{name}={value!r}'.format(**locals()) 

138 params = ', '.join(map(make_param, self._fields)) 

139 return 'EntryPoint({params})'.format(**locals()) 

140 

141 if affected: # pragma: nocover 

142 __repr__ = __compat_repr__ 

143 del affected