Package grizzled :: Package io :: Module filelock
[hide private]
[frames] | no frames]

Source Code for Module grizzled.io.filelock

  1  # $Id: cee003fb7c38cb61af6bf2d036245576cfc8cf44 $ 
  2   
  3  """ 
  4  File Locking 
  5  ============ 
  6   
  7  This module provides portable advisory file locking primitives that operate on 
  8  file descriptors. POSIX-like systems and Windows systems use different 
  9  primitives to perform file locking, and these different primitives are modeled 
 10  by incompatible (and different) modules in the Python standard library. This 
 11  module provides an abstract ``FileLock`` class, and underlying 
 12  implementations, to hide the operating system dependencies behind a simple 
 13  portable interface. 
 14   
 15  To create a file lock, simply instantiate the ``FileLock`` class with an open 
 16  file descriptor. It handles the rest: 
 17   
 18  .. python:: 
 19   
 20      from grizzled.io.filelock import FileLock 
 21   
 22      fd = open('/tmp/lockfile', 'r+') 
 23      lock = FileLock(fd) 
 24      lock.acquire() 
 25   
 26      ... 
 27   
 28      lock.release() 
 29   
 30  You can also use the ``locked_file()`` function to simplify your code: 
 31   
 32  .. python:: 
 33   
 34      from grizzled.io.filelock import locked_file 
 35   
 36      fd = open('/tmp/lockfile', 'r+') 
 37      with locked_file(fd): 
 38          ... 
 39  """ 
 40   
 41  __docformat__ = "restructuredtext en" 
 42   
 43  # --------------------------------------------------------------------------- 
 44  # Imports 
 45  # --------------------------------------------------------------------------- 
 46   
 47  import os 
 48  from contextlib import contextmanager 
 49   
 50  # --------------------------------------------------------------------------- 
 51  # Exports 
 52  # --------------------------------------------------------------------------- 
 53   
 54  __all__ = ['FileLock', 'locked_file'] 
 55   
 56  LOCK_CLASSES = {'posix' : '_PosixFileLock', 
 57                  'nt'    : '_WindowsFileLock'} 
58 59 # --------------------------------------------------------------------------- 60 # Classes 61 # --------------------------------------------------------------------------- 62 63 -class FileLock(object):
64 """ 65 A ``FileLock`` object models a file lock. It wraps a file descriptor 66 and contains methods to acquire and release a lock on the file. 67 68 File lock implementations that implement this interface are guaranteed 69 to be advisory, but not mandatory, file locks. (They may, in fact, also 70 be mandatory file locks, but they are not guaranteed to be.) 71 72 Currently, there are underlying implementations for both POSIX systems 73 and Windows. 74 """ 75
76 - def __init__(self, fd):
77 """ 78 Allocate a new file lock that operates on the specified file 79 descriptor. 80 81 :Parameters: 82 fd : int 83 Open file descriptor. The file must be opened for writing or 84 updating, not reading. 85 """ 86 try: 87 cls = eval(LOCK_CLASSES[os.name]) 88 self.lock = cls(fd) 89 90 except KeyError: 91 raise NotImplementedError, \ 92 '''Don't know how to lock files on "%s" systems.''' % os.name
93
94 - def acquire(self, no_wait=False):
95 """ 96 Lock the associated file. If someone already has the file locked, 97 this method will suspend the calling process, unless ``no_wait`` is 98 ``True``. 99 100 :Parameters: 101 no_wait : bool 102 If ``False``, then ``acquire()`` will suspend the calling 103 process if someone has the file locked. If ``True``, then 104 ``acquire()`` will raise an ``IOError`` if the file is 105 locked by someone else. 106 107 :raise IOError: If the file cannot be locked for any reason. 108 """ 109 self.lock.acquire(no_wait)
110
111 - def release(self):
112 """ 113 Unlock (i.e., release the lock on) the associated file. 114 """ 115 self.lock.release()
116
117 -class _PosixFileLock(object):
118 """File lock implementation for POSIX-compliant systems.""" 119
120 - def __init__(self, fd):
121 self.fd = fd
122
123 - def acquire(self, no_wait=False):
124 import fcntl 125 flags = fcntl.LOCK_EX 126 if no_wait: 127 flags |= fcntl.LOCK_NB 128 129 fcntl.lockf(self.fd, flags)
130
131 - def release(self):
132 import fcntl 133 fcntl.lockf(self.fd, fcntl.LOCK_UN)
134
135 -class _WindowsFileLock(object):
136 """File lock implementation for Windows systems.""" 137
138 - def __init__(self, fd):
139 self.fd = fd
140
141 - def lock(self, no_wait=False):
142 import msvcrt 143 if no_wait: 144 op = msvcrt.LK_NBLCK 145 else: 146 op = msvcrt.LK_LOCK 147 148 self.fd.seek(0) 149 msvcrt.locking(self.fd, op, 1)
150
151 - def unlock(self):
152 import msvcrt 153 self.fd.seek(0) 154 msvcrt.locking(self.fd, LK_UNLCK, 1)
155
156 # --------------------------------------------------------------------------- 157 # Functions 158 # --------------------------------------------------------------------------- 159 160 @contextmanager 161 -def locked_file(fd, no_wait=False):
162 """ 163 This function is intended to be used as a ``with`` statement context 164 manager. It wraps a ``FileLock`` object so that the locking and unlocking 165 of the file descriptor are automatic. With the ``locked_file()`` function, 166 you can replace this code: 167 168 .. python:: 169 170 lock = FileLock(fd) 171 lock.acquire() 172 try: 173 do_something() 174 finally: 175 lock.release() 176 177 with this code: 178 179 .. python:: 180 181 with locked_file(fd): 182 do_something() 183 184 :Parameters: 185 fd : int 186 Open file descriptor. The file must be opened for writing 187 or updating, not reading. 188 no_wait : bool 189 If ``False``, then ``locked_file()`` will suspend the calling 190 process if someone has the file locked. If ``True``, then 191 ``locked_file()`` will raise an ``IOError`` if the file is 192 locked by someone else. 193 """ 194 locked = False 195 try: 196 lock = FileLock(fd) 197 lock.acquire(no_wait) 198 locked = True 199 yield lock 200 finally: 201 if locked: 202 lock.release()
203