1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import os
29 import time
30 import errno
31
34
36 """ A file locking mechanism that has context-manager support so
37 you can use it in a with statement. This should be relatively cross
38 compatible as it doesn't rely on msvcrt or fcntl for the locking.
39 """
40
41 - def __init__(self, file_name, timeout=10, delay=.05):
42 """ Prepare the file locker. Specify the file to lock and optionally
43 the maximum timeout and the delay between each attempt to lock.
44 """
45 self.is_locked = False
46 self.lockfile = os.path.join(os.getcwd(), "%s.lock" % file_name)
47 self.file_name = file_name
48 self.timeout = timeout
49 self.delay = delay
50
51
53 """ Acquire the lock, if possible. If the lock is in use, it check again
54 every `wait` seconds. It does this until it either gets the lock or
55 exceeds `timeout` number of seconds, in which case it throws
56 an exception.
57 """
58 start_time = time.time()
59 while True:
60 try:
61 self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR)
62 break;
63 except OSError as e:
64 if e.errno != errno.EEXIST:
65 raise
66 if (time.time() - start_time) >= self.timeout:
67 raise FileLockException("Timeout occured.")
68 time.sleep(self.delay)
69 self.is_locked = True
70
71
73 """ Get rid of the lock by deleting the lockfile.
74 When working in a `with` statement, this gets automatically
75 called at the end.
76 """
77 if self.is_locked:
78 os.close(self.fd)
79 os.unlink(self.lockfile)
80 self.is_locked = False
81
82
84 """ Activated when used in the with statement.
85 Should automatically acquire a lock to be used in the with block.
86 """
87 if not self.is_locked:
88 self.acquire()
89 return self
90
91
92 - def __exit__(self, type, value, traceback):
93 """ Activated at the end of the with statement.
94 It automatically releases the lock if it isn't locked.
95 """
96 if self.is_locked:
97 self.release()
98
99
101 """ Make sure that the FileLock instance doesn't leave a lockfile
102 lying around.
103 """
104 self.release()
105