Skip to content

Commit 4a56ee2

Browse files
committed
Execute handle_error()/handle_error_async() on exception
1 parent 34cfa75 commit 4a56ee2

File tree

10 files changed

+88
-30
lines changed

10 files changed

+88
-30
lines changed

postgres_lock/asyncpg.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,22 @@ async def acquire_async(lock: Lock, block: bool = True) -> bool:
4545
return False if result is False else True
4646

4747

48-
def handle_error(lock: Lock) -> None:
48+
def handle_error(lock: Lock, exc: BaseException) -> None:
4949
"""
5050
Handle an error.
51+
52+
Parameters:
53+
exc (Exception): Exception.
5154
"""
5255
raise NotImplementedError("ascynpg interface does not support handle_error()")
5356

5457

55-
async def handle_error_async(lock: Lock) -> None:
58+
async def handle_error_async(lock: Lock, exc: BaseException) -> None:
5659
"""
5760
Handle an error asynchronously.
61+
62+
Parameters:
63+
exc (Exception): Exception.
5864
"""
5965
if not lock.rollback_on_error:
6066
return

postgres_lock/lock.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,23 @@ async def acquire_async(self, block: bool = True) -> bool:
151151

152152
return self._locked
153153

154-
def handle_error(self) -> None:
154+
def handle_error(self, exc: BaseException) -> None:
155155
"""
156156
Handle an error.
157+
158+
Parameters:
159+
exc (Exception): Exception.
157160
"""
158-
return self.impl.handle_error(self)
161+
return self.impl.handle_error(self, exc)
159162

160-
async def handle_error_async(self) -> None:
163+
async def handle_error_async(self, exc: BaseException) -> None:
161164
"""
162165
Handle an error asynchronously.
166+
167+
Parameters:
168+
exc (Exception): Exception.
163169
"""
164-
return await self.impl.handle_error_async(self)
170+
return await self.impl.handle_error_async(self, exc)
165171

166172
@property
167173
def locked(self) -> bool:
@@ -304,6 +310,9 @@ async def __aexit__(
304310
Exception (BaseException): Exception that was raised.
305311
Traceback (TracebackType): Traceback.
306312
"""
313+
if exc:
314+
await self.impl.handle_error_async(self, exc)
315+
307316
await self.impl.release_async(self)
308317

309318
if exc:
@@ -329,6 +338,9 @@ def __exit__(
329338
Exception (BaseException): Exception that was raised.
330339
Traceback (TracebackType): Traceback.
331340
"""
341+
if exc:
342+
self.impl.handle_error(self, exc)
343+
332344
self.impl.release(self)
333345

334346
if exc:

postgres_lock/psycopg2.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,25 @@ async def acquire_async(lock: Lock, block: bool = True) -> bool:
4848
raise NotImplementedError("psycopg2 interface does not support acquire_async()")
4949

5050

51-
def handle_error(lock: Lock) -> None:
51+
def handle_error(lock: Lock, exc: BaseException) -> None:
5252
"""
5353
Handle an error.
54+
55+
Parameters:
56+
exc (Exception): Exception.
5457
"""
5558
if not lock.rollback_on_error:
5659
return
5760

5861
lock.conn.rollback()
5962

6063

61-
async def handle_error_async(lock: Lock) -> None:
64+
async def handle_error_async(lock: Lock, exc: BaseException) -> None:
6265
"""
6366
Handle an error asynchronously.
67+
68+
Parameters:
69+
exc (Exception): Exception.
6470
"""
6571
raise NotImplementedError(
6672
"psycopg2 interface does not support handle_error_async()"

postgres_lock/psycopg3.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def acquire(lock: Lock, block: bool = True) -> bool:
2828
cursor = lock.conn.cursor()
2929
cursor.execute(f"SELECT pg_catalog.{lock_func}({lock.lock_id})")
3030
result, *_ = cursor.fetchone()
31+
cursor.close()
3132

3233
# lock function returns True/False in unblocking mode, and always None in blocking mode
3334
return False if result is False else True
@@ -54,24 +55,31 @@ async def acquire_async(lock: Lock, block: bool = True) -> bool:
5455
await cursor.execute(f"SELECT pg_catalog.{lock_func}({lock.lock_id})")
5556

5657
result, *_ = await cursor.fetchone()
58+
cursor.close()
5759

5860
# lock function returns True/False in unblocking mode, and always None in blocking mode
5961
return False if result is False else True
6062

6163

62-
def handle_error(lock: Lock) -> None:
64+
def handle_error(lock: Lock, exc: BaseException) -> None:
6365
"""
6466
Handle an error.
67+
68+
Parameters:
69+
exc (Exception): Exception.
6570
"""
6671
if not lock.rollback_on_error:
6772
return
6873

6974
lock.conn.rollback()
7075

7176

72-
async def handle_error_async(lock: Lock) -> None:
77+
async def handle_error_async(lock: Lock, exc: BaseException) -> None:
7378
"""
7479
Handle an error asynchronously.
80+
81+
Parameters:
82+
exc (Exception): Exception.
7583
"""
7684
if not lock.rollback_on_error:
7785
return
@@ -92,6 +100,7 @@ def release(lock: Lock) -> bool:
92100
cursor = lock.conn.cursor()
93101
cursor.execute(f"SELECT pg_catalog.{lock.unlock_func}({lock.lock_id})")
94102
result, *_ = cursor.fetchone()
103+
cursor.close()
95104

96105
return result
97106

@@ -111,5 +120,6 @@ async def release_async(lock: Lock) -> bool:
111120
await cursor.execute(f"SELECT pg_catalog.{lock.unlock_func}({lock.lock_id})")
112121

113122
result, *_ = await cursor.fetchone()
123+
cursor.close()
114124

115125
return result

postgres_lock/sqlalchemy.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,25 @@ async def acquire_async(lock: Lock, block: bool = True) -> bool:
5959
return False if result is False else True
6060

6161

62-
def handle_error(lock: Lock) -> None:
62+
def handle_error(lock: Lock, exc: BaseException) -> None:
6363
"""
6464
Handle an error.
65+
66+
Parameters:
67+
exc (Exception): Exception.
6568
"""
6669
if not lock.rollback_on_error:
6770
return
6871

6972
lock.conn.rollback()
7073

7174

72-
async def handle_error_async(lock: Lock) -> None:
75+
async def handle_error_async(lock: Lock, exc: BaseException) -> None:
7376
"""
7477
Handle an error asynchronously.
78+
79+
Parameters:
80+
exc (Exception): Exception.
7581
"""
7682
if not lock.rollback_on_error:
7783
return

tests/test_asyncpg.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ async def test_acquire_async__block_true(result):
8787

8888
def test_handle_error():
8989
with raises(NotImplementedError) as exc:
90-
handle_error(None)
90+
handle_error(None, None)
9191

9292
assert str(exc.value) == "ascynpg interface does not support handle_error()"
9393

@@ -97,14 +97,14 @@ async def test_handle_error_async():
9797
lock = Mock()
9898
lock.conn.execute = AsyncMock()
9999

100-
await handle_error_async(lock)
100+
await handle_error_async(lock, None)
101101

102102

103103
@mark.asyncio
104104
async def test_handle_error_async__rollback_disabled():
105105
lock = Mock(rollback_on_error=False)
106106

107-
await handle_error_async(lock)
107+
await handle_error_async(lock, None)
108108

109109

110110
def test_release():

tests/test_lock.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def test_context_manager__raises_exception(_load_impl):
204204
assert str(exc.value) == "Inner exception"
205205

206206
lock.impl.acquire.assert_called_with(lock, block=True)
207+
lock.impl.handle_error.assert_called_with(lock, exc.value)
207208
lock.impl.release.assert_called_with(lock)
208209

209210

@@ -226,6 +227,7 @@ async def test_context_manager_async(_load_impl):
226227
async def test_context_manager_async__raises_exception(_load_impl):
227228
lock = Lock(None, "key")
228229
lock.impl.acquire_async = AsyncMock()
230+
lock.impl.handle_error_async = AsyncMock()
229231
lock.impl.release_async = AsyncMock()
230232

231233
with raises(Exception) as exc:
@@ -235,27 +237,32 @@ async def test_context_manager_async__raises_exception(_load_impl):
235237
assert str(exc.value) == "Inner exception"
236238

237239
lock.impl.acquire_async.assert_called_with(lock, block=True)
240+
lock.impl.handle_error_async.assert_called_with(lock, exc.value)
238241
lock.impl.release_async.assert_called_with(lock)
239242

240243

241244
@patch(f"{PATH}.Lock._load_impl")
242245
def test_handle_error(_load_impl):
243246
lock = Lock(None, "key")
247+
exc = Exception()
244248

245-
assert lock.impl.handle_error.return_value == lock.handle_error()
249+
assert lock.impl.handle_error.return_value == lock.handle_error(exc)
246250

247-
lock.impl.handle_error.assert_called_with(lock)
251+
lock.impl.handle_error.assert_called_with(lock, exc)
248252

249253

250254
@mark.asyncio
251255
@patch(f"{PATH}.Lock._load_impl")
252256
async def test_handle_error_async(_load_impl):
253257
lock = Lock(None, "key")
254258
lock.impl.handle_error_async = AsyncMock()
259+
exc = Exception()
255260

256-
assert lock.impl.handle_error_async.return_value == await lock.handle_error_async()
261+
assert lock.impl.handle_error_async.return_value == await lock.handle_error_async(
262+
exc
263+
)
257264

258-
lock.impl.handle_error_async.assert_called_with(lock)
265+
lock.impl.handle_error_async.assert_called_with(lock, exc)
259266

260267

261268
@patch(f"{PATH}.Lock._load_impl")

tests/test_psycopg2.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def test_acquire__defaults(result):
3030
assert not acquire(lock)
3131

3232
cursor.execute.assert_called_with(f"SELECT pg_catalog.{lock_func}({lock.lock_id})")
33+
cursor.close.assert_called_once()
3334

3435

3536
@mark.parametrize("result", [None, True, False])
@@ -72,6 +73,7 @@ def test_acquire__block_true(result):
7273
assert not acquire(lock, block=True)
7374

7475
cursor.execute.assert_called_with(f"SELECT pg_catalog.{lock_func}({lock.lock_id})")
76+
cursor.close.assert_called_once()
7577

7678

7779
@mark.asyncio
@@ -85,21 +87,21 @@ async def test_acquire_async():
8587
def test_handle_error():
8688
lock = Mock()
8789

88-
handle_error(lock)
90+
handle_error(lock, None)
8991

9092
lock.conn.rollback.assert_called_once()
9193

9294

9395
def test_handle_error__rollback_disabled():
9496
lock = Mock(rollback_on_error=False)
9597

96-
handle_error(lock)
98+
handle_error(lock, None)
9799

98100

99101
@mark.asyncio
100102
async def test_handle_error_async():
101103
with raises(NotImplementedError) as exc:
102-
await handle_error_async(None)
104+
await handle_error_async(None, None)
103105

104106
assert str(exc.value) == "psycopg2 interface does not support handle_error_async()"
105107

@@ -117,6 +119,7 @@ def test_release(result):
117119
cursor.execute.assert_called_with(
118120
f"SELECT pg_catalog.{lock.unlock_func}({lock.lock_id})"
119121
)
122+
cursor.close.assert_called_once()
120123

121124

122125
@mark.asyncio

0 commit comments

Comments
 (0)