diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index d85a3269215272..21ca5c5f62ae83 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -146,6 +146,7 @@ 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( diff --git a/Lib/asyncio/tools.py b/Lib/asyncio/tools.py index dde755e3796bbb..bf1cb5e64cbfbe 100644 --- a/Lib/asyncio/tools.py +++ b/Lib/asyncio/tools.py @@ -21,13 +21,21 @@ class CycleFoundException(Exception): # ─── indexing helpers ─────────────────────────────────────────── +def _format_stack_entry(elem: tuple[str, str, int] | str) -> str: + if isinstance(elem, tuple): + fqname, path, line_no = elem + return f"{fqname} {path}:{line_no}" + + return elem + + def _index(result): id2name, awaits = {}, [] for _thr_id, tasks in result: for tid, tname, awaited in tasks: id2name[tid] = tname for stack, parent_id in awaited: - stack = [elem[0] if isinstance(elem, tuple) else elem for elem in stack] + stack = [_format_stack_entry(elem) for elem in stack] awaits.append((parent_id, stack, tid)) return id2name, awaits @@ -106,7 +114,7 @@ def dfs(v): # ─── PRINT TREE FUNCTION ─────────────────────────────────────── def build_async_tree(result, task_emoji="(T)", cor_emoji=""): """ - Build a list of strings for pretty-print a async call tree. + Build a list of strings for pretty-print an async call tree. The call tree is produced by `get_all_async_stacks()`, prefixing tasks with `task_emoji` and coroutine frames with `cor_emoji`. @@ -169,7 +177,7 @@ def build_task_table(result): return table def _print_cycle_exception(exception: CycleFoundException): - print("ERROR: await-graph contains cycles – cannot print a tree!", file=sys.stderr) + print("ERROR: await-graph contains cycles - cannot print a tree!", file=sys.stderr) print("", file=sys.stderr) for c in exception.cycles: inames = " → ".join(exception.id2name.get(tid, hex(tid)) for tid in c) diff --git a/Lib/test/test_asyncio/test_tools.py b/Lib/test/test_asyncio/test_tools.py index 2caf56172c9193..0413e236c27dfa 100644 --- a/Lib/test/test_asyncio/test_tools.py +++ b/Lib/test/test_asyncio/test_tools.py @@ -18,10 +18,18 @@ 3, "timer", [ - [["awaiter3", "awaiter2", "awaiter"], 4], - [["awaiter1_3", "awaiter1_2", "awaiter1"], 5], - [["awaiter1_3", "awaiter1_2", "awaiter1"], 6], - [["awaiter3", "awaiter2", "awaiter"], 7], + [[("awaiter3", "/path/to/app.py", 130), + ("awaiter2", "/path/to/app.py", 120), + ("awaiter", "/path/to/app.py", 110)], 4], + [[("awaiterB3", "/path/to/app.py", 190), + ("awaiterB2", "/path/to/app.py", 180), + ("awaiterB", "/path/to/app.py", 170)], 5], + [[("awaiterB3", "/path/to/app.py", 190), + ("awaiterB2", "/path/to/app.py", 180), + ("awaiterB", "/path/to/app.py", 170)], 6], + [[("awaiter3", "/path/to/app.py", 130), + ("awaiter2", "/path/to/app.py", 120), + ("awaiter", "/path/to/app.py", 110)], 7], ], ), ( @@ -91,14 +99,14 @@ " │ └── __aexit__", " │ └── _aexit", " │ ├── (T) child1_1", - " │ │ └── awaiter", - " │ │ └── awaiter2", - " │ │ └── awaiter3", + " │ │ └── awaiter /path/to/app.py:110", + " │ │ └── awaiter2 /path/to/app.py:120", + " │ │ └── awaiter3 /path/to/app.py:130", " │ │ └── (T) timer", " │ └── (T) child2_1", - " │ └── awaiter1", - " │ └── awaiter1_2", - " │ └── awaiter1_3", + " │ └── awaiterB /path/to/app.py:170", + " │ └── awaiterB2 /path/to/app.py:180", + " │ └── awaiterB3 /path/to/app.py:190", " │ └── (T) timer", " └── (T) root2", " └── bloch", @@ -106,14 +114,14 @@ " └── __aexit__", " └── _aexit", " ├── (T) child1_2", - " │ └── awaiter", - " │ └── awaiter2", - " │ └── awaiter3", + " │ └── awaiter /path/to/app.py:110", + " │ └── awaiter2 /path/to/app.py:120", + " │ └── awaiter3 /path/to/app.py:130", " │ └── (T) timer", " └── (T) child2_2", - " └── awaiter1", - " └── awaiter1_2", - " └── awaiter1_3", + " └── awaiterB /path/to/app.py:170", + " └── awaiterB2 /path/to/app.py:180", + " └── awaiterB3 /path/to/app.py:190", " └── (T) timer", ] ] @@ -589,7 +597,6 @@ class TestAsyncioToolsTree(unittest.TestCase): - def test_asyncio_utils(self): for input_, tree in TEST_INPUTS_TREE: with self.subTest(input_):