Skip to content

Commit 60cdd80

Browse files
authored
pythongh-91048: Add filename:line_no information to asyncio pstree (python#133478)
1 parent cae660d commit 60cdd80

File tree

3 files changed

+36
-20
lines changed

3 files changed

+36
-20
lines changed

Lib/asyncio/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ def interrupt(self) -> None:
146146
parser = argparse.ArgumentParser(
147147
prog="python3 -m asyncio",
148148
description="Interactive asyncio shell and CLI tools",
149+
color=True,
149150
)
150151
subparsers = parser.add_subparsers(help="sub-commands", dest="command")
151152
ps = subparsers.add_parser(

Lib/asyncio/tools.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,21 @@ class CycleFoundException(Exception):
2121

2222

2323
# ─── indexing helpers ───────────────────────────────────────────
24+
def _format_stack_entry(elem: tuple[str, str, int] | str) -> str:
25+
if isinstance(elem, tuple):
26+
fqname, path, line_no = elem
27+
return f"{fqname} {path}:{line_no}"
28+
29+
return elem
30+
31+
2432
def _index(result):
2533
id2name, awaits = {}, []
2634
for _thr_id, tasks in result:
2735
for tid, tname, awaited in tasks:
2836
id2name[tid] = tname
2937
for stack, parent_id in awaited:
30-
stack = [elem[0] if isinstance(elem, tuple) else elem for elem in stack]
38+
stack = [_format_stack_entry(elem) for elem in stack]
3139
awaits.append((parent_id, stack, tid))
3240
return id2name, awaits
3341

@@ -106,7 +114,7 @@ def dfs(v):
106114
# ─── PRINT TREE FUNCTION ───────────────────────────────────────
107115
def build_async_tree(result, task_emoji="(T)", cor_emoji=""):
108116
"""
109-
Build a list of strings for pretty-print a async call tree.
117+
Build a list of strings for pretty-print an async call tree.
110118
111119
The call tree is produced by `get_all_async_stacks()`, prefixing tasks
112120
with `task_emoji` and coroutine frames with `cor_emoji`.
@@ -169,7 +177,7 @@ def build_task_table(result):
169177
return table
170178

171179
def _print_cycle_exception(exception: CycleFoundException):
172-
print("ERROR: await-graph contains cycles cannot print a tree!", file=sys.stderr)
180+
print("ERROR: await-graph contains cycles - cannot print a tree!", file=sys.stderr)
173181
print("", file=sys.stderr)
174182
for c in exception.cycles:
175183
inames = " → ".join(exception.id2name.get(tid, hex(tid)) for tid in c)

Lib/test/test_asyncio/test_tools.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,18 @@
1818
3,
1919
"timer",
2020
[
21-
[["awaiter3", "awaiter2", "awaiter"], 4],
22-
[["awaiter1_3", "awaiter1_2", "awaiter1"], 5],
23-
[["awaiter1_3", "awaiter1_2", "awaiter1"], 6],
24-
[["awaiter3", "awaiter2", "awaiter"], 7],
21+
[[("awaiter3", "/path/to/app.py", 130),
22+
("awaiter2", "/path/to/app.py", 120),
23+
("awaiter", "/path/to/app.py", 110)], 4],
24+
[[("awaiterB3", "/path/to/app.py", 190),
25+
("awaiterB2", "/path/to/app.py", 180),
26+
("awaiterB", "/path/to/app.py", 170)], 5],
27+
[[("awaiterB3", "/path/to/app.py", 190),
28+
("awaiterB2", "/path/to/app.py", 180),
29+
("awaiterB", "/path/to/app.py", 170)], 6],
30+
[[("awaiter3", "/path/to/app.py", 130),
31+
("awaiter2", "/path/to/app.py", 120),
32+
("awaiter", "/path/to/app.py", 110)], 7],
2533
],
2634
),
2735
(
@@ -91,29 +99,29 @@
9199
" │ └── __aexit__",
92100
" │ └── _aexit",
93101
" │ ├── (T) child1_1",
94-
" │ │ └── awaiter",
95-
" │ │ └── awaiter2",
96-
" │ │ └── awaiter3",
102+
" │ │ └── awaiter /path/to/app.py:110",
103+
" │ │ └── awaiter2 /path/to/app.py:120",
104+
" │ │ └── awaiter3 /path/to/app.py:130",
97105
" │ │ └── (T) timer",
98106
" │ └── (T) child2_1",
99-
" │ └── awaiter1",
100-
" │ └── awaiter1_2",
101-
" │ └── awaiter1_3",
107+
" │ └── awaiterB /path/to/app.py:170",
108+
" │ └── awaiterB2 /path/to/app.py:180",
109+
" │ └── awaiterB3 /path/to/app.py:190",
102110
" │ └── (T) timer",
103111
" └── (T) root2",
104112
" └── bloch",
105113
" └── blocho_caller",
106114
" └── __aexit__",
107115
" └── _aexit",
108116
" ├── (T) child1_2",
109-
" │ └── awaiter",
110-
" │ └── awaiter2",
111-
" │ └── awaiter3",
117+
" │ └── awaiter /path/to/app.py:110",
118+
" │ └── awaiter2 /path/to/app.py:120",
119+
" │ └── awaiter3 /path/to/app.py:130",
112120
" │ └── (T) timer",
113121
" └── (T) child2_2",
114-
" └── awaiter1",
115-
" └── awaiter1_2",
116-
" └── awaiter1_3",
122+
" └── awaiterB /path/to/app.py:170",
123+
" └── awaiterB2 /path/to/app.py:180",
124+
" └── awaiterB3 /path/to/app.py:190",
117125
" └── (T) timer",
118126
]
119127
]
@@ -589,7 +597,6 @@
589597

590598

591599
class TestAsyncioToolsTree(unittest.TestCase):
592-
593600
def test_asyncio_utils(self):
594601
for input_, tree in TEST_INPUTS_TREE:
595602
with self.subTest(input_):

0 commit comments

Comments
 (0)