##// 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 else:
449 else:
450 default = ''
450 default = ''
451
451
452 with patch_stdout(raw=True):
452 # In order to make sure that asyncio code written in the
453 # In order to make sure that asyncio code written in the
453 # interactive shell doesn't interfere with the prompt, we run the
454 # interactive shell doesn't interfere with the prompt, we run the
454 # prompt in a different event loop.
455 # prompt in a different event loop.
455 # If we don't do this, people could spawn coroutine with a
456 # If we don't do this, people could spawn coroutine with a
456 # while/true inside which will freeze the prompt.
457 # while/true inside which will freeze the prompt.
458
457
458 try:
459 old_loop = asyncio.get_event_loop()
459 old_loop = asyncio.get_event_loop()
460 asyncio.set_event_loop(self.pt_loop)
460 except RuntimeError:
461 try:
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 text = self.pt_app.prompt(
467 text = self.pt_app.prompt(
463 default=default,
468 default=default,
464 **self._extra_prompt_options())
469 **self._extra_prompt_options())
465 finally:
470 finally:
466 # Restore the original event loop.
471 # Restore the original event loop.
467 asyncio.set_event_loop(old_loop)
472 asyncio.set_event_loop(old_loop)
473
468 return text
474 return text
469
475
470 def enable_win_unicode_console(self):
476 def enable_win_unicode_console(self):
@@ -580,11 +586,22 b' class TerminalInteractiveShell(InteractiveShell):'
580 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
586 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
581 # this inputhook.
587 # this inputhook.
582 if PTK3:
588 if PTK3:
583 if self._inputhook:
589 import asyncio
584 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
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 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
601 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
586 else:
602 else:
587 import asyncio
603 # When there's no inputhook, run the prompt in a separate
604 # asyncio event loop.
588 self.pt_loop = asyncio.new_event_loop()
605 self.pt_loop = asyncio.new_event_loop()
589
606
590 # Run !system commands directly, not through pipes, so terminal programs
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 import asyncio
30 import asyncio
31 from prompt_toolkit import __version__ as ptk_version
32
33 PTK3 = ptk_version.startswith('3.')
34
31
35
32 # Keep reference to the original asyncio loop, because getting the event loop
36 # Keep reference to the original asyncio loop, because getting the event loop
33 # within the input hook would return the other loop.
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 def inputhook(context):
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 def stop():
55 def stop():
39 loop.stop()
56 loop.stop()
40
57
@@ -44,3 +61,4 b' def inputhook(context):'
44 loop.run_forever()
61 loop.run_forever()
45 finally:
62 finally:
46 loop.remove_reader(fileno)
63 loop.remove_reader(fileno)
64
General Comments 0
You need to be logged in to leave comments. Login now