|
11 | 11 | Task,
|
12 | 12 | ensure_future,
|
13 | 13 | get_event_loop,
|
| 14 | + new_event_loop, |
| 15 | + set_event_loop, |
14 | 16 | sleep,
|
15 | 17 | )
|
16 | 18 | from subprocess import Popen
|
@@ -785,13 +787,30 @@ def run(
|
785 | 787 | """
|
786 | 788 | A blocking 'run' call that waits until the UI is finished.
|
787 | 789 |
|
| 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 | +
|
788 | 793 | :param pre_run: Optional callable, which is called right after the
|
789 | 794 | "reset" of the application.
|
790 | 795 | :param set_exception_handler: When set, in case of an exception, go out
|
791 | 796 | of the alternate screen and hide the application, display the
|
792 | 797 | exception, and wait for the user to press ENTER.
|
793 | 798 | """
|
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)) |
795 | 814 |
|
796 | 815 | def _handle_exception(self, loop, context: Dict[str, Any]) -> None:
|
797 | 816 | """
|
|
0 commit comments