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): |
|
|||
453 |
|
|
452 | # In order to make sure that asyncio code written in the | |
454 |
|
|
453 | # interactive shell doesn't interfere with the prompt, we run the | |
455 |
|
|
454 | # prompt in a different event loop. | |
456 |
|
|
455 | # If we don't do this, people could spawn coroutine with a | |
457 |
|
|
456 | # 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 | except RuntimeError: | |||
|
461 | # This happens when the user used `asyncio.run()`. | |||
|
462 | old_loop = None | |||
|
463 | ||||
460 |
|
|
464 | asyncio.set_event_loop(self.pt_loop) | |
461 |
|
|
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 |
|
|
470 | finally: | |
466 |
|
|
471 | # Restore the original event loop. | |
467 |
|
|
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 |
|
|
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