Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/lockfile/__init__.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 """ | |
4 lockfile.py - Platform-independent advisory file locks. | |
5 | |
6 Requires Python 2.5 unless you apply 2.4.diff | |
7 Locking is done on a per-thread basis instead of a per-process basis. | |
8 | |
9 Usage: | |
10 | |
11 >>> lock = LockFile('somefile') | |
12 >>> try: | |
13 ... lock.acquire() | |
14 ... except AlreadyLocked: | |
15 ... print 'somefile', 'is locked already.' | |
16 ... except LockFailed: | |
17 ... print 'somefile', 'can\\'t be locked.' | |
18 ... else: | |
19 ... print 'got lock' | |
20 got lock | |
21 >>> print lock.is_locked() | |
22 True | |
23 >>> lock.release() | |
24 | |
25 >>> lock = LockFile('somefile') | |
26 >>> print lock.is_locked() | |
27 False | |
28 >>> with lock: | |
29 ... print lock.is_locked() | |
30 True | |
31 >>> print lock.is_locked() | |
32 False | |
33 | |
34 >>> lock = LockFile('somefile') | |
35 >>> # It is okay to lock twice from the same thread... | |
36 >>> with lock: | |
37 ... lock.acquire() | |
38 ... | |
39 >>> # Though no counter is kept, so you can't unlock multiple times... | |
40 >>> print lock.is_locked() | |
41 False | |
42 | |
43 Exceptions: | |
44 | |
45 Error - base class for other exceptions | |
46 LockError - base class for all locking exceptions | |
47 AlreadyLocked - Another thread or process already holds the lock | |
48 LockFailed - Lock failed for some other reason | |
49 UnlockError - base class for all unlocking exceptions | |
50 AlreadyUnlocked - File was not locked. | |
51 NotMyLock - File was locked but not by the current thread/process | |
52 """ | |
53 | |
54 from __future__ import absolute_import | |
55 | |
56 import functools | |
57 import os | |
58 import socket | |
59 import threading | |
60 import warnings | |
61 | |
62 # Work with PEP8 and non-PEP8 versions of threading module. | |
63 if not hasattr(threading, "current_thread"): | |
64 threading.current_thread = threading.currentThread | |
65 if not hasattr(threading.Thread, "get_name"): | |
66 threading.Thread.get_name = threading.Thread.getName | |
67 | |
68 __all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked', | |
69 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock', | |
70 'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock', | |
71 'LockBase', 'locked'] | |
72 | |
73 | |
74 class Error(Exception): | |
75 """ | |
76 Base class for other exceptions. | |
77 | |
78 >>> try: | |
79 ... raise Error | |
80 ... except Exception: | |
81 ... pass | |
82 """ | |
83 pass | |
84 | |
85 | |
86 class LockError(Error): | |
87 """ | |
88 Base class for error arising from attempts to acquire the lock. | |
89 | |
90 >>> try: | |
91 ... raise LockError | |
92 ... except Error: | |
93 ... pass | |
94 """ | |
95 pass | |
96 | |
97 | |
98 class LockTimeout(LockError): | |
99 """Raised when lock creation fails within a user-defined period of time. | |
100 | |
101 >>> try: | |
102 ... raise LockTimeout | |
103 ... except LockError: | |
104 ... pass | |
105 """ | |
106 pass | |
107 | |
108 | |
109 class AlreadyLocked(LockError): | |
110 """Some other thread/process is locking the file. | |
111 | |
112 >>> try: | |
113 ... raise AlreadyLocked | |
114 ... except LockError: | |
115 ... pass | |
116 """ | |
117 pass | |
118 | |
119 | |
120 class LockFailed(LockError): | |
121 """Lock file creation failed for some other reason. | |
122 | |
123 >>> try: | |
124 ... raise LockFailed | |
125 ... except LockError: | |
126 ... pass | |
127 """ | |
128 pass | |
129 | |
130 | |
131 class UnlockError(Error): | |
132 """ | |
133 Base class for errors arising from attempts to release the lock. | |
134 | |
135 >>> try: | |
136 ... raise UnlockError | |
137 ... except Error: | |
138 ... pass | |
139 """ | |
140 pass | |
141 | |
142 | |
143 class NotLocked(UnlockError): | |
144 """Raised when an attempt is made to unlock an unlocked file. | |
145 | |
146 >>> try: | |
147 ... raise NotLocked | |
148 ... except UnlockError: | |
149 ... pass | |
150 """ | |
151 pass | |
152 | |
153 | |
154 class NotMyLock(UnlockError): | |
155 """Raised when an attempt is made to unlock a file someone else locked. | |
156 | |
157 >>> try: | |
158 ... raise NotMyLock | |
159 ... except UnlockError: | |
160 ... pass | |
161 """ | |
162 pass | |
163 | |
164 | |
165 class _SharedBase(object): | |
166 def __init__(self, path): | |
167 self.path = path | |
168 | |
169 def acquire(self, timeout=None): | |
170 """ | |
171 Acquire the lock. | |
172 | |
173 * If timeout is omitted (or None), wait forever trying to lock the | |
174 file. | |
175 | |
176 * If timeout > 0, try to acquire the lock for that many seconds. If | |
177 the lock period expires and the file is still locked, raise | |
178 LockTimeout. | |
179 | |
180 * If timeout <= 0, raise AlreadyLocked immediately if the file is | |
181 already locked. | |
182 """ | |
183 raise NotImplemented("implement in subclass") | |
184 | |
185 def release(self): | |
186 """ | |
187 Release the lock. | |
188 | |
189 If the file is not locked, raise NotLocked. | |
190 """ | |
191 raise NotImplemented("implement in subclass") | |
192 | |
193 def __enter__(self): | |
194 """ | |
195 Context manager support. | |
196 """ | |
197 self.acquire() | |
198 return self | |
199 | |
200 def __exit__(self, *_exc): | |
201 """ | |
202 Context manager support. | |
203 """ | |
204 self.release() | |
205 | |
206 def __repr__(self): | |
207 return "<%s: %r>" % (self.__class__.__name__, self.path) | |
208 | |
209 | |
210 class LockBase(_SharedBase): | |
211 """Base class for platform-specific lock classes.""" | |
212 def __init__(self, path, threaded=True, timeout=None): | |
213 """ | |
214 >>> lock = LockBase('somefile') | |
215 >>> lock = LockBase('somefile', threaded=False) | |
216 """ | |
217 super(LockBase, self).__init__(path) | |
218 self.lock_file = os.path.abspath(path) + ".lock" | |
219 self.hostname = socket.gethostname() | |
220 self.pid = os.getpid() | |
221 if threaded: | |
222 t = threading.current_thread() | |
223 # Thread objects in Python 2.4 and earlier do not have ident | |
224 # attrs. Worm around that. | |
225 ident = getattr(t, "ident", hash(t)) | |
226 self.tname = "-%x" % (ident & 0xffffffff) | |
227 else: | |
228 self.tname = "" | |
229 dirname = os.path.dirname(self.lock_file) | |
230 | |
231 # unique name is mostly about the current process, but must | |
232 # also contain the path -- otherwise, two adjacent locked | |
233 # files conflict (one file gets locked, creating lock-file and | |
234 # unique file, the other one gets locked, creating lock-file | |
235 # and overwriting the already existing lock-file, then one | |
236 # gets unlocked, deleting both lock-file and unique file, | |
237 # finally the last lock errors out upon releasing. | |
238 self.unique_name = os.path.join(dirname, | |
239 "%s%s.%s%s" % (self.hostname, | |
240 self.tname, | |
241 self.pid, | |
242 hash(self.path))) | |
243 self.timeout = timeout | |
244 | |
245 def is_locked(self): | |
246 """ | |
247 Tell whether or not the file is locked. | |
248 """ | |
249 raise NotImplemented("implement in subclass") | |
250 | |
251 def i_am_locking(self): | |
252 """ | |
253 Return True if this object is locking the file. | |
254 """ | |
255 raise NotImplemented("implement in subclass") | |
256 | |
257 def break_lock(self): | |
258 """ | |
259 Remove a lock. Useful if a locking thread failed to unlock. | |
260 """ | |
261 raise NotImplemented("implement in subclass") | |
262 | |
263 def __repr__(self): | |
264 return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, | |
265 self.path) | |
266 | |
267 | |
268 def _fl_helper(cls, mod, *args, **kwds): | |
269 warnings.warn("Import from %s module instead of lockfile package" % mod, | |
270 DeprecationWarning, stacklevel=2) | |
271 # This is a bit funky, but it's only for awhile. The way the unit tests | |
272 # are constructed this function winds up as an unbound method, so it | |
273 # actually takes three args, not two. We want to toss out self. | |
274 if not isinstance(args[0], str): | |
275 # We are testing, avoid the first arg | |
276 args = args[1:] | |
277 if len(args) == 1 and not kwds: | |
278 kwds["threaded"] = True | |
279 return cls(*args, **kwds) | |
280 | |
281 | |
282 def LinkFileLock(*args, **kwds): | |
283 """Factory function provided for backwards compatibility. | |
284 | |
285 Do not use in new code. Instead, import LinkLockFile from the | |
286 lockfile.linklockfile module. | |
287 """ | |
288 from . import linklockfile | |
289 return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", | |
290 *args, **kwds) | |
291 | |
292 | |
293 def MkdirFileLock(*args, **kwds): | |
294 """Factory function provided for backwards compatibility. | |
295 | |
296 Do not use in new code. Instead, import MkdirLockFile from the | |
297 lockfile.mkdirlockfile module. | |
298 """ | |
299 from . import mkdirlockfile | |
300 return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", | |
301 *args, **kwds) | |
302 | |
303 | |
304 def SQLiteFileLock(*args, **kwds): | |
305 """Factory function provided for backwards compatibility. | |
306 | |
307 Do not use in new code. Instead, import SQLiteLockFile from the | |
308 lockfile.mkdirlockfile module. | |
309 """ | |
310 from . import sqlitelockfile | |
311 return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", | |
312 *args, **kwds) | |
313 | |
314 | |
315 def locked(path, timeout=None): | |
316 """Decorator which enables locks for decorated function. | |
317 | |
318 Arguments: | |
319 - path: path for lockfile. | |
320 - timeout (optional): Timeout for acquiring lock. | |
321 | |
322 Usage: | |
323 @locked('/var/run/myname', timeout=0) | |
324 def myname(...): | |
325 ... | |
326 """ | |
327 def decor(func): | |
328 @functools.wraps(func) | |
329 def wrapper(*args, **kwargs): | |
330 lock = FileLock(path, timeout=timeout) | |
331 lock.acquire() | |
332 try: | |
333 return func(*args, **kwargs) | |
334 finally: | |
335 lock.release() | |
336 return wrapper | |
337 return decor | |
338 | |
339 | |
340 if hasattr(os, "link"): | |
341 from . import linklockfile as _llf | |
342 LockFile = _llf.LinkLockFile | |
343 else: | |
344 from . import mkdirlockfile as _mlf | |
345 LockFile = _mlf.MkdirLockFile | |
346 | |
347 FileLock = LockFile |