Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,14 @@ tarfile
(Contributed by Christoph Walcher in :gh:`57911`.)


timeit
------

* Error tracebacks are now colourised by default. This can be controlled by
:ref:`environment variables <using-on-controlling-color>`.
(Contributed by Yi Hong in :gh:`139374`.)


types
------

Expand Down
5 changes: 4 additions & 1 deletion Lib/test/test_timeit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import io
from textwrap import dedent

from test.support import captured_stdout
from test.support import captured_stdout, force_not_colorized
from test.support import captured_stderr

# timeit's default number of iterations.
Expand Down Expand Up @@ -225,6 +225,7 @@ def assert_exc_string(self, exc_string, expected_exc_name):
self.assertStartsWith(exc_lines[0], 'Traceback')
self.assertStartsWith(exc_lines[-1], expected_exc_name)

@force_not_colorized
def test_print_exc(self):
s = io.StringIO()
t = timeit.Timer("1/0")
Expand Down Expand Up @@ -351,11 +352,13 @@ def test_main_with_time_unit(self):
self.assertEqual(error_stringio.getvalue(),
"Unrecognized unit. Please select nsec, usec, msec, or sec.\n")

@force_not_colorized
def test_main_exception(self):
with captured_stderr() as error_stringio:
s = self.run_main(switches=['1/0'])
self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')

@force_not_colorized
def test_main_exception_fixed_reps(self):
with captured_stderr() as error_stringio:
s = self.run_main(switches=['-n1', '1/0'])
Expand Down
19 changes: 14 additions & 5 deletions Lib/timeit.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def __init__(self, stmt="pass", setup="pass", timer=default_timer,
exec(code, global_ns, local_ns)
self.inner = local_ns["inner"]

def print_exc(self, file=None):
def print_exc(self, file=None, **kwargs):
"""Helper to print a traceback from the timed code.

Typical use:
Expand All @@ -149,16 +149,22 @@ def print_exc(self, file=None):

The optional file argument directs where the traceback is
sent; it defaults to sys.stderr.

The optional colorize keyword argument controls whether the
traceback is colorized; it defaults to False for programmatic
usage. When used from the command line, this is automatically
set based on terminal capabilities.
"""
import linecache, traceback
import linecache, traceback, sys
if self.src is not None:
linecache.cache[dummy_src_name] = (len(self.src),
None,
self.src.split("\n"),
dummy_src_name)
# else the source is already stored somewhere else

traceback.print_exc(file=file)
kwargs['colorize'] = kwargs.get('colorize', False)
traceback.print_exc(file=file, **kwargs)

def timeit(self, number=default_number):
"""Time 'number' executions of the main statement.
Expand Down Expand Up @@ -260,6 +266,7 @@ def main(args=None, *, _wrap_timer=None):
if args is None:
args = sys.argv[1:]
import getopt
import _colorize
try:
opts, args = getopt.getopt(args, "n:u:s:r:pvh",
["number=", "setup=", "repeat=",
Expand Down Expand Up @@ -326,7 +333,8 @@ def callback(number, time_taken):
try:
number, _ = t.autorange(callback)
except:
t.print_exc()
colorize = _colorize.can_colorize()
t.print_exc(colorize=colorize)
return 1

if verbose:
Expand All @@ -335,7 +343,8 @@ def callback(number, time_taken):
try:
raw_timings = t.repeat(repeat, number)
except:
t.print_exc()
colorize = _colorize.can_colorize()
t.print_exc(colorize=colorize)
return 1

def format_time(dt):
Expand Down
4 changes: 2 additions & 2 deletions Lib/traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ def _safe_string(value, what, func=str):

# --

def print_exc(limit=None, file=None, chain=True):
def print_exc(limit=None, file=None, chain=True, **kwargs):
"""Shorthand for 'print_exception(sys.exception(), limit=limit, file=file, chain=chain)'."""
print_exception(sys.exception(), limit=limit, file=file, chain=chain)
print_exception(sys.exception(), limit=limit, file=file, chain=chain, **kwargs)

def format_exc(limit=None, chain=True):
"""Like print_exc() but return a string."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:mod:`timeit`: Add color to error tracebacks.
Loading