Repository navigation
Sync canonical stdlib modules and offline stack formatting #9315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,13 +12,16 @@ | |
| import types | ||
| import warnings | ||
|
|
||
| from _colorize import get_theme | ||
| from _pyrepl.console import InteractiveColoredConsole | ||
| try: | ||
| from _colorize import get_theme | ||
| from _pyrepl.console import InteractiveColoredConsole as InteractiveConsole | ||
| except ModuleNotFoundError: | ||
| from code import InteractiveConsole | ||
|
|
||
| from . import futures | ||
|
|
||
|
|
||
| class AsyncIOInteractiveConsole(InteractiveColoredConsole): | ||
| class AsyncIOInteractiveConsole(InteractiveConsole): | ||
|
|
||
| def __init__(self, locals, loop): | ||
| super().__init__(locals, filename="<stdin>") | ||
|
|
@@ -96,7 +99,7 @@ def run(self): | |
|
|
||
| console.write(banner) | ||
|
|
||
| if not sys.flags.isolated and (startup_path := os.getenv("PYTHONSTARTUP")): | ||
| if not sys.flags.ignore_environment and (startup_path := os.getenv("PYTHONSTARTUP")): | ||
| sys.audit("cpython.run_startup", startup_path) | ||
| try: | ||
| import tokenize | ||
|
|
@@ -112,13 +115,17 @@ def run(self): | |
| if CAN_USE_PYREPL: | ||
| theme = get_theme().syntax | ||
| ps1 = f"{theme.prompt}{ps1}{theme.reset}" | ||
| console.write(f"{ps1}import asyncio\n") | ||
| import_line = f'{theme.keyword}import{theme.reset} asyncio' | ||
| else: | ||
| import_line = "import asyncio" | ||
| console.write(f"{ps1}{import_line}\n") | ||
|
|
||
| if CAN_USE_PYREPL: | ||
| from _pyrepl.simple_interact import ( | ||
| run_multiline_interactive_console, | ||
| ) | ||
| try: | ||
| sys.ps1 = ps1 | ||
| run_multiline_interactive_console(console) | ||
| except SystemExit: | ||
| # expected via the `exit` and `quit` commands | ||
|
|
@@ -152,24 +159,35 @@ def interrupt(self) -> None: | |
| parser = argparse.ArgumentParser( | ||
| prog="python3 -m asyncio", | ||
| description="Interactive asyncio shell and CLI tools", | ||
| color=True, | ||
| ) | ||
| subparsers = parser.add_subparsers(help="sub-commands", dest="command") | ||
| ps = subparsers.add_parser( | ||
| "ps", help="Display a table of all pending tasks in a process" | ||
| ) | ||
| ps.add_argument("pid", type=int, help="Process ID to inspect") | ||
| ps.add_argument( | ||
| "--retries", | ||
| type=int, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When either new Useful? React with 👍 / 👎. |
||
| default=3, | ||
| help="Number of retries on transient attach errors", | ||
| ) | ||
| pstree = subparsers.add_parser( | ||
| "pstree", help="Display a tree of all pending tasks in a process" | ||
| ) | ||
| pstree.add_argument("pid", type=int, help="Process ID to inspect") | ||
| pstree.add_argument( | ||
| "--retries", | ||
| type=int, | ||
| default=3, | ||
| help="Number of retries on transient attach errors", | ||
| ) | ||
| args = parser.parse_args() | ||
| match args.command: | ||
| case "ps": | ||
| asyncio.tools.display_awaited_by_tasks_table(args.pid) | ||
| asyncio.tools.display_awaited_by_tasks_table(args.pid, retries=args.retries) | ||
| sys.exit(0) | ||
| case "pstree": | ||
| asyncio.tools.display_awaited_by_tasks_tree(args.pid) | ||
| asyncio.tools.display_awaited_by_tasks_tree(args.pid, retries=args.retries) | ||
| sys.exit(0) | ||
| case None: | ||
| pass # continue to the interactive shell | ||
|
|
@@ -182,20 +200,26 @@ def interrupt(self) -> None: | |
|
|
||
| sys.audit("cpython.run_stdin") | ||
|
|
||
| if os.getenv('PYTHON_BASIC_REPL'): | ||
| if not sys.flags.ignore_environment and os.getenv('PYTHON_BASIC_REPL'): | ||
| CAN_USE_PYREPL = False | ||
| else: | ||
| from _pyrepl.main import CAN_USE_PYREPL | ||
| try: | ||
| from _pyrepl.main import CAN_USE_PYREPL | ||
| except ModuleNotFoundError: | ||
| CAN_USE_PYREPL = False | ||
|
|
||
| return_code = 0 | ||
| loop = asyncio.new_event_loop() | ||
| asyncio.set_event_loop(loop) | ||
|
|
||
| repl_locals = {'asyncio': asyncio} | ||
| for key in {'__name__', '__package__', | ||
| '__loader__', '__spec__', | ||
| '__builtins__', '__file__'}: | ||
| repl_locals[key] = locals()[key] | ||
| repl_locals = { | ||
| 'asyncio': asyncio, | ||
| '__name__': __name__, | ||
| '__package__': None, | ||
| '__loader__': __loader__, | ||
| '__spec__': None, | ||
| '__builtins__': __builtins__, | ||
| } | ||
|
|
||
| console = AsyncIOInteractiveConsole(repl_locals, loop) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
_pyrepl.consoleis unavailable and this fallback is selected, any evaluated statement that raises reachesAsyncIOInteractiveConsole.runcode(), which returnsself.STATEMENT_FAILED;code.InteractiveConsoledoes not define that attribute (it exists only onInteractiveColoredConsole). The resultingAttributeErrorescapes the basic console'sinteract()loop andREPLThreadstops the event loop, so the first normal user error terminates the fallback REPL. Define the sentinel onAsyncIOInteractiveConsoleor avoid returning it on this path.Useful? React with 👍 / 👎.