diff options
author | Ćukasz Langa <lukasz@langa.pl> | 2024-05-31 20:26:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-31 20:26:02 (GMT) |
commit | 2237946af0981c46dc7d3886477e425ccfb37f28 (patch) | |
tree | 55317ee5d19a7bcba247052de2d0de660ebcb724 /Lib/_pyrepl | |
parent | f9d47fed9fbbe9313404838050f6dfe1c7fe6340 (diff) | |
download | cpython-2237946af0981c46dc7d3886477e425ccfb37f28.zip cpython-2237946af0981c46dc7d3886477e425ccfb37f28.tar.gz cpython-2237946af0981c46dc7d3886477e425ccfb37f28.tar.bz2 |
gh-118894: Make asyncio REPL use pyrepl (GH-119433)
Diffstat (limited to 'Lib/_pyrepl')
-rw-r--r-- | Lib/_pyrepl/commands.py | 5 | ||||
-rw-r--r-- | Lib/_pyrepl/console.py | 57 | ||||
-rw-r--r-- | Lib/_pyrepl/reader.py | 1 | ||||
-rw-r--r-- | Lib/_pyrepl/simple_interact.py | 53 |
4 files changed, 70 insertions, 46 deletions
diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py index ed977f8..2ef5dad 100644 --- a/Lib/_pyrepl/commands.py +++ b/Lib/_pyrepl/commands.py @@ -219,6 +219,11 @@ class interrupt(FinishCommand): os.kill(os.getpid(), signal.SIGINT) +class ctrl_c(Command): + def do(self) -> None: + raise KeyboardInterrupt + + class suspend(Command): def do(self) -> None: import signal diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py index fcabf78..aa0bde8 100644 --- a/Lib/_pyrepl/console.py +++ b/Lib/_pyrepl/console.py @@ -19,10 +19,14 @@ from __future__ import annotations -import sys +import _colorize # type: ignore[import-not-found] from abc import ABC, abstractmethod +import ast +import code from dataclasses import dataclass, field +import os.path +import sys TYPE_CHECKING = False @@ -136,3 +140,54 @@ class Console(ABC): @abstractmethod def repaint(self) -> None: ... + + +class InteractiveColoredConsole(code.InteractiveConsole): + def __init__( + self, + locals: dict[str, object] | None = None, + filename: str = "<console>", + *, + local_exit: bool = False, + ) -> None: + super().__init__(locals=locals, filename=filename, local_exit=local_exit) # type: ignore[call-arg] + self.can_colorize = _colorize.can_colorize() + + def showsyntaxerror(self, filename=None): + super().showsyntaxerror(colorize=self.can_colorize) + + def showtraceback(self): + super().showtraceback(colorize=self.can_colorize) + + def runsource(self, source, filename="<input>", symbol="single"): + try: + tree = ast.parse(source) + except (SyntaxError, OverflowError, ValueError): + self.showsyntaxerror(filename) + return False + if tree.body: + *_, last_stmt = tree.body + for stmt in tree.body: + wrapper = ast.Interactive if stmt is last_stmt else ast.Module + the_symbol = symbol if stmt is last_stmt else "exec" + item = wrapper([stmt]) + try: + code = self.compile.compiler(item, filename, the_symbol, dont_inherit=True) + except SyntaxError as e: + if e.args[0] == "'await' outside function": + python = os.path.basename(sys.executable) + e.add_note( + f"Try the asyncio REPL ({python} -m asyncio) to use" + f" top-level 'await' and run background asyncio tasks." + ) + self.showsyntaxerror(filename) + return False + except (OverflowError, ValueError): + self.showsyntaxerror(filename) + return False + + if code is None: + return True + + self.runcode(code) + return False diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py index 0045425..5401ae7 100644 --- a/Lib/_pyrepl/reader.py +++ b/Lib/_pyrepl/reader.py @@ -131,6 +131,7 @@ default_keymap: tuple[tuple[KeySpec, CommandName], ...] = tuple( ("\\\\", "self-insert"), (r"\x1b[200~", "enable_bracketed_paste"), (r"\x1b[201~", "disable_bracketed_paste"), + (r"\x03", "ctrl-c"), ] + [(c, "self-insert") for c in map(chr, range(32, 127)) if c != "\\"] + [(c, "self-insert") for c in map(chr, range(128, 256)) if c.isalpha()] diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py index c624f6e..256bbc7 100644 --- a/Lib/_pyrepl/simple_interact.py +++ b/Lib/_pyrepl/simple_interact.py @@ -25,14 +25,13 @@ allowing multiline input and multiline history entries. from __future__ import annotations -import _colorize # type: ignore[import-not-found] import _sitebuiltins import linecache import sys import code -import ast from types import ModuleType +from .console import InteractiveColoredConsole from .readline import _get_reader, multiline_input _error: tuple[type[Exception], ...] | type[Exception] @@ -74,57 +73,21 @@ REPL_COMMANDS = { "clear": _clear_screen, } -class InteractiveColoredConsole(code.InteractiveConsole): - def __init__( - self, - locals: dict[str, object] | None = None, - filename: str = "<console>", - *, - local_exit: bool = False, - ) -> None: - super().__init__(locals=locals, filename=filename, local_exit=local_exit) # type: ignore[call-arg] - self.can_colorize = _colorize.can_colorize() - - def showsyntaxerror(self, filename=None): - super().showsyntaxerror(colorize=self.can_colorize) - - def showtraceback(self): - super().showtraceback(colorize=self.can_colorize) - - def runsource(self, source, filename="<input>", symbol="single"): - try: - tree = ast.parse(source) - except (OverflowError, SyntaxError, ValueError): - self.showsyntaxerror(filename) - return False - if tree.body: - *_, last_stmt = tree.body - for stmt in tree.body: - wrapper = ast.Interactive if stmt is last_stmt else ast.Module - the_symbol = symbol if stmt is last_stmt else "exec" - item = wrapper([stmt]) - try: - code = compile(item, filename, the_symbol, dont_inherit=True) - except (OverflowError, ValueError, SyntaxError): - self.showsyntaxerror(filename) - return False - - if code is None: - return True - - self.runcode(code) - return False - def run_multiline_interactive_console( - mainmodule: ModuleType | None= None, future_flags: int = 0 + mainmodule: ModuleType | None = None, + future_flags: int = 0, + console: code.InteractiveConsole | None = None, ) -> None: import __main__ from .readline import _setup _setup() mainmodule = mainmodule or __main__ - console = InteractiveColoredConsole(mainmodule.__dict__, filename="<stdin>") + if console is None: + console = InteractiveColoredConsole( + mainmodule.__dict__, filename="<stdin>" + ) if future_flags: console.compile.compiler.flags |= future_flags |