Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/joblib/backports.py: 27%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

98 statements  

1""" 

2Backports of fixes for joblib dependencies 

3""" 

4import os 

5import re 

6import time 

7 

8from os.path import basename 

9from multiprocessing import util 

10 

11 

12class Version: 

13 """Backport from deprecated distutils 

14 

15 We maintain this backport to avoid introducing a new dependency on 

16 `packaging`. 

17 

18 We might rexplore this choice in the future if all major Python projects 

19 introduce a dependency on packaging anyway. 

20 """ 

21 

22 def __init__(self, vstring=None): 

23 if vstring: 

24 self.parse(vstring) 

25 

26 def __repr__(self): 

27 return "%s ('%s')" % (self.__class__.__name__, str(self)) 

28 

29 def __eq__(self, other): 

30 c = self._cmp(other) 

31 if c is NotImplemented: 

32 return c 

33 return c == 0 

34 

35 def __lt__(self, other): 

36 c = self._cmp(other) 

37 if c is NotImplemented: 

38 return c 

39 return c < 0 

40 

41 def __le__(self, other): 

42 c = self._cmp(other) 

43 if c is NotImplemented: 

44 return c 

45 return c <= 0 

46 

47 def __gt__(self, other): 

48 c = self._cmp(other) 

49 if c is NotImplemented: 

50 return c 

51 return c > 0 

52 

53 def __ge__(self, other): 

54 c = self._cmp(other) 

55 if c is NotImplemented: 

56 return c 

57 return c >= 0 

58 

59 

60class LooseVersion(Version): 

61 """Backport from deprecated distutils 

62 

63 We maintain this backport to avoid introducing a new dependency on 

64 `packaging`. 

65 

66 We might rexplore this choice in the future if all major Python projects 

67 introduce a dependency on packaging anyway. 

68 """ 

69 

70 component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) 

71 

72 def __init__(self, vstring=None): 

73 if vstring: 

74 self.parse(vstring) 

75 

76 def parse(self, vstring): 

77 # I've given up on thinking I can reconstruct the version string 

78 # from the parsed tuple -- so I just store the string here for 

79 # use by __str__ 

80 self.vstring = vstring 

81 components = [x for x in self.component_re.split(vstring) 

82 if x and x != '.'] 

83 for i, obj in enumerate(components): 

84 try: 

85 components[i] = int(obj) 

86 except ValueError: 

87 pass 

88 

89 self.version = components 

90 

91 def __str__(self): 

92 return self.vstring 

93 

94 def __repr__(self): 

95 return "LooseVersion ('%s')" % str(self) 

96 

97 def _cmp(self, other): 

98 if isinstance(other, str): 

99 other = LooseVersion(other) 

100 elif not isinstance(other, LooseVersion): 

101 return NotImplemented 

102 

103 if self.version == other.version: 

104 return 0 

105 if self.version < other.version: 

106 return -1 

107 if self.version > other.version: 

108 return 1 

109 

110 

111try: 

112 import numpy as np 

113 

114 def make_memmap(filename, dtype='uint8', mode='r+', offset=0, 

115 shape=None, order='C', unlink_on_gc_collect=False): 

116 """Custom memmap constructor compatible with numpy.memmap. 

117 

118 This function: 

119 - is a backport the numpy memmap offset fix (See 

120 https://github.com/numpy/numpy/pull/8443 for more details. 

121 The numpy fix is available starting numpy 1.13) 

122 - adds ``unlink_on_gc_collect``, which specifies explicitly whether 

123 the process re-constructing the memmap owns a reference to the 

124 underlying file. If set to True, it adds a finalizer to the 

125 newly-created memmap that sends a maybe_unlink request for the 

126 memmaped file to resource_tracker. 

127 """ 

128 util.debug( 

129 "[MEMMAP READ] creating a memmap (shape {}, filename {}, " 

130 "pid {})".format(shape, basename(filename), os.getpid()) 

131 ) 

132 

133 mm = np.memmap(filename, dtype=dtype, mode=mode, offset=offset, 

134 shape=shape, order=order) 

135 if LooseVersion(np.__version__) < '1.13': 

136 mm.offset = offset 

137 if unlink_on_gc_collect: 

138 from ._memmapping_reducer import add_maybe_unlink_finalizer 

139 add_maybe_unlink_finalizer(mm) 

140 return mm 

141except ImportError: 

142 def make_memmap(filename, dtype='uint8', mode='r+', offset=0, 

143 shape=None, order='C', unlink_on_gc_collect=False): 

144 raise NotImplementedError( 

145 "'joblib.backports.make_memmap' should not be used " 

146 'if numpy is not installed.') 

147 

148 

149if os.name == 'nt': 

150 # https://github.com/joblib/joblib/issues/540 

151 access_denied_errors = (5, 13) 

152 from os import replace 

153 

154 def concurrency_safe_rename(src, dst): 

155 """Renames ``src`` into ``dst`` overwriting ``dst`` if it exists. 

156 

157 On Windows os.replace can yield permission errors if executed by two 

158 different processes. 

159 """ 

160 max_sleep_time = 1 

161 total_sleep_time = 0 

162 sleep_time = 0.001 

163 while total_sleep_time < max_sleep_time: 

164 try: 

165 replace(src, dst) 

166 break 

167 except Exception as exc: 

168 if getattr(exc, 'winerror', None) in access_denied_errors: 

169 time.sleep(sleep_time) 

170 total_sleep_time += sleep_time 

171 sleep_time *= 2 

172 else: 

173 raise 

174 else: 

175 raise 

176else: 

177 from os import replace as concurrency_safe_rename # noqa