Skip to content

Commit 0ec34ca

Browse files
uriyyoasvetlov
andauthored
bpo-42392: Remove loop parameter form asyncio locks and Queue (#23420)
Co-authored-by: Andrew Svetlov <[email protected]>
1 parent b0b4285 commit 0ec34ca

File tree

10 files changed

+304
-451
lines changed

10 files changed

+304
-451
lines changed

Lib/asyncio/locks.py

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
__all__ = ('Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore')
44

55
import collections
6-
import warnings
76

8-
from . import events
97
from . import exceptions
8+
from . import mixins
109

1110

1211
class _ContextManagerMixin:
@@ -20,7 +19,7 @@ async def __aexit__(self, exc_type, exc, tb):
2019
self.release()
2120

2221

23-
class Lock(_ContextManagerMixin):
22+
class Lock(_ContextManagerMixin, mixins._LoopBoundedMixin):
2423
"""Primitive lock objects.
2524
2625
A primitive lock is a synchronization primitive that is not owned
@@ -74,16 +73,9 @@ class Lock(_ContextManagerMixin):
7473
7574
"""
7675

77-
def __init__(self, *, loop=None):
76+
def __init__(self):
7877
self._waiters = None
7978
self._locked = False
80-
if loop is None:
81-
self._loop = events.get_event_loop()
82-
else:
83-
self._loop = loop
84-
warnings.warn("The loop argument is deprecated since Python 3.8, "
85-
"and scheduled for removal in Python 3.10.",
86-
DeprecationWarning, stacklevel=2)
8779

8880
def __repr__(self):
8981
res = super().__repr__()
@@ -109,7 +101,7 @@ async def acquire(self):
109101

110102
if self._waiters is None:
111103
self._waiters = collections.deque()
112-
fut = self._loop.create_future()
104+
fut = self._get_loop().create_future()
113105
self._waiters.append(fut)
114106

115107
# Finally block should be called before the CancelledError
@@ -161,7 +153,7 @@ def _wake_up_first(self):
161153
fut.set_result(True)
162154

163155

164-
class Event:
156+
class Event(mixins._LoopBoundedMixin):
165157
"""Asynchronous equivalent to threading.Event.
166158
167159
Class implementing event objects. An event manages a flag that can be set
@@ -170,16 +162,9 @@ class Event:
170162
false.
171163
"""
172164

173-
def __init__(self, *, loop=None):
165+
def __init__(self):
174166
self._waiters = collections.deque()
175167
self._value = False
176-
if loop is None:
177-
self._loop = events.get_event_loop()
178-
else:
179-
self._loop = loop
180-
warnings.warn("The loop argument is deprecated since Python 3.8, "
181-
"and scheduled for removal in Python 3.10.",
182-
DeprecationWarning, stacklevel=2)
183168

184169
def __repr__(self):
185170
res = super().__repr__()
@@ -220,7 +205,7 @@ async def wait(self):
220205
if self._value:
221206
return True
222207

223-
fut = self._loop.create_future()
208+
fut = self._get_loop().create_future()
224209
self._waiters.append(fut)
225210
try:
226211
await fut
@@ -229,7 +214,7 @@ async def wait(self):
229214
self._waiters.remove(fut)
230215

231216

232-
class Condition(_ContextManagerMixin):
217+
class Condition(_ContextManagerMixin, mixins._LoopBoundedMixin):
233218
"""Asynchronous equivalent to threading.Condition.
234219
235220
This class implements condition variable objects. A condition variable
@@ -239,18 +224,10 @@ class Condition(_ContextManagerMixin):
239224
A new Lock object is created and used as the underlying lock.
240225
"""
241226

242-
def __init__(self, lock=None, *, loop=None):
243-
if loop is None:
244-
self._loop = events.get_event_loop()
245-
else:
246-
self._loop = loop
247-
warnings.warn("The loop argument is deprecated since Python 3.8, "
248-
"and scheduled for removal in Python 3.10.",
249-
DeprecationWarning, stacklevel=2)
250-
227+
def __init__(self, lock=None):
251228
if lock is None:
252-
lock = Lock(loop=loop)
253-
elif lock._loop is not self._loop:
229+
lock = Lock()
230+
elif lock._loop is not self._get_loop():
254231
raise ValueError("loop argument must agree with lock")
255232

256233
self._lock = lock
@@ -284,7 +261,7 @@ async def wait(self):
284261

285262
self.release()
286263
try:
287-
fut = self._loop.create_future()
264+
fut = self._get_loop().create_future()
288265
self._waiters.append(fut)
289266
try:
290267
await fut
@@ -351,7 +328,7 @@ def notify_all(self):
351328
self.notify(len(self._waiters))
352329

353330

354-
class Semaphore(_ContextManagerMixin):
331+
class Semaphore(_ContextManagerMixin, mixins._LoopBoundedMixin):
355332
"""A Semaphore implementation.
356333
357334
A semaphore manages an internal counter which is decremented by each
@@ -366,18 +343,11 @@ class Semaphore(_ContextManagerMixin):
366343
ValueError is raised.
367344
"""
368345

369-
def __init__(self, value=1, *, loop=None):
346+
def __init__(self, value=1):
370347
if value < 0:
371348
raise ValueError("Semaphore initial value must be >= 0")
372349
self._value = value
373350
self._waiters = collections.deque()
374-
if loop is None:
375-
self._loop = events.get_event_loop()
376-
else:
377-
self._loop = loop
378-
warnings.warn("The loop argument is deprecated since Python 3.8, "
379-
"and scheduled for removal in Python 3.10.",
380-
DeprecationWarning, stacklevel=2)
381351

382352
def __repr__(self):
383353
res = super().__repr__()
@@ -407,7 +377,7 @@ async def acquire(self):
407377
True.
408378
"""
409379
while self._value <= 0:
410-
fut = self._loop.create_future()
380+
fut = self._get_loop().create_future()
411381
self._waiters.append(fut)
412382
try:
413383
await fut
@@ -436,14 +406,9 @@ class BoundedSemaphore(Semaphore):
436406
above the initial value.
437407
"""
438408

439-
def __init__(self, value=1, *, loop=None):
440-
if loop:
441-
warnings.warn("The loop argument is deprecated since Python 3.8, "
442-
"and scheduled for removal in Python 3.10.",
443-
DeprecationWarning, stacklevel=2)
444-
409+
def __init__(self, value=1):
445410
self._bound_value = value
446-
super().__init__(value, loop=loop)
411+
super().__init__(value)
447412

448413
def release(self):
449414
if self._value >= self._bound_value:

Lib/asyncio/mixins.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Event loop mixins."""
2+
3+
import threading
4+
from . import events
5+
6+
_global_lock = threading.Lock()
7+
8+
9+
class _LoopBoundedMixin:
10+
_loop = None
11+
12+
def _get_loop(self):
13+
loop = events._get_running_loop()
14+
15+
if self._loop is None:
16+
with _global_lock:
17+
if self._loop is None:
18+
self._loop = loop
19+
if loop is not self._loop:
20+
raise RuntimeError(f'{type(self).__name__} have already bounded to another loop')
21+
return loop

Lib/asyncio/queues.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
import collections
44
import heapq
5-
import warnings
65

7-
from . import events
86
from . import locks
7+
from . import mixins
98

109

1110
class QueueEmpty(Exception):
@@ -18,7 +17,7 @@ class QueueFull(Exception):
1817
pass
1918

2019

21-
class Queue:
20+
class Queue(mixins._LoopBoundedMixin):
2221
"""A queue, useful for coordinating producer and consumer coroutines.
2322
2423
If maxsize is less than or equal to zero, the queue size is infinite. If it
@@ -30,22 +29,15 @@ class Queue:
3029
interrupted between calling qsize() and doing an operation on the Queue.
3130
"""
3231

33-
def __init__(self, maxsize=0, *, loop=None):
34-
if loop is None:
35-
self._loop = events.get_event_loop()
36-
else:
37-
self._loop = loop
38-
warnings.warn("The loop argument is deprecated since Python 3.8, "
39-
"and scheduled for removal in Python 3.10.",
40-
DeprecationWarning, stacklevel=2)
32+
def __init__(self, maxsize=0):
4133
self._maxsize = maxsize
4234

4335
# Futures.
4436
self._getters = collections.deque()
4537
# Futures.
4638
self._putters = collections.deque()
4739
self._unfinished_tasks = 0
48-
self._finished = locks.Event(loop=loop)
40+
self._finished = locks.Event()
4941
self._finished.set()
5042
self._init(maxsize)
5143

@@ -122,7 +114,7 @@ async def put(self, item):
122114
slot is available before adding item.
123115
"""
124116
while self.full():
125-
putter = self._loop.create_future()
117+
putter = self._get_loop().create_future()
126118
self._putters.append(putter)
127119
try:
128120
await putter
@@ -160,7 +152,7 @@ async def get(self):
160152
If queue is empty, wait until an item is available.
161153
"""
162154
while self.empty():
163-
getter = self._loop.create_future()
155+
getter = self._get_loop().create_future()
164156
self._getters.append(getter)
165157
try:
166158
await getter

Lib/asyncio/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ def as_completed(fs, *, loop=None, timeout=None):
578578
raise TypeError(f"expect an iterable of futures, not {type(fs).__name__}")
579579

580580
from .queues import Queue # Import here to avoid circular import problem.
581-
done = Queue(loop=loop)
581+
done = Queue()
582582

583583
if loop is None:
584584
loop = events.get_event_loop()

0 commit comments

Comments
 (0)