8000 bpo-34793: Drop old-style context managers in asyncio.locks (GH-17533) · python/cpython@90d9ba6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 90d9ba6

Browse files
authored
bpo-34793: Drop old-style context managers in asyncio.locks (GH-17533)
1 parent abb9a44 commit 90d9ba6

File tree

6 files changed

+50
-223
lines changed

6 files changed

+50
-223
lines changed

Doc/library/asyncio-sync.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ BoundedSemaphore
347347
---------
348348

349349

350-
.. deprecated:: 3.7
350+
.. versionchanged:: 3.9
351351

352352
Acquiring a lock using ``await lock`` or ``yield from lock`` and/or
353353
:keyword:`with` statement (``with await lock``, ``with (yield from
354-
lock)``) is deprecated. Use ``async with lock`` instead.
354+
lock)``) was removed. Use ``async with lock`` instead.

Doc/whatsnew/3.9.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,11 @@ Removed
470470
:exc:`DeprecationWarning` since Python 3.8.
471471
(Contributed by Inada Naoki in :issue:`39377`)
472472

473+
* ``with (await asyncio.lock):`` and ``with (yield from asyncio.lock):`` statements are
474+
not longer supported, use ``async with lock`` instead. The same is correct for
475+
``asyncio.Condition`` and ``asyncio.Semaphore``.
476+
(Contributed by Andrew Svetlov in :issue:`34793`.)
477+
473478

474479
Porting to Python 3.9
475480
=====================

Lib/asyncio/locks.py

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,96 +3,13 @@
33
__all__ = ('Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore')
44

55
import collections
6-
import types
76
import warnings
87

98
from . import events
10-
from . import futures
119
from . import exceptions
12-
from .import coroutines
13-
14-
15-
class _ContextManager:
16-
"""Context manager.
17-
18-
This enables the following idiom for acquiring and releasing a
19-
lock around a block:
20-
21-
with (yield from lock):
22-
<block>
23-
24-
while failing loudly when accidentally using:
25-
26-
with lock:
27-
<block>
28-
29-
Deprecated, use 'async with' statement:
30-
async with lock:
31-
<block>
32-
"""
33-
34-
def __init__(self, lock):
35-
self._lock = lock
36-
37-
def __enter__(self):
38-
# We have no use for the "as ..." clause in the with
39-
# statement for locks.
40-
return None
41-
42-
def __exit__(self, *args):
43-
try:
44-
self._lock.release()
45-
finally:
46-
self._lock = None # Crudely prevent reuse.
4710

4811

4912
class _ContextManagerMixin:
50-
def __enter__(self):
51-
raise RuntimeError(
52-
'"yield from" should be used as context manager expression')
53-
54-
def __exit__(self, *args):
55-
# This must exist because __enter__ exists, even though that
56-
# always raises; that's how the with-statement works.
57-
pass
58-
59-
@types.coroutine
60-
def __iter__(self):
61-
# This is not a coroutine. It is meant to enable the idiom:
62-
#
63-
# with (yield from lock):
64-
# <block>
65-
#
66-
# as an alternative to:
67-
#
68-
# yield from lock.acquire()
69-
# try:
70-
# <block>
71-
# finally:
72-
# lock.release()
73-
# Deprecated, use 'async with' statement:
74-
# async with lock:
75-
# <block>
76-
warnings.warn("'with (yield from lock)' is deprecated "
77-
"use 'async with lock' instead",
78-
DeprecationWarning, stacklevel=2)
79-
yield from self.acquire()
80-
return _ContextManager(self)
81-
82-
# The flag is needed for legacy asyncio.iscoroutine()
83-
__iter__._is_coroutine = coroutines._is_coroutine
84-
85-
async def __acquire_ctx(self):
86-
await self.acquire()
87-
return _ContextManager(self)
88-
89-
def __await__(self):
90-
warnings.warn("'with await lock' is deprecated "
91-
"use 'async with lock' instead",
92-
DeprecationWarning, stacklevel=2)
93-
# To make "with await lock" work.
94-
return self.__acquire_ctx().__await__()
95-
9613
async def __aenter__(self):
9714
await self.acquire()
9815
# We have no use for the "as ..." clause in the with

Lib/test/test_asyncio/test_locks.py

Lines changed: 34 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,24 @@ def test_repr(self):
4747
self.assertTrue(repr(lock).endswith('[unlocked]>'))
4848
self.assertTrue(RGX_REPR.match(repr(lock)))
4949

50-
with self.assertWarns(DeprecationWarning):
51-
@asyncio.coroutine
52-
def acquire_lock():
53-
with self.assertWarns(DeprecationWarning):
54-
yield from lock
55-
56-
self.loop.run_until_complete(acquire_lock())
50+
self.loop.run_until_complete(lock.acquire())
5751
self.assertTrue(repr(lock).endswith('[locked]>'))
5852
self.assertTrue(RGX_REPR.match(repr(lock)))
5953

6054
def test_lock(self):
6155
with self.assertWarns(DeprecationWarning):
6256
lock = asyncio.Lock(loop=self.loop)
6357

64-
6558
@asyncio.coroutine
6659
def acquire_lock():
67-
with self.assertWarns(DeprecationWarning):
68-
return (yield from lock)
69-
70-
res = self.loop.run_until_complete(acquire_lock())
60+
return (yield from lock)
7161

72-
self.assertTrue(res)
73-
self.assertTrue(lock.locked())
62+
with self.assertRaisesRegex(
63+
TypeError,
64+
"object is not iterable"
65+
):
66+
self.loop.run_until_complete(acquire_lock())
7467

75-
lock.release()
7668
self.assertFalse(lock.locked())
7769

7870
def test_lock_by_with_statement(self):
@@ -90,13 +82,13 @@ def test_lock_by_with_statement(self):
9082
def test(lock):
9183
yield from asyncio.sleep(0.01)
9284
self.assertFalse(lock.locked())
93-
with self.assertWarns(DeprecationWarning):
94-
with (yield from lock) as _lock:
95-
self.assertIs(_lock, None)
96-
self.assertTrue(lock.locked())
97-
yield from asyncio.sleep(0.01)
98-
self.assertTrue(lock.locked())
99-
self.assertFalse(lock.locked())
85+
with self.assertRaisesRegex(
86+
TypeError,
87+
"object is not iterable"
88+
):
89+
with (yield from lock):
90+
pass
91+
self.assertFalse(lock.locked())
10092

10193
for primitive in primitives:
10294
loop.run_until_complete(test(primitive))
@@ -302,52 +294,16 @@ def test_release_no_waiters(self):
302294
self.assertFalse(lock.locked())
303295

304296
def test_context_manager(self):
305-
with self.assertWarns(DeprecationWarning):
306-
lock = asyncio.Lock(loop=self.loop)
297+
async def f():
298+
lock = asyncio.Lock()
299+
self.assertFalse(lock.locked())
307300

308-
@asyncio.coroutine
309-
def acquire_lock():
310-
with self.assertWarns(DeprecationWarning):
311-
return (yield from lock)
301+
async with lock:
302+
self.assertTrue(lock.locked())
312303

313-
with self.loop.run_until_complete(acquire_lock()):
314-
self.assertTrue(lock.locked())
304+
self.assertFalse(lock.locked())
315305

316-
self.assertFalse(lock.locked())
317-
318-
def test_context_manager_cant_reuse(self):
319-
with self.assertWarns(DeprecationWarning):
320-
lock = asyncio.Lock(loop=self.loop)
321-
322-
@asyncio.coroutine
323-
def acquire_lock():
324-
with self.assertWarns(DeprecationWarning):
325-
return (yield from lock)
326-
327-
# This spells "yield from lock" outside a generator.
328-
cm = self.loop.run_until_complete(acquire_lock())
329-
with cm:
330-
self.assertTrue(lock.locked())
331-
332-
self.assertFalse(lock.locked())
333-
334-
with self.assertRaises(AttributeError):
335-
with cm:
336-
pass
337-
338-
def test_context_manager_no_yield(self):
339-
with self.assertWarns(DeprecationWarning):
340-
lock = asyncio.Lock(loop=self.loop)
341-
342-
try:
343-
with lock:
344-
self.fail('RuntimeError is not raised in with expression')
345-
except RuntimeError as err:
346-
self.assertEqual(
347-
str(err),
348-
'"yield from" should be used as context manager expression')
349-
350-
self.assertFalse(lock.locked())
306+
self.loop.run_until_complete(f())
351307

352308

353309
class EventTests(test_utils.TestCase):
@@ -809,33 +765,14 @@ def test_repr(self):
809765
self.assertTrue(RGX_REPR.match(repr(cond)))
810766

811767
def test_context_manager(self):
812-
with self.assertWarns(DeprecationWarning):
813-
cond = asyncio.Condition(loop=self.loop)
814-
815-
with self.assertWarns(DeprecationWarning):
816-
@asyncio.coroutine
817-
def acquire_cond():
818-
with self.assertWarns(DeprecationWarning):
819-
return (yield from cond)
820-
821-
with self.loop.run_until_complete(acquire_cond()):
822-
self.assertTrue(cond.locked())
823-
824-
self.assertFalse(cond.locked())
825-
826-
def test_context_manager_no_yield(self):
827-
with self.assertWarns(DeprecationWarning):
828-
cond = asyncio.Condition(loop=self.loop)
829-
830-
try:
831-
with cond:
832-
self.fail('RuntimeError is not raised in with expression')
833-
except RuntimeError as err:
834-
self.assertEqual(
835-
str(err),
836-
'"yield from" should be used as context manager expression')
768+
async def f():
769+
cond = asyncio.Condition()
770+
self.assertFalse(cond.locked())
771+
async with cond:
772+
self.assertTrue(cond.locked())
773+
self.assertFalse(cond.locked())
837774

838-
self.assertFalse(cond.locked())
775+
self.loop.run_until_complete(f())
839776

840777
def test_explicit_lock(self):
841778
with self.assertWarns(DeprecationWarning):
@@ -920,16 +857,14 @@ def test_semaphore(self):
920857
with self.assertWarns(DeprecationWarning):
921858
@asyncio.coroutine
922859
def acquire_lock():
923-
with self.assertWarns(DeprecationWarning):
924-
return (yield from sem)
860+
return (yield from sem)
925861

926-
res = self.loop.run_until_complete(acquire_lock())
927-
928-
self.assertTrue(res)
929-
self.assertTrue(sem.locked())
930-
self.assertEqual(0, sem._value)
862+
with self.assertRaisesRegex(
863+
TypeError,
864+
"'Semaphore' object is not iterable",
865+
):
866+
self.loop.run_until_complete(acquire_lock())
931867

932-
sem.release()
933868
self.assertFalse(sem.locked())
934869
self.assertEqual(1, sem._value)
935870

@@ -1064,38 +999,6 @@ def test_release_no_waiters(self):
1064999
sem.release()
10651000
self.assertFalse(sem.locked())
10661001

1067-
def test_context_manager(self):
1068-
with self.assertWarns(DeprecationWarning):
1069-
sem = asyncio.Semaphore(2, loop=self.loop)
1070-
1071-
@asyncio.coroutine
1072-
def acquire_lock():
1073-
with self.assertWarns(DeprecationWarning):
1074-
return (yield from sem)
1075-
1076-
with self.loop.run_until_complete(acquire_lock()):
1077-
self.assertFalse(sem.locked())
1078-
self.assertEqual(1, sem._value)
1079-
1080-
with self.loop.run_until_complete(acquire_lock()):
1081-
self.assertTrue(sem.locked())
1082-
1083-
self.assertEqual(2, sem._value)
1084-
1085-
def test_context_manager_no_yield(self):
1086-
with self.assertWarns(DeprecationWarning):
1087-
sem = asyncio.Semaphore(2, loop=self.loop)
1088-
1089-
try:
1090-
with sem:
1091-
self.fail('RuntimeError is not raised in with expression')
1092-
except RuntimeError as err:
1093-
self.assertEqual(
1094-
str(err),
1095-
'"yield from" should be used as context manager expression')
1096-
1097-
self.assertEqual(2, sem._value)
1098-
10991002

11001003
if __name__ == '__main__':
11011004
unittest.main()

Lib/test/test_asyncio/test_pep492.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,12 @@ def test_context_manager_with_await(self):
7777
async def test(lock):
7878
await asyncio.sleep(0.01)
7979
self.assertFalse(lock.locked())
80-
with self.assertWarns(DeprecationWarning):
81-
with await lock as _lock:
82-
self.assertIs(_lock, None)
83-
self.assertTrue(lock.locked())
84-
await asyncio.sleep(0.01)
85-
self.assertTrue(lock.locked())
86-
self.assertFalse(lock.locked())
80+
with self.assertRaisesRegex(
81+
TypeError,
82+
"can't be used in 'await' expression"
83+
):
84+
with await lock:
85+
pass
8786

8887
for primitive in primitives:
8988
self.loop.run_until_complete(test(primitive))
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Remove support for ``with (await asyncio.lock):`` and ``with (yield from
2+
asyncio.lock):``. The same is correct for ``asyncio.Condition`` and
3+
``asyncio.Semaphore``.

0 commit comments

Comments
 (0)
0