root / ci / filelocker.py @ 329705c8
History | View | Annotate | Download (3.1 kB)
1 | 62fcf0e5 | Ilias Tsitsimpis | # filelocker.py - Cross-platform (posix/nt) API for flock-style file locking.
|
---|---|---|---|
2 | 62fcf0e5 | Ilias Tsitsimpis | # Requires python 1.5.2 or better.
|
3 | 62fcf0e5 | Ilias Tsitsimpis | """Cross-platform (posix/nt) API for flock-style file locking.
|
4 | 62fcf0e5 | Ilias Tsitsimpis |
|
5 | 62fcf0e5 | Ilias Tsitsimpis |
|
6 | 62fcf0e5 | Ilias Tsitsimpis | Synopsis:
|
7 | 62fcf0e5 | Ilias Tsitsimpis |
|
8 | 62fcf0e5 | Ilias Tsitsimpis | import filelocker
|
9 | 62fcf0e5 | Ilias Tsitsimpis | with filelocker.lock("lockfile", filelocker.LOCK_EX):
|
10 | 62fcf0e5 | Ilias Tsitsimpis | print "Got it"
|
11 | 62fcf0e5 | Ilias Tsitsimpis |
|
12 | 62fcf0e5 | Ilias Tsitsimpis |
|
13 | 62fcf0e5 | Ilias Tsitsimpis | Methods:
|
14 | 62fcf0e5 | Ilias Tsitsimpis |
|
15 | 62fcf0e5 | Ilias Tsitsimpis | lock ( file, flags, tries=10 )
|
16 | 62fcf0e5 | Ilias Tsitsimpis |
|
17 | 62fcf0e5 | Ilias Tsitsimpis |
|
18 | 62fcf0e5 | Ilias Tsitsimpis | Constants:
|
19 | 62fcf0e5 | Ilias Tsitsimpis |
|
20 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_EX
|
21 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_SH
|
22 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_NB
|
23 | 62fcf0e5 | Ilias Tsitsimpis |
|
24 | 62fcf0e5 | Ilias Tsitsimpis |
|
25 | 62fcf0e5 | Ilias Tsitsimpis | Exceptions:
|
26 | 62fcf0e5 | Ilias Tsitsimpis |
|
27 | 62fcf0e5 | Ilias Tsitsimpis | LockException
|
28 | 62fcf0e5 | Ilias Tsitsimpis |
|
29 | 62fcf0e5 | Ilias Tsitsimpis |
|
30 | 62fcf0e5 | Ilias Tsitsimpis | Notes:
|
31 | 62fcf0e5 | Ilias Tsitsimpis |
|
32 | 62fcf0e5 | Ilias Tsitsimpis | For the 'nt' platform, this module requires the Python Extensions for Windows.
|
33 | 62fcf0e5 | Ilias Tsitsimpis | Be aware that this may not work as expected on Windows 95/98/ME.
|
34 | 62fcf0e5 | Ilias Tsitsimpis |
|
35 | 62fcf0e5 | Ilias Tsitsimpis |
|
36 | 62fcf0e5 | Ilias Tsitsimpis | History:
|
37 | 62fcf0e5 | Ilias Tsitsimpis |
|
38 | 62fcf0e5 | Ilias Tsitsimpis | I learned the win32 technique for locking files from sample code
|
39 | 62fcf0e5 | Ilias Tsitsimpis | provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
|
40 | 62fcf0e5 | Ilias Tsitsimpis | that accompanies the win32 modules.
|
41 | 62fcf0e5 | Ilias Tsitsimpis |
|
42 | 62fcf0e5 | Ilias Tsitsimpis |
|
43 | 62fcf0e5 | Ilias Tsitsimpis | Author: Jonathan Feinberg <jdf@pobox.com>,
|
44 | 62fcf0e5 | Ilias Tsitsimpis | Lowell Alleman <lalleman@mfps.com>
|
45 | 62fcf0e5 | Ilias Tsitsimpis | Version: $Id: filelocker.py 5474 2008-05-16 20:53:50Z lowell $
|
46 | 62fcf0e5 | Ilias Tsitsimpis |
|
47 | 62fcf0e5 | Ilias Tsitsimpis |
|
48 | 62fcf0e5 | Ilias Tsitsimpis | Modified to work as a contextmanager
|
49 | 62fcf0e5 | Ilias Tsitsimpis |
|
50 | 62fcf0e5 | Ilias Tsitsimpis | """
|
51 | 62fcf0e5 | Ilias Tsitsimpis | |
52 | 62fcf0e5 | Ilias Tsitsimpis | import os |
53 | 62fcf0e5 | Ilias Tsitsimpis | from contextlib import contextmanager |
54 | 62fcf0e5 | Ilias Tsitsimpis | |
55 | 62fcf0e5 | Ilias Tsitsimpis | |
56 | 62fcf0e5 | Ilias Tsitsimpis | class LockException(Exception): |
57 | 62fcf0e5 | Ilias Tsitsimpis | # Error codes:
|
58 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_FAILED = 1
|
59 | 62fcf0e5 | Ilias Tsitsimpis | |
60 | 62fcf0e5 | Ilias Tsitsimpis | |
61 | 62fcf0e5 | Ilias Tsitsimpis | # Import modules for each supported platform
|
62 | 62fcf0e5 | Ilias Tsitsimpis | if os.name == 'nt': |
63 | 62fcf0e5 | Ilias Tsitsimpis | import win32con |
64 | 62fcf0e5 | Ilias Tsitsimpis | import win32file |
65 | 62fcf0e5 | Ilias Tsitsimpis | import pywintypes |
66 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK |
67 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_SH = 0 # the default |
68 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY |
69 | 62fcf0e5 | Ilias Tsitsimpis | # is there any reason not to reuse the following structure?
|
70 | 62fcf0e5 | Ilias Tsitsimpis | __overlapped = pywintypes.OVERLAPPED() |
71 | 62fcf0e5 | Ilias Tsitsimpis | elif os.name == 'posix': |
72 | 62fcf0e5 | Ilias Tsitsimpis | import fcntl |
73 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_EX = fcntl.LOCK_EX |
74 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_SH = fcntl.LOCK_SH |
75 | 62fcf0e5 | Ilias Tsitsimpis | LOCK_NB = fcntl.LOCK_NB |
76 | 62fcf0e5 | Ilias Tsitsimpis | else:
|
77 | 62fcf0e5 | Ilias Tsitsimpis | raise RuntimeError("FileLocker only defined for nt and posix platforms") |
78 | 62fcf0e5 | Ilias Tsitsimpis | |
79 | 62fcf0e5 | Ilias Tsitsimpis | |
80 | 62fcf0e5 | Ilias Tsitsimpis | # --------------------------------------
|
81 | 62fcf0e5 | Ilias Tsitsimpis | # Implementation for NT
|
82 | 62fcf0e5 | Ilias Tsitsimpis | if os.name == 'nt': |
83 | 62fcf0e5 | Ilias Tsitsimpis | @contextmanager
|
84 | 62fcf0e5 | Ilias Tsitsimpis | def lock(filename, flags): |
85 | 62fcf0e5 | Ilias Tsitsimpis | file = open(filename, "w+") |
86 | 62fcf0e5 | Ilias Tsitsimpis | hfile = win32file._get_osfhandle(file.fileno())
|
87 | 62fcf0e5 | Ilias Tsitsimpis | |
88 | 62fcf0e5 | Ilias Tsitsimpis | try:
|
89 | 62fcf0e5 | Ilias Tsitsimpis | win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped) |
90 | 62fcf0e5 | Ilias Tsitsimpis | try:
|
91 | 62fcf0e5 | Ilias Tsitsimpis | yield
|
92 | 62fcf0e5 | Ilias Tsitsimpis | finally:
|
93 | 62fcf0e5 | Ilias Tsitsimpis | file.close()
|
94 | 62fcf0e5 | Ilias Tsitsimpis | except pywintypes.error, exc_value:
|
95 | 62fcf0e5 | Ilias Tsitsimpis | # error: (33, 'LockFileEx',
|
96 | 62fcf0e5 | Ilias Tsitsimpis | # 'The process cannot access the file because another
|
97 | 62fcf0e5 | Ilias Tsitsimpis | # process has locked a portion of the file.')
|
98 | 62fcf0e5 | Ilias Tsitsimpis | file.close()
|
99 | 62fcf0e5 | Ilias Tsitsimpis | if exc_value[0] == 33: |
100 | 62fcf0e5 | Ilias Tsitsimpis | raise LockException(LockException.LOCK_FAILED, exc_value[2]) |
101 | 62fcf0e5 | Ilias Tsitsimpis | else:
|
102 | 62fcf0e5 | Ilias Tsitsimpis | # Q: Are there exceptions/codes we should be dealing with?
|
103 | 62fcf0e5 | Ilias Tsitsimpis | raise
|
104 | 62fcf0e5 | Ilias Tsitsimpis | |
105 | 62fcf0e5 | Ilias Tsitsimpis | |
106 | 62fcf0e5 | Ilias Tsitsimpis | # --------------------------------------
|
107 | 62fcf0e5 | Ilias Tsitsimpis | # Implementation for Posix
|
108 | 62fcf0e5 | Ilias Tsitsimpis | elif os.name == 'posix': |
109 | 62fcf0e5 | Ilias Tsitsimpis | @contextmanager
|
110 | 62fcf0e5 | Ilias Tsitsimpis | def lock(filename, flags): |
111 | 62fcf0e5 | Ilias Tsitsimpis | file = open(filename, "w+") |
112 | 62fcf0e5 | Ilias Tsitsimpis | |
113 | 62fcf0e5 | Ilias Tsitsimpis | try:
|
114 | 62fcf0e5 | Ilias Tsitsimpis | fcntl.flock(file.fileno(), flags)
|
115 | 62fcf0e5 | Ilias Tsitsimpis | try:
|
116 | 62fcf0e5 | Ilias Tsitsimpis | yield
|
117 | 62fcf0e5 | Ilias Tsitsimpis | finally:
|
118 | 62fcf0e5 | Ilias Tsitsimpis | file.close()
|
119 | 62fcf0e5 | Ilias Tsitsimpis | except IOError, exc_value: |
120 | 62fcf0e5 | Ilias Tsitsimpis | # IOError: [Errno 11] Resource temporarily unavailable
|
121 | 62fcf0e5 | Ilias Tsitsimpis | file.close()
|
122 | 62fcf0e5 | Ilias Tsitsimpis | if exc_value[0] == 11: |
123 | 62fcf0e5 | Ilias Tsitsimpis | raise LockException(LockException.LOCK_FAILED, exc_value[1]) |
124 | 62fcf0e5 | Ilias Tsitsimpis | else:
|
125 | 62fcf0e5 | Ilias Tsitsimpis | raise |