~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/pip/_vendor/lockfile/__init__.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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