Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3fae04b

Browse files
[3.11] gh-93453: Only emit deprecation warning in asyncio.get_event_loop when a new event loop is created (#99949)
It no longer emits a deprecation warning if the current event loop was set. Co-authored-by: Łukasz Langa <[email protected]>
1 parent 235f5fd commit 3fae04b

13 files changed

+109
-123
lines changed

Doc/library/asyncio-eventloop.rst

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ an event loop:
4343

4444
Get the current event loop.
4545

46-
If there is no current event loop set in the current OS thread,
47-
the OS thread is main, and :func:`set_event_loop` has not yet
48-
been called, asyncio will create a new event loop and set it as the
49-
current one.
46+
When called from a coroutine or a callback (e.g. scheduled with
47+
call_soon or similar API), this function will always return the
48+
running event loop.
49+
50+
If there is no running event loop set, the function will return
51+
the result of ``get_event_loop_policy().get_event_loop()`` call.
5052

5153
Because this function has rather complex behavior (especially
5254
when custom event loop policies are in use), using the
@@ -58,10 +60,14 @@ an event loop:
5860
event loop.
5961

6062
.. deprecated:: 3.10
61-
Emits a deprecation warning if there is no running event loop.
62-
In future Python releases, this function may become an alias of
63-
:func:`get_running_loop` and will accordingly raise a
64-
:exc:`RuntimeError` if there is no running event loop.
63+
Deprecation warning is emitted if there is no current event loop.
64+
In Python 3.12 it will be an error.
65+
66+
.. note::
67+
In Python versions 3.10.0--3.10.8 and 3.11.0 this function
68+
(and other functions which used it implicitly) emitted a
69+
:exc:`DeprecationWarning` if there was no running event loop, even if
70+
the current loop was set.
6571

6672
.. function:: set_event_loop(loop)
6773

Doc/library/asyncio-llapi-index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Obtaining the Event Loop
1919
- The **preferred** function to get the running event loop.
2020

2121
* - :func:`asyncio.get_event_loop`
22-
- Get an event loop instance (current or via the policy).
22+
- Get an event loop instance (running or current via the current policy).
2323

2424
* - :func:`asyncio.set_event_loop`
2525
- Set the event loop as current via the current policy.

Doc/library/asyncio-policy.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ asyncio ships with the following built-in policies:
112112

113113
On Windows, :class:`ProactorEventLoop` is now used by default.
114114

115+
.. deprecated:: 3.11.1
116+
:meth:`get_event_loop` now emits a :exc:`DeprecationWarning` if there
117+
is no current event loop set and a new event loop has been implicitly
118+
created. In Python 3.12 it will be an error.
119+
115120

116121
.. class:: WindowsSelectorEventLoopPolicy
117122

Lib/asyncio/events.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,21 @@ def get_event_loop(self):
671671
if (self._local._loop is None and
672672
not self._local._set_called and
673673
threading.current_thread() is threading.main_thread()):
674+
stacklevel = 2
675+
try:
676+
f = sys._getframe(1)
677+
except AttributeError:
678+
pass
679+
else:
680+
while f:
681+
module = f.f_globals.get('__name__')
682+
if not (module == 'asyncio' or module.startswith('asyncio.')):
683+
break
684+
f = f.f_back
685+
stacklevel += 1
686+
import warnings
687+
warnings.warn('There is no current event loop',
688+
DeprecationWarning, stacklevel=stacklevel)
674689
self.set_event_loop(self.new_event_loop())
675690

676691
if self._local._loop is None:
@@ -786,12 +801,13 @@ def get_event_loop():
786801

787802

788803
def _get_event_loop(stacklevel=3):
804+
# This internal method is going away in Python 3.12, left here only for
805+
# backwards compatibility with 3.10.0 - 3.10.8 and 3.11.0.
806+
# Similarly, this method's C equivalent in _asyncio is going away as well.
807+
# See GH-99949 for more details.
789808
current_loop = _get_running_loop()
790809
if current_loop is not None:
791810
return current_loop
792-
import warnings
793-
warnings.warn('There is no current event loop',
794-
DeprecationWarning, stacklevel=stacklevel)
795811
return get_event_loop_policy().get_event_loop()
796812

797813

Lib/test/test_asyncio/test_base_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ async def coro():
746746
def test_env_var_debug(self):
747747
code = '\n'.join((
748748
'import asyncio',
749-
'loop = asyncio.get_event_loop()',
749+
'loop = asyncio.new_event_loop()',
750750
'print(loop.get_debug())'))
751751

752752
# Test with -E to not fail if the unit test was run with

Lib/test/test_asyncio/test_events.py

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,8 +2547,9 @@ def test_event_loop_policy(self):
25472547
def test_get_event_loop(self):
25482548
policy = asyncio.DefaultEventLoopPolicy()
25492549
self.assertIsNone(policy._local._loop)
2550-
2551-
loop = policy.get_event_loop()
2550+
with self.assertWarns(DeprecationWarning) as cm:
2551+
loop = policy.get_event_loop()
2552+
self.assertEqual(cm.filename, __file__)
25522553
self.assertIsInstance(loop, asyncio.AbstractEventLoop)
25532554

25542555
self.assertIs(policy._local._loop, loop)
@@ -2562,7 +2563,10 @@ def test_get_event_loop_calls_set_event_loop(self):
25622563
policy, "set_event_loop",
25632564
wraps=policy.set_event_loop) as m_set_event_loop:
25642565

2565-
loop = policy.get_event_loop()
2566+
with self.assertWarns(DeprecationWarning) as cm:
2567+
loop = policy.get_event_loop()
2568+
self.addCleanup(loop.close)
2569+
self.assertEqual(cm.filename, __file__)
25662570

25672571
# policy._local._loop must be set through .set_event_loop()
25682572
# (the unix DefaultEventLoopPolicy needs this call to attach
@@ -2596,7 +2600,8 @@ def test_new_event_loop(self):
25962600

25972601
def test_set_event_loop(self):
25982602
policy = asyncio.DefaultEventLoopPolicy()
2599-
old_loop = policy.get_event_loop()
2603+
old_loop = policy.new_event_loop()
2604+
policy.set_event_loop(old_loop)
26002605

26012606
self.assertRaises(TypeError, policy.set_event_loop, object())
26022607

@@ -2709,15 +2714,11 @@ def get_event_loop(self):
27092714
asyncio.set_event_loop_policy(Policy())
27102715
loop = asyncio.new_event_loop()
27112716

2712-
with self.assertWarns(DeprecationWarning) as cm:
2713-
with self.assertRaises(TestError):
2714-
asyncio.get_event_loop()
2715-
self.assertEqual(cm.filename, __file__)
2717+
with self.assertRaises(TestError):
2718+
asyncio.get_event_loop()
27162719
asyncio.set_event_loop(None)
2717-
with self.assertWarns(DeprecationWarning) as cm:
2718-
with self.assertRaises(TestError):
2719-
asyncio.get_event_loop()
2720-
self.assertEqual(cm.filename, __file__)
2720+
with self.assertRaises(TestError):
2721+
asyncio.get_event_loop()
27212722

27222723
with self.assertRaisesRegex(RuntimeError, 'no running'):
27232724
asyncio.get_running_loop()
@@ -2731,16 +2732,11 @@ async def func():
27312732
loop.run_until_complete(func())
27322733

27332734
asyncio.set_event_loop(loop)
2734-
with self.assertWarns(DeprecationWarning) as cm:
2735-
with self.assertRaises(TestError):
2736-
asyncio.get_event_loop()
2737-
self.assertEqual(cm.filename, __file__)
2738-
2735+
with self.assertRaises(TestError):
2736+
asyncio.get_event_loop()
27392737
asyncio.set_event_loop(None)
2740-
with self.assertWarns(DeprecationWarning) as cm:
2741-
with self.assertRaises(TestError):
2742-
asyncio.get_event_loop()
2743-
self.assertEqual(cm.filename, __file__)
2738+
with self.assertRaises(TestError):
2739+
asyncio.get_event_loop()
27442740

27452741
finally:
27462742
asyncio.set_event_loop_policy(old_policy)
@@ -2764,10 +2760,8 @@ def test_get_event_loop_returns_running_loop2(self):
27642760
self.addCleanup(loop2.close)
27652761
self.assertEqual(cm.filename, __file__)
27662762
asyncio.set_event_loop(None)
2767-
with self.assertWarns(DeprecationWarning) as cm:
2768-
with self.assertRaisesRegex(RuntimeError, 'no current'):
2769-
asyncio.get_event_loop()
2770-
self.assertEqual(cm.filename, __file__)
2763+
with self.assertRaisesRegex(RuntimeError, 'no current'):
2764+
asyncio.get_event_loop()
27712765

27722766
with self.assertRaisesRegex(RuntimeError, 'no running'):
27732767
asyncio.get_running_loop()
@@ -2781,15 +2775,11 @@ async def func():
27812775
loop.run_until_complete(func())
27822776

27832777
asyncio.set_event_loop(loop)
2784-
with self.assertWarns(DeprecationWarning) as cm:
2785-
self.assertIs(asyncio.get_event_loop(), loop)
2786-
self.assertEqual(cm.filename, __file__)
2778+
self.assertIs(asyncio.get_event_loop(), loop)
27872779

27882780
asyncio.set_event_loop(None)
2789-
with self.assertWarns(DeprecationWarning) as cm:
2790-
with self.assertRaisesRegex(RuntimeError, 'no current'):
2791-
asyncio.get_event_loop()
2792-
self.assertEqual(cm.filename, __file__)
2781+
with self.assertRaisesRegex(RuntimeError, 'no current'):
2782+
asyncio.get_event_loop()
27932783

27942784
finally:
27952785
asyncio.set_event_loop_policy(old_policy)

Lib/test/test_asyncio/test_futures.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,8 @@ def test_initial_state(self):
145145
self.assertTrue(f.cancelled())
146146

147147
def test_constructor_without_loop(self):
148-
with self.assertWarns(DeprecationWarning) as cm:
149-
with self.assertRaisesRegex(RuntimeError, 'There is no current event loop'):
150-
self._new_future()
151-
self.assertEqual(cm.filename, __file__)
148+
with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
149+
self._new_future()
152150

153151
def test_constructor_use_running_loop(self):
154152
async def test():
@@ -158,12 +156,10 @@ async def test():
158156
self.assertIs(f.get_loop(), self.loop)
159157

160158
def test_constructor_use_global_loop(self):
161-
# Deprecated in 3.10
159+
# Deprecated in 3.10, undeprecated in 3.11.1
162160
asyncio.set_event_loop(self.loop)
163161
self.addCleanup(asyncio.set_event_loop, None)
164-
with self.assertWarns(DeprecationWarning) as cm:
165-
f = self._new_future()
166-
self.assertEqual(cm.filename, __file__)
162+
f = self._new_future()
167163
self.assertIs(f._loop, self.loop)
168164
self.assertIs(f.get_loop(), self.loop)
169165

@@ -499,10 +495,8 @@ def run(arg):
499495
return (arg, threading.get_ident())
500496
ex = concurrent.futures.ThreadPoolExecutor(1)
501497
f1 = ex.submit(run, 'oi')
502-
with self.assertWarns(DeprecationWarning) as cm:
503-
with self.assertRaises(RuntimeError):
504-
asyncio.wrap_future(f1)
505-
self.assertEqual(cm.filename, __file__)
498+
with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
499+
asyncio.wrap_future(f1)
506500
ex.shutdown(wait=True)
507501

508502
def test_wrap_future_use_running_loop(self):
@@ -517,16 +511,14 @@ async def test():
517511
ex.shutdown(wait=True)
518512

519513
def test_wrap_future_use_global_loop(self):
520-
# Deprecated in 3.10
514+
# Deprecated in 3.10, undeprecated in 3.11.1
521515
asyncio.set_event_loop(self.loop)
522516
self.addCleanup(asyncio.set_event_loop, None)
523517
def run(arg):
524518
return (arg, threading.get_ident())
525519
ex = concurrent.futures.ThreadPoolExecutor(1)
526520
f1 = ex.submit(run, 'oi')
527-
with self.assertWarns(DeprecationWarning) as cm:
528-
f2 = asyncio.wrap_future(f1)
529-
self.assertEqual(cm.filename, __file__)
521+
f2 = asyncio.wrap_future(f1)
530522
self.assertIs(self.loop, f2._loop)
531523
ex.shutdown(wait=True)
532524

Lib/test/test_asyncio/test_streams.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -810,10 +810,8 @@ def test_read_all_from_pipe_reader(self):
810810
self.assertEqual(data, b'data')
811811

812812
def test_streamreader_constructor_without_loop(self):
813-
with self.assertWarns(DeprecationWarning) as cm:
814-
with self.assertRaisesRegex(RuntimeError, 'There is no current event loop'):
815-
asyncio.StreamReader()
816-
self.assertEqual(cm.filename, __file__)
813+
with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
814+
asyncio.StreamReader()
817815

818816
def test_streamreader_constructor_use_running_loop(self):
819817
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
@@ -827,21 +825,17 @@ async def test():
827825
def test_streamreader_constructor_use_global_loop(self):
828826
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
829827
# retrieves the current loop if the loop parameter is not set
830-
# Deprecated in 3.10
828+
# Deprecated in 3.10, undeprecated in 3.11.1
831829
self.addCleanup(asyncio.set_event_loop, None)
832830
asyncio.set_event_loop(self.loop)
833-
with self.assertWarns(DeprecationWarning) as cm:
834-
reader = asyncio.StreamReader()
835-
self.assertEqual(cm.filename, __file__)
831+
reader = asyncio.StreamReader()
836832
self.assertIs(reader._loop, self.loop)
837833

838834

839835
def test_streamreaderprotocol_constructor_without_loop(self):
840836
reader = mock.Mock()
841-
with self.assertWarns(DeprecationWarning) as cm:
842-
with self.assertRaisesRegex(RuntimeError, 'There is no current event loop'):
843-
asyncio.StreamReaderProtocol(reader)
844-
self.assertEqual(cm.filename, __file__)
837+
with self.assertRaisesRegex(RuntimeError, 'no current event loop'):
838+
asyncio.StreamReaderProtocol(reader)
845839

846840
def test_streamreaderprotocol_constructor_use_running_loop(self):
847841
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
@@ -855,13 +849,11 @@ async def test():
855849
def test_streamreaderprotocol_constructor_use_global_loop(self):
856850
# asyncio issue #184: Ensure that StreamReaderProtocol constructor
857851
# retrieves the current loop if the loop parameter is not set
858-
# Deprecated in 3.10
852+
# Deprecated in 3.10, undeprecated in 3.11.1
859853
self.addCleanup(asyncio.set_event_loop, None)
860854
asyncio.set_event_loop(self.loop)
861855
reader = mock.Mock()
862-
with self.assertWarns(DeprecationWarning) as cm:
863-
protocol = asyncio.StreamReaderProtocol(reader)
864-
self.assertEqual(cm.filename, __file__)
856+
protocol = asyncio.StreamReaderProtocol(reader)
865857
self.assertIs(protocol._loop, self.loop)
866858

867859
def test_multiple_drain(self):

0 commit comments

Comments
 (0)