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 |
