Skip to content

Commit 470cbe9

Browse files
dpdaniAA-Turner
andauthored
gh-134861: Add CSV output format to python -m asyncio ps (#134862)
Co-authored-by: Adam Turner <[email protected]>
1 parent 0953200 commit 470cbe9

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

Lib/asyncio/__main__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import argparse
22
import ast
33
import asyncio
4-
import asyncio.tools
54
import concurrent.futures
65
import contextvars
76
import inspect
@@ -11,6 +10,9 @@
1110
import threading
1211
import types
1312
import warnings
13+
from asyncio.tools import (TaskTableOutputFormat,
14+
display_awaited_by_tasks_table,
15+
display_awaited_by_tasks_tree)
1416

1517
from _colorize import get_theme
1618
from _pyrepl.console import InteractiveColoredConsole
@@ -153,17 +155,19 @@ def interrupt(self) -> None:
153155
"ps", help="Display a table of all pending tasks in a process"
154156
)
155157
ps.add_argument("pid", type=int, help="Process ID to inspect")
158+
formats = [fmt.value for fmt in TaskTableOutputFormat]
159+
ps.add_argument("--format", choices=formats, default="table")
156160
pstree = subparsers.add_parser(
157161
"pstree", help="Display a tree of all pending tasks in a process"
158162
)
159163
pstree.add_argument("pid", type=int, help="Process ID to inspect")
160164
args = parser.parse_args()
161165
match args.command:
162166
case "ps":
163-
asyncio.tools.display_awaited_by_tasks_table(args.pid)
167+
display_awaited_by_tasks_table(args.pid, format=args.format)
164168
sys.exit(0)
165169
case "pstree":
166-
asyncio.tools.display_awaited_by_tasks_tree(args.pid)
170+
display_awaited_by_tasks_tree(args.pid)
167171
sys.exit(0)
168172
case None:
169173
pass # continue to the interactive shell

Lib/asyncio/tools.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Tools to analyze tasks running in asyncio programs."""
22

3-
from collections import defaultdict, namedtuple
3+
from collections import defaultdict
4+
import csv
45
from itertools import count
5-
from enum import Enum
6+
from enum import Enum, StrEnum, auto
67
import sys
78
from _remote_debugging import RemoteUnwinder, FrameInfo
89

@@ -232,18 +233,51 @@ def _get_awaited_by_tasks(pid: int) -> list:
232233
sys.exit(1)
233234

234235

235-
def display_awaited_by_tasks_table(pid: int) -> None:
236+
class TaskTableOutputFormat(StrEnum):
237+
table = auto()
238+
csv = auto()
239+
240+
241+
def display_awaited_by_tasks_table(pid, *, format=TaskTableOutputFormat.table):
236242
"""Build and print a table of all pending tasks under `pid`."""
237243

238244
tasks = _get_awaited_by_tasks(pid)
239245
table = build_task_table(tasks)
240-
# Print the table in a simple tabular format
241-
print(
242-
f"{'tid':<10} {'task id':<20} {'task name':<20} {'coroutine stack':<50} {'awaiter chain':<50} {'awaiter name':<15} {'awaiter id':<15}"
243-
)
244-
print("-" * 180)
246+
format = TaskTableOutputFormat(format)
247+
if format == TaskTableOutputFormat.table:
248+
_display_awaited_by_tasks_table(table)
249+
else:
250+
_display_awaited_by_tasks_csv(table, format=format)
251+
252+
253+
_row_header = ('tid', 'task id', 'task name', 'coroutine stack',
254+
'awaiter chain', 'awaiter name', 'awaiter id')
255+
256+
257+
def _display_awaited_by_tasks_table(table):
258+
"""Print the table in a simple tabular format."""
259+
print(_fmt_table_row(*_row_header))
260+
print('-' * 180)
245261
for row in table:
246-
print(f"{row[0]:<10} {row[1]:<20} {row[2]:<20} {row[3]:<50} {row[4]:<50} {row[5]:<15} {row[6]:<15}")
262+
print(_fmt_table_row(*row))
263+
264+
265+
def _fmt_table_row(tid, task_id, task_name, coro_stack,
266+
awaiter_chain, awaiter_name, awaiter_id):
267+
# Format a single row for the table format
268+
return (f'{tid:<10} {task_id:<20} {task_name:<20} {coro_stack:<50} '
269+
f'{awaiter_chain:<50} {awaiter_name:<15} {awaiter_id:<15}')
270+
271+
272+
def _display_awaited_by_tasks_csv(table, *, format):
273+
"""Print the table in CSV format"""
274+
if format == TaskTableOutputFormat.csv:
275+
delimiter = ','
276+
else:
277+
raise ValueError(f"Unknown output format: {format}")
278+
csv_writer = csv.writer(sys.stdout, delimiter=delimiter)
279+
csv_writer.writerow(_row_header)
280+
csv_writer.writerows(table)
247281

248282

249283
def display_awaited_by_tasks_tree(pid: int) -> None:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add CSV as an output format for :program:`python -m asyncio ps`.

0 commit comments

Comments
 (0)