Skip to content

Commit 5ee9df2

Browse files
Create a new event loop in Application.run(), if get_event_loop() raises RuntimeError.
1 parent c54ca73 commit 5ee9df2

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

prompt_toolkit/application/application.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
Task,
1212
ensure_future,
1313
get_event_loop,
14+
new_event_loop,
15+
set_event_loop,
1416
sleep,
1517
)
1618
from subprocess import Popen
@@ -785,13 +787,30 @@ def run(
785787
"""
786788
A blocking 'run' call that waits until the UI is finished.
787789
790+
This will start the current asyncio event loop. If no loop is set for
791+
the current thread, then it will create a new loop.
792+
788793
:param pre_run: Optional callable, which is called right after the
789794
"reset" of the application.
790795
:param set_exception_handler: When set, in case of an exception, go out
791796
of the alternate screen and hide the application, display the
792797
exception, and wait for the user to press ENTER.
793798
"""
794-
return get_event_loop().run_until_complete(self.run_async(pre_run=pre_run))
799+
# We don't create a new event loop by default, because we want to be
800+
# sure that when this is called multiple times, each call of `run()`
801+
# goes through the same event loop. This way, users can schedule
802+
# background-tasks that keep running across multiple prompts.
803+
try:
804+
loop = get_event_loop()
805+
except RuntimeError:
806+
# Possibly we are not running in the main thread, where no event
807+
# loop is set by default. Or somebody called `asyncio.run()`
808+
# before, which closes the existing event loop. We can create a new
809+
# loop.
810+
loop = new_event_loop()
811+
set_event_loop(loop)
812+
813+
return loop.run_until_complete(self.run_async(pre_run=pre_run))
795814

796815
def _handle_exception(self, loop, context: Dict[str, Any]) -> None:
797816
"""

0 commit comments

Comments
 (0)