Skip to content

Commit e18dda9

Browse files
yihong0618StanFromIrelandhugovkZeroIntensitypicnixz
authored
gh-139374: colorize traceback when using timeit command-line interface (#139375)
--------- Signed-off-by: yihong0618 <[email protected]> Co-authored-by: Stan Ulbrych <[email protected]> Co-authored-by: Hugo van Kemenade <[email protected]> Co-authored-by: Peter Bierma <[email protected]> Co-authored-by: Bénédikt Tran <[email protected]>
1 parent 6661123 commit e18dda9

File tree

5 files changed

+31
-9
lines changed

5 files changed

+31
-9
lines changed

Doc/whatsnew/3.15.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ tarfile
536536
(Contributed by Christoph Walcher in :gh:`57911`.)
537537

538538

539+
timeit
540+
------
541+
542+
* The command-line interface now colorizes error tracebacks
543+
by default. This can be controlled with
544+
:ref:`environment variables <using-on-controlling-color>`.
545+
(Contributed by Yi Hong in :gh:`139374`.)
546+
547+
539548
types
540549
------
541550

Lib/test/test_timeit.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import io
55
from textwrap import dedent
66

7-
from test.support import captured_stdout
8-
from test.support import captured_stderr
7+
from test.support import (
8+
captured_stdout, captured_stderr, force_not_colorized,
9+
)
910

1011
# timeit's default number of iterations.
1112
DEFAULT_NUMBER = 1000000
@@ -351,11 +352,13 @@ def test_main_with_time_unit(self):
351352
self.assertEqual(error_stringio.getvalue(),
352353
"Unrecognized unit. Please select nsec, usec, msec, or sec.\n")
353354

355+
@force_not_colorized
354356
def test_main_exception(self):
355357
with captured_stderr() as error_stringio:
356358
s = self.run_main(switches=['1/0'])
357359
self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
358360

361+
@force_not_colorized
359362
def test_main_exception_fixed_reps(self):
360363
with captured_stderr() as error_stringio:
361364
s = self.run_main(switches=['-n1', '1/0'])

Lib/timeit.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def __init__(self, stmt="pass", setup="pass", timer=default_timer,
133133
exec(code, global_ns, local_ns)
134134
self.inner = local_ns["inner"]
135135

136-
def print_exc(self, file=None):
136+
def print_exc(self, file=None, **kwargs):
137137
"""Helper to print a traceback from the timed code.
138138
139139
Typical use:
@@ -149,6 +149,11 @@ def print_exc(self, file=None):
149149
150150
The optional file argument directs where the traceback is
151151
sent; it defaults to sys.stderr.
152+
153+
The optional colorize keyword argument controls whether the
154+
traceback is colorized; it defaults to False for programmatic
155+
usage. When used from the command line, this is automatically
156+
set based on terminal capabilities.
152157
"""
153158
import linecache, traceback
154159
if self.src is not None:
@@ -158,7 +163,8 @@ def print_exc(self, file=None):
158163
dummy_src_name)
159164
# else the source is already stored somewhere else
160165

161-
traceback.print_exc(file=file)
166+
kwargs['colorize'] = kwargs.get('colorize', False)
167+
traceback.print_exc(file=file, **kwargs)
162168

163169
def timeit(self, number=default_number):
164170
"""Time 'number' executions of the main statement.
@@ -257,9 +263,12 @@ def main(args=None, *, _wrap_timer=None):
257263
is not None, it must be a callable that accepts a timer function
258264
and returns another timer function (used for unit testing).
259265
"""
266+
import getopt
260267
if args is None:
261268
args = sys.argv[1:]
262-
import getopt
269+
import _colorize
270+
colorize = _colorize.can_colorize()
271+
263272
try:
264273
opts, args = getopt.getopt(args, "n:u:s:r:pvh",
265274
["number=", "setup=", "repeat=",
@@ -326,7 +335,7 @@ def callback(number, time_taken):
326335
try:
327336
number, _ = t.autorange(callback)
328337
except:
329-
t.print_exc()
338+
t.print_exc(colorize=colorize)
330339
return 1
331340

332341
if verbose:
@@ -335,7 +344,7 @@ def callback(number, time_taken):
335344
try:
336345
raw_timings = t.repeat(repeat, number)
337346
except:
338-
t.print_exc()
347+
t.print_exc(colorize=colorize)
339348
return 1
340349

341350
def format_time(dt):

Lib/traceback.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ def _safe_string(value, what, func=str):
206206

207207
# --
208208

209-
def print_exc(limit=None, file=None, chain=True):
209+
def print_exc(limit=None, file=None, chain=True, **kwargs):
210210
"""Shorthand for 'print_exception(sys.exception(), limit=limit, file=file, chain=chain)'."""
211-
print_exception(sys.exception(), limit=limit, file=file, chain=chain)
211+
print_exception(sys.exception(), limit=limit, file=file, chain=chain, **kwargs)
212212

213213
def format_exc(limit=None, chain=True):
214214
"""Like print_exc() but return a string."""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:mod:`timeit`: Add color to error tracebacks.

0 commit comments

Comments
 (0)