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

Skip to content

Commit e343cd4

Browse files
authored
Merge pull request #13349 from minrk/policy_get_event_loop
get_running_loop is only valid in coroutines
2 parents 9c54f3e + 0fbbb2b commit e343cd4

5 files changed

Lines changed: 64 additions & 12 deletions

File tree

IPython/core/async_helpers.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,28 @@
1212

1313

1414
import ast
15+
import asyncio
1516
import inspect
1617

1718

1819
class _AsyncIORunner:
20+
def __init__(self):
21+
self._loop = None
22+
23+
@property
24+
def loop(self):
25+
"""Always returns a non-closed event loop"""
26+
if self._loop is None or self._loop.is_closed():
27+
policy = asyncio.get_event_loop_policy()
28+
self._loop = policy.new_event_loop()
29+
policy.set_event_loop(self._loop)
30+
return self._loop
31+
1932
def __call__(self, coro):
2033
"""
2134
Handler for asyncio autoawait
2235
"""
23-
import asyncio
24-
25-
return asyncio.get_event_loop_policy().get_event_loop().run_until_complete(coro)
36+
return self.loop.run_until_complete(coro)
2637

2738
def __str__(self):
2839
return "asyncio"

IPython/core/magics/script.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ def safe_watcher():
8181
yield
8282
return
8383

84-
loop = policy.get_event_loop()
84+
try:
85+
loop = policy.get_event_loop()
86+
if loop.is_closed():
87+
raise RuntimeError("open a new one")
88+
except RuntimeError:
89+
# closed loop, make a new one
90+
loop = policy.new_event_loop()
91+
policy.set_event_loop(loop)
92+
8593
try:
8694
watcher = asyncio.SafeChildWatcher()
8795
watcher.attach_loop(loop)
@@ -236,9 +244,19 @@ async def _stream_communicate(process, cell):
236244
await asyncio.wait([stdout_task, stderr_task])
237245
await process.wait()
238246

239-
if sys.platform.startswith("win"):
240-
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
241-
loop = asyncio.get_event_loop_policy().get_event_loop()
247+
policy = asyncio.get_event_loop_policy()
248+
if sys.platform.startswith("win") and not isinstance(
249+
policy, asyncio.WindowsProactorEventLoopPolicy
250+
):
251+
# _do not_ overwrite the current policy
252+
policy = asyncio.WindowsProactorEventLoopPolicy()
253+
254+
try:
255+
loop = policy.get_event_loop()
256+
except RuntimeError:
257+
# closed loop, make a new one
258+
loop = policy.new_event_loop()
259+
policy.set_event_loop(loop)
242260
argv = arg_split(line, posix=not sys.platform.startswith("win"))
243261
args, cmd = self.shebang.parser.parse_known_args(argv)
244262
try:

IPython/core/tests/test_interactiveshell.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,22 @@ def test_run_cell_async():
10581058
assert result.result == 5
10591059

10601060

1061+
def test_run_cell_await():
1062+
ip.run_cell("import asyncio")
1063+
result = ip.run_cell("await asyncio.sleep(0.01); 10")
1064+
assert ip.user_ns["_"] == 10
1065+
1066+
1067+
def test_run_cell_asyncio_run():
1068+
ip.run_cell("import asyncio")
1069+
result = ip.run_cell("await asyncio.sleep(0.01); 1")
1070+
assert ip.user_ns["_"] == 1
1071+
result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1072+
assert ip.user_ns["_"] == 2
1073+
result = ip.run_cell("await asyncio.sleep(0.01); 3")
1074+
assert ip.user_ns["_"] == 3
1075+
1076+
10611077
def test_should_run_async():
10621078
assert not ip.should_run_async("a = 5")
10631079
assert ip.should_run_async("await x")

IPython/core/tests/test_magic.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,11 @@ def test_script_config():
970970

971971
@pytest.fixture
972972
def event_loop():
973-
yield asyncio.get_event_loop_policy().get_event_loop()
973+
policy = asyncio.get_event_loop_policy()
974+
loop = policy.new_event_loop()
975+
policy.set_event_loop(loop)
976+
yield loop
977+
loop.close()
974978

975979

976980
@dec.skip_win32

IPython/terminal/interactiveshell.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,21 +504,24 @@ def prompt_for_code(self):
504504
# If we don't do this, people could spawn coroutine with a
505505
# while/true inside which will freeze the prompt.
506506

507+
policy = asyncio.get_event_loop_policy()
507508
try:
508-
old_loop = asyncio.get_running_loop()
509+
old_loop = policy.get_event_loop()
509510
except RuntimeError:
510-
# This happens when the user used `asyncio.run()`.
511+
# This happens when the the event loop is closed,
512+
# e.g. by calling `asyncio.run()`.
511513
old_loop = None
512514

513-
asyncio.set_event_loop(self.pt_loop)
515+
policy.set_event_loop(self.pt_loop)
514516
try:
515517
with patch_stdout(raw=True):
516518
text = self.pt_app.prompt(
517519
default=default,
518520
**self._extra_prompt_options())
519521
finally:
520522
# Restore the original event loop.
521-
asyncio.set_event_loop(old_loop)
523+
if old_loop is not None:
524+
policy.set_event_loop(old_loop)
522525

523526
return text
524527

0 commit comments

Comments
 (0)