Statistics
| Branch: | Tag: | Revision:

root / ci / filelocker.py @ 329705c8

History | View | Annotate | Download (3.1 kB)

1
# filelocker.py - Cross-platform (posix/nt) API for flock-style file locking.
2
#                 Requires python 1.5.2 or better.
3
"""Cross-platform (posix/nt) API for flock-style file locking.
4

5

6
Synopsis:
7

8
    import filelocker
9
    with filelocker.lock("lockfile", filelocker.LOCK_EX):
10
        print "Got it"
11

12

13
Methods:
14

15
   lock ( file, flags, tries=10 )
16

17

18
Constants:
19

20
   LOCK_EX
21
   LOCK_SH
22
   LOCK_NB
23

24

25
Exceptions:
26

27
    LockException
28

29

30
Notes:
31

32
For the 'nt' platform, this module requires the Python Extensions for Windows.
33
Be aware that this may not work as expected on Windows 95/98/ME.
34

35

36
History:
37

38
I learned the win32 technique for locking files from sample code
39
provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
40
that accompanies the win32 modules.
41

42

43
Author: Jonathan Feinberg <jdf@pobox.com>,
44
        Lowell Alleman <lalleman@mfps.com>
45
Version: $Id: filelocker.py 5474 2008-05-16 20:53:50Z lowell $
46

47

48
Modified to work as a contextmanager
49

50
"""
51

    
52
import os
53
from contextlib import contextmanager
54

    
55

    
56
class LockException(Exception):
57
    # Error codes:
58
    LOCK_FAILED = 1
59

    
60

    
61
# Import modules for each supported platform
62
if os.name == 'nt':
63
    import win32con
64
    import win32file
65
    import pywintypes
66
    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
67
    LOCK_SH = 0  # the default
68
    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
69
    # is there any reason not to reuse the following structure?
70
    __overlapped = pywintypes.OVERLAPPED()
71
elif os.name == 'posix':
72
    import fcntl
73
    LOCK_EX = fcntl.LOCK_EX
74
    LOCK_SH = fcntl.LOCK_SH
75
    LOCK_NB = fcntl.LOCK_NB
76
else:
77
    raise RuntimeError("FileLocker only defined for nt and posix platforms")
78

    
79

    
80
# --------------------------------------
81
# Implementation for NT
82
if os.name == 'nt':
83
    @contextmanager
84
    def lock(filename, flags):
85
        file = open(filename, "w+")
86
        hfile = win32file._get_osfhandle(file.fileno())
87

    
88
        try:
89
            win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped)
90
            try:
91
                yield
92
            finally:
93
                file.close()
94
        except pywintypes.error, exc_value:
95
            # error: (33, 'LockFileEx',
96
            #         'The process cannot access the file because another
97
            #          process has locked a portion of the file.')
98
            file.close()
99
            if exc_value[0] == 33:
100
                raise LockException(LockException.LOCK_FAILED, exc_value[2])
101
            else:
102
                # Q:  Are there exceptions/codes we should be dealing with?
103
                raise
104

    
105

    
106
# --------------------------------------
107
# Implementation for Posix
108
elif os.name == 'posix':
109
    @contextmanager
110
    def lock(filename, flags):
111
        file = open(filename, "w+")
112

    
113
        try:
114
            fcntl.flock(file.fileno(), flags)
115
            try:
116
                yield
117
            finally:
118
                file.close()
119
        except IOError, exc_value:
120
            #  IOError: [Errno 11] Resource temporarily unavailable
121
            file.close()
122
            if exc_value[0] == 11:
123
                raise LockException(LockException.LOCK_FAILED, exc_value[1])
124
            else:
125
                raise