Skip to content

Commit 2ef7a8d

Browse files
authored
Merge pull request #275 from labthings/release-locks-on-error
Release locks on error
2 parents cdeb2d0 + 7151372 commit 2ef7a8d

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

src/labthings/sync/lock.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ def _owner(self):
5353
@contextmanager
5454
def __call__(self, timeout=sentinel, blocking: bool = True):
5555
result = self.acquire(timeout=timeout, blocking=blocking)
56-
yield result
57-
if result:
58-
self.release()
56+
try:
57+
yield result
58+
finally:
59+
if result:
60+
self.release()
5961

6062
def locked(self):
6163
""" """
@@ -122,9 +124,11 @@ def _owner(self):
122124
@contextmanager
123125
def __call__(self, timeout=sentinel, blocking: bool = True):
124126
result = self.acquire(timeout=timeout, blocking=blocking)
125-
yield result
126-
if result:
127-
self.release()
127+
try:
128+
yield result
129+
finally:
130+
if result:
131+
self.release()
128132

129133
def acquire(self, blocking: bool = True, timeout=sentinel):
130134
"""

tests/test_sync_lock.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,33 @@ def g():
108108
with pytest.raises(lock.LockError):
109109
with this_lock(timeout=0.01):
110110
pass
111+
112+
class DummyException(Exception):
113+
pass
114+
115+
def test_rlock_released_after_error_args(this_lock):
116+
"""If an exception occurs in a with block, the lock should release.
117+
118+
NB there are two sets of code that do this - one if arguments are
119+
given (i.e. the __call__ method of the lock class) and one without
120+
arguments (i.e. the __enter__ and __exit__ methods).
121+
122+
See the following function for the no-arguments version.
123+
"""
124+
try:
125+
with this_lock():
126+
assert this_lock.locked()
127+
raise DummyException()
128+
except DummyException:
129+
pass
130+
assert not this_lock.locked()
131+
132+
def test_rlock_released_after_error_noargs(this_lock):
133+
"""If an exception occurs in a with block, the lock should release."""
134+
try:
135+
with this_lock:
136+
assert this_lock.locked()
137+
raise DummyException()
138+
except DummyException:
139+
pass
140+
assert not this_lock.locked()

0 commit comments

Comments
 (0)