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
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
1"""
2Backports of fixes for joblib dependencies
3"""
4import os
5import re
6import time
8from os.path import basename
9from multiprocessing import util
12class Version:
13 """Backport from deprecated distutils
15 We maintain this backport to avoid introducing a new dependency on
16 `packaging`.
18 We might rexplore this choice in the future if all major Python projects
19 introduce a dependency on packaging anyway.
20 """
22 def __init__(self, vstring=None):
23 if vstring:
24 self.parse(vstring)
26 def __repr__(self):
27 return "%s ('%s')" % (self.__class__.__name__, str(self))
29 def __eq__(self, other):
30 c = self._cmp(other)
31 if c is NotImplemented:
32 return c
33 return c == 0
35 def __lt__(self, other):
36 c = self._cmp(other)
37 if c is NotImplemented:
38 return c
39 return c < 0
41 def __le__(self, other):
42 c = self._cmp(other)
43 if c is NotImplemented:
44 return c
45 return c <= 0
47 def __gt__(self, other):
48 c = self._cmp(other)
49 if c is NotImplemented:
50 return c
51 return c > 0
53 def __ge__(self, other):
54 c = self._cmp(other)
55 if c is NotImplemented:
56 return c
57 return c >= 0
60class LooseVersion(Version):
61 """Backport from deprecated distutils
63 We maintain this backport to avoid introducing a new dependency on
64 `packaging`.
66 We might rexplore this choice in the future if all major Python projects
67 introduce a dependency on packaging anyway.
68 """
70 component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
72 def __init__(self, vstring=None):
73 if vstring:
74 self.parse(vstring)
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
89 self.version = components
91 def __str__(self):
92 return self.vstring
94 def __repr__(self):
95 return "LooseVersion ('%s')" % str(self)
97 def _cmp(self, other):
98 if isinstance(other, str):
99 other = LooseVersion(other)
100 elif not isinstance(other, LooseVersion):
101 return NotImplemented
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
111try:
112 import numpy as np
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.
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 )
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.')
149if os.name == 'nt':
150 # https://github.com/joblib/joblib/issues/540
151 access_denied_errors = (5, 13)
152 from os import replace
154 def concurrency_safe_rename(src, dst):
155 """Renames ``src`` into ``dst`` overwriting ``dst`` if it exists.
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