##// END OF EJS Templates
Merge pull request #12001 from jonathanslenders/asyncio-inputhook-fix...
Matthias Bussonnier -
r25323:8e34b1a3 merge
parent child Browse files
Show More
@@ -449,22 +449,28 b' class TerminalInteractiveShell(InteractiveShell):'
449 449 else:
450 450 default = ''
451 451
452 with patch_stdout(raw=True):
453 # In order to make sure that asyncio code written in the
454 # interactive shell doesn't interfere with the prompt, we run the
455 # prompt in a different event loop.
456 # If we don't do this, people could spawn coroutine with a
457 # while/true inside which will freeze the prompt.
452 # In order to make sure that asyncio code written in the
453 # interactive shell doesn't interfere with the prompt, we run the
454 # prompt in a different event loop.
455 # If we don't do this, people could spawn coroutine with a
456 # while/true inside which will freeze the prompt.
458 457
458 try:
459 459 old_loop = asyncio.get_event_loop()
460 asyncio.set_event_loop(self.pt_loop)
461 try:
460 except RuntimeError:
461 # This happens when the user used `asyncio.run()`.
462 old_loop = None
463
464 asyncio.set_event_loop(self.pt_loop)
465 try:
466 with patch_stdout(raw=True):
462 467 text = self.pt_app.prompt(
463 468 default=default,
464 469 **self._extra_prompt_options())
465 finally:
466 # Restore the original event loop.
467 asyncio.set_event_loop(old_loop)
470 finally:
471 # Restore the original event loop.
472 asyncio.set_event_loop(old_loop)
473
468 474 return text
469 475
470 476 def enable_win_unicode_console(self):
@@ -580,11 +586,22 b' class TerminalInteractiveShell(InteractiveShell):'
580 586 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
581 587 # this inputhook.
582 588 if PTK3:
583 if self._inputhook:
584 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
589 import asyncio
590 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
591
592 if gui == 'asyncio':
593 # When we integrate the asyncio event loop, run the UI in the
594 # same event loop as the rest of the code. don't use an actual
595 # input hook. (Asyncio is not made for nesting event loops.)
596 self.pt_loop = asyncio.get_event_loop()
597
598 elif self._inputhook:
599 # If an inputhook was set, create a new asyncio event loop with
600 # this inputhook for the prompt.
585 601 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
586 602 else:
587 import asyncio
603 # When there's no inputhook, run the prompt in a separate
604 # asyncio event loop.
588 605 self.pt_loop = asyncio.new_event_loop()
589 606
590 607 # Run !system commands directly, not through pipes, so terminal programs
@@ -28,6 +28,10 b' prompt_toolkit`s `patch_stdout`)::'
28 28
29 29 """
30 30 import asyncio
31 from prompt_toolkit import __version__ as ptk_version
32
33 PTK3 = ptk_version.startswith('3.')
34
31 35
32 36 # Keep reference to the original asyncio loop, because getting the event loop
33 37 # within the input hook would return the other loop.
@@ -35,6 +39,19 b' loop = asyncio.get_event_loop()'
35 39
36 40
37 41 def inputhook(context):
42 """
43 Inputhook for asyncio event loop integration.
44 """
45 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
46 # The event loop integration here is implemented in `interactiveshell.py`
47 # by running the prompt itself in the current asyncio loop. The main reason
48 # for this is that nesting asyncio event loops is unreliable.
49 if PTK3:
50 return
51
52 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
53 # because prompt_toolkit 2.0 uses a different event loop internally.
54
38 55 def stop():
39 56 loop.stop()
40 57
@@ -44,3 +61,4 b' def inputhook(context):'
44 61 loop.run_forever()
45 62 finally:
46 63 loop.remove_reader(fileno)
64
General Comments 0
You need to be logged in to leave comments. Login now