Skip to content

Commit 9bb8e7c

Browse files
committed
PEP 830: apply round-2 feedback
Updates the implementation to match the PEP revisions in python/peps#4928 * Drop the ``us`` display format; ``-X traceback_timestamps`` with no value or ``=1`` now selects ``ns``. * ``ns`` format now renders as seconds with nine fractional digits (``<@1776017178.687320256>``) instead of a raw integer with an ``ns`` suffix. Integer divmod is used to preserve full precision. * The ``no_timestamp`` boolean on the traceback formatting APIs is replaced by a tri-state ``timestamps`` keyword: ``None`` follows the global config, ``False`` suppresses, ``True`` forces display of any non-zero ``__timestamp_ns__``. The setting now propagates through ``__cause__``, ``__context__`` and exception-group members. * MemoryError instances handed out from the free list receive a fresh timestamp at hand-out time; only the last-resort static singleton remains at 0.
1 parent 2672099 commit 9bb8e7c

File tree

13 files changed

+252
-116
lines changed

13 files changed

+252
-116
lines changed

Doc/c-api/init_config.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,9 +1905,9 @@ PyConfig
19051905
If not ``NULL`` or an empty string, timestamps of exceptions are collected
19061906
and will be displayed in the configured format. Acceptable values are:
19071907
1908-
* ``"us"``: Display timestamps in microseconds
1909-
* ``"ns"``: Display timestamps in nanoseconds
1910-
* ``"iso"``: Display timestamps in ISO-8601 format
1908+
* ``"ns"``: Display UTC seconds since the epoch with nanosecond resolution
1909+
* ``"iso"``: Display an ISO-8601 formatted UTC time with microsecond
1910+
resolution
19111911
* ``""``: Collection and display is disabled.
19121912
19131913
Set by the :option:`-X traceback_timestamps=FORMAT <-X>` command line

Doc/library/exceptions.rst

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,22 @@ The following exceptions are used mostly as base classes for other exceptions.
161161

162162
.. attribute:: __timestamp_ns__
163163

164-
The absolute time in nanoseconds at which this exception was instantiated
165-
(usually: when it was raised).
166-
Having the same accuracy and time epoch as :func:`time.time_ns`.
164+
The absolute UTC time in nanoseconds at which this exception was
165+
instantiated (usually: when it was raised), with the same accuracy and
166+
epoch as :func:`time.time_ns`.
167167
Collection and display of these timestamps after the exception message in
168168
tracebacks is off by default but can be configured using the
169169
:envvar:`PYTHON_TRACEBACK_TIMESTAMPS` environment variable or the
170170
:option:`-X traceback_timestamps <-X>` command line option. In
171171
applications with complicated exception chains and exception groups it
172-
may be useful to help understand what happened when. The value will be
173-
``0`` if a timestamp was not recorded. :exc:`StopIteration` and
174-
:exc:`StopAsyncIteration` never record timestamps as those are primarily
175-
for control flow.
172+
may be useful to help understand what happened when.
173+
174+
The value is ``0`` when a timestamp was not recorded.
175+
:exc:`StopIteration` and :exc:`StopAsyncIteration` never record
176+
timestamps as they are used primarily for control flow.
177+
178+
This attribute does not affect the result of :func:`str` or :func:`repr`
179+
on the exception.
176180

177181
With ``PYTHON_TRACEBACK_TIMESTAMPS=iso`` in the environment ::
178182

@@ -186,7 +190,7 @@ The following exceptions are used mostly as base classes for other exceptions.
186190
Traceback (most recent call last):
187191
File "<python-input-0>", line 1, in <module>
188192
raise RuntimeError("example")
189-
RuntimeError: example <@1739172733527638530ns>
193+
RuntimeError: example <@1739172733.527638530>
190194

191195
.. versionadded:: next
192196

Doc/library/sys.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only
655655
* - .. attribute:: flags.traceback_timestamps
656656
- :option:`-X traceback_timestamps <-X>` and
657657
:envvar:`PYTHON_TRACEBACK_TIMESTAMPS`. This is a string containing
658-
the selected format (``us``, ``ns``, ``iso``), or an empty string
658+
the selected format (``ns`` or ``iso``), or an empty string
659659
when disabled.
660660

661661
.. versionchanged:: 3.2

Doc/library/traceback.rst

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Module-Level Functions
7979

8080

8181
.. function:: print_exception(exc, /[, value, tb], limit=None, \
82-
file=None, chain=True, \*, no_timestamp=False)
82+
file=None, chain=True, \*, timestamps=None)
8383

8484
Print exception information and stack trace entries from
8585
:ref:`traceback object <traceback-objects>`
@@ -108,11 +108,14 @@ Module-Level Functions
108108
printed as well, like the interpreter itself does when printing an unhandled
109109
exception.
110110

111-
If *no_timestamp* is ``True`` and a traceback timestamp format is enabled via the
112-
:envvar:`PYTHON_TRACEBACK_TIMESTAMPS` environment variable or the
113-
:option:`-X traceback_timestamps <-X>` option, any timestamp after the exception
114-
message will be omitted. This is useful for tests or other situations where
115-
you need consistent output regardless of when exceptions occur.
111+
The *timestamps* argument controls whether the
112+
:attr:`~BaseException.__timestamp_ns__` of each exception is appended after
113+
its message. When ``None`` (the default), the global configuration set by
114+
:envvar:`PYTHON_TRACEBACK_TIMESTAMPS` or
115+
:option:`-X traceback_timestamps <-X>` is followed. When ``False``,
116+
timestamps are never shown. When ``True``, any non-zero
117+
``__timestamp_ns__`` is shown regardless of the global configuration, using
118+
the configured format if one is set and the ``ns`` format otherwise.
116119

117120
.. versionchanged:: 3.5
118121
The *etype* argument is ignored and inferred from the type of *value*.
@@ -122,7 +125,7 @@ Module-Level Functions
122125
positional-only.
123126

124127
.. versionchanged:: next
125-
The *no_timestamp* keyword only argument was added.
128+
The *timestamps* keyword-only argument was added.
126129

127130

128131
.. function:: print_exc(limit=None, file=None, chain=True)
@@ -191,7 +194,7 @@ Module-Level Functions
191194

192195

193196
.. function:: format_exception_only(exc, /[, value], \*, show_group=False, \
194-
no_timestamp=False)
197+
timestamps=None)
195198

196199
Format the exception part of a traceback using an exception value such as
197200
given by :data:`sys.last_value`. The return value is a list of strings, each
@@ -209,11 +212,8 @@ Module-Level Functions
209212
:exc:`BaseExceptionGroup`, the nested exceptions are included as
210213
well, recursively, with indentation relative to their nesting depth.
211214

212-
If *no_timestamp* is ``True`` and a traceback timestamp formatting is enabled
213-
via the :envvar:`PYTHON_TRACEBACK_TIMESTAMPS` environment variable or the
214-
:option:`-X traceback_timestamps <-X>` command line option, any timestamp
215-
after the exception message will be omitted. This is useful for tests or
216-
other situations where you need canonical output.
215+
The *timestamps* argument has the same meaning as for
216+
:func:`print_exception`.
217217

218218
.. versionchanged:: 3.10
219219
The *etype* parameter has been renamed to *exc* and is now
@@ -227,24 +227,20 @@ Module-Level Functions
227227
*show_group* parameter was added.
228228

229229
.. versionchanged:: next
230-
The *no_timestamp* keyword only argument was added.
230+
The *timestamps* keyword-only argument was added.
231231

232232

233233
.. function:: format_exception(exc, /[, value, tb], limit=None, chain=True, \
234-
\*, no_timestamp=False)
234+
\*, timestamps=None)
235235

236236
Format a stack trace and the exception information. The arguments have the
237237
same meaning as the corresponding arguments to :func:`print_exception`. The
238238
return value is a list of strings, each ending in a newline and some
239239
containing internal newlines. When these lines are concatenated and printed,
240240
exactly the same text is printed as does :func:`print_exception`.
241241

242-
If *no_timestamp* is ``True`` and a traceback timestamp formatting is enabled
243-
via the :envvar:`PYTHON_TRACEBACK_TIMESTAMPS` environment variable or the
244-
:option:`-X traceback_timestamps <-X>` command line option, any timestamp
245-
after the exception message will be omitted. This is useful for tests or
246-
other situations where you need consistent output regardless of when
247-
exceptions occur.
242+
The *timestamps* argument has the same meaning as for
243+
:func:`print_exception`.
248244

249245
.. versionchanged:: 3.5
250246
The *etype* argument is ignored and inferred from the type of *value*.
@@ -254,7 +250,7 @@ Module-Level Functions
254250
:func:`print_exception`.
255251

256252
.. versionchanged:: next
257-
The *no_timestamp* keyword only argument was added.
253+
The *timestamps* keyword-only argument was added.
258254

259255

260256
.. function:: format_exc(limit=None, chain=True)
@@ -329,7 +325,7 @@ storing this information by avoiding holding references to
329325
In addition, they expose more options to configure the output compared to
330326
the module-level functions described above.
331327

332-
.. class:: TracebackException(exc_type, exc_value, exc_traceback, \*, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10, no_timestamp=False)
328+
.. class:: TracebackException(exc_type, exc_value, exc_traceback, \*, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10, timestamps=None)
333329

334330
Capture an exception for later rendering. The meaning of *limit*,
335331
*lookup_lines* and *capture_locals* are as for the :class:`StackSummary`
@@ -349,9 +345,13 @@ the module-level functions described above.
349345
group's exceptions array. The formatted output is truncated when either
350346
limit is exceeded.
351347

352-
If *no_timestamp* is ``True`` the ``__timestamp_ns__`` attribute from the
353-
exception will not be rendered when formatting this
354-
:class:`!TracebackException`.
348+
The *timestamps* argument controls whether each exception's
349+
:attr:`~BaseException.__timestamp_ns__` is captured for later rendering.
350+
When ``None`` (the default), the global configuration set by
351+
:envvar:`PYTHON_TRACEBACK_TIMESTAMPS` or
352+
:option:`-X traceback_timestamps <-X>` is followed. When ``False``,
353+
timestamps are never shown. When ``True``, any non-zero
354+
``__timestamp_ns__`` is shown regardless of the global configuration.
355355

356356
.. versionchanged:: 3.10
357357
Added the *compact* parameter.
@@ -360,7 +360,7 @@ the module-level functions described above.
360360
Added the *max_group_width* and *max_group_depth* parameters.
361361

362362
.. versionchanged:: next
363-
Added the *no_timestamp* parameter.
363+
Added the *timestamps* parameter.
364364

365365
.. attribute:: __cause__
366366

Doc/using/cmdline.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -713,12 +713,12 @@ Miscellaneous options
713713

714714
.. versionadded:: 3.15
715715

716-
* :samp:`-X traceback_timestamps=[us|ns|iso|0|1]` enables or configures timestamp
716+
* :samp:`-X traceback_timestamps=[ns|iso|0|1]` enables or configures timestamp
717717
display in exception tracebacks. When enabled, each exception's traceback
718718
will include a timestamp showing when the exception occurred. The format
719-
options are: ``us`` (microseconds), ``ns``
720-
(nanoseconds), ``iso`` (ISO-8601 formatted time), ``0`` (disable timestamps),
721-
and ``1`` (equivalent to ``us``). See also :envvar:`PYTHON_TRACEBACK_TIMESTAMPS`.
719+
options are: ``ns`` (seconds since the epoch with nanosecond resolution),
720+
``iso`` (ISO-8601 formatted UTC time), ``0`` (disable timestamps),
721+
and ``1`` (equivalent to ``ns``). See also :envvar:`PYTHON_TRACEBACK_TIMESTAMPS`.
722722

723723
.. versionadded:: next
724724

@@ -1440,9 +1440,9 @@ conflict.
14401440
by the runtime will be annotated with the timestamp of each exception. The
14411441
values control the format of the timestamp:
14421442

1443-
* ``us`` or ``1``: Prints decimal timestamps with microsecond precision.
1444-
* ``ns``: Prints the raw timestamp in nanoseconds.
1445-
* ``iso``: Prints the timestamp formatted by :meth:`~datetime.datetime.isoformat` (also microsecond precision).
1443+
* ``ns`` or ``1``: Prints UTC seconds since the epoch with nanosecond
1444+
resolution.
1445+
* ``iso``: Prints an ISO-8601 formatted UTC time with microsecond resolution.
14461446
* ``0``: Explicitly disables timestamps.
14471447

14481448
When unset, timestamps are disabled by default. The time is not recorded on

Lib/doctest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ def _exception_traceback(exc_info):
273273
# Get a traceback message.
274274
excout = StringIO()
275275
exc_type, exc_val, exc_tb = exc_info
276-
traceback.print_exception(exc_type, exc_val, exc_tb, file=excout, no_timestamp=True)
276+
traceback.print_exception(exc_type, exc_val, exc_tb, file=excout, timestamps=False)
277277
return excout.getvalue()
278278

279279
# Override some StringIO methods.
@@ -1449,7 +1449,7 @@ def __run(self, test, compileflags, out):
14491449

14501450
# The example raised an exception: check if it was expected.
14511451
else:
1452-
formatted_ex = traceback.format_exception_only(*exc_info[:2], no_timestamp=True)
1452+
formatted_ex = traceback.format_exception_only(*exc_info[:2], timestamps=False)
14531453
if issubclass(exc_info[0], SyntaxError):
14541454
# SyntaxError / IndentationError is special:
14551455
# we don't care about the carets / suggestions / etc

Lib/test/support/__init__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,17 +3039,15 @@ def no_traceback_timestamps():
30393039

30403040
with (
30413041
swap_attr(traceback, "_TIMESTAMP_FORMAT", ""),
3042+
# The C fallback display path in pythonrun.c gates on
3043+
# PyCallable_Check(_timestamp_formatter), so None is needed here in
3044+
# addition to the empty format string.
3045+
swap_attr(traceback, "_timestamp_formatter", None),
30423046
EnvironmentVarGuard() as env,
30433047
):
30443048
# This prevents it from being on in child processes.
30453049
env.unset("PYTHON_TRACEBACK_TIMESTAMPS")
3046-
# Silence our other-path pythonrun.c print_exception_message().
3047-
tf = getattr(traceback, "_timestamp_formatter", "Nope!")
3048-
if tf != "Nope!":
3049-
del traceback._timestamp_formatter
30503050
yield
3051-
if tf != "Nope!":
3052-
traceback._timestamp_formatter = tf
30533051

30543052

30553053
def force_no_traceback_timestamps(func):

Lib/test/test_code_module.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def test_sysexcepthook(self):
158158
self.assertIs(self.sysmod.last_traceback, self.sysmod.last_value.__traceback__)
159159
self.assertIs(self.sysmod.last_exc, self.sysmod.last_value)
160160
self.assertEqual(
161-
traceback.format_exception(self.sysmod.last_exc, no_timestamp=True),
161+
traceback.format_exception(self.sysmod.last_exc, timestamps=False),
162162
[
163163
'Traceback (most recent call last):\n',
164164
' File "<console>", line 1, in <module>\n',
@@ -183,7 +183,7 @@ def test_sysexcepthook_syntax_error(self):
183183
self.assertIsNone(self.sysmod.last_value.__traceback__)
184184
self.assertIs(self.sysmod.last_exc, self.sysmod.last_value)
185185
self.assertEqual(
186-
traceback.format_exception(self.sysmod.last_exc, no_timestamp=True),
186+
traceback.format_exception(self.sysmod.last_exc, timestamps=False),
187187
[
188188
' File "<console>", line 2\n',
189189
' x = ?\n',
@@ -205,7 +205,7 @@ def test_sysexcepthook_indentation_error(self):
205205
self.assertIsNone(self.sysmod.last_value.__traceback__)
206206
self.assertIs(self.sysmod.last_exc, self.sysmod.last_value)
207207
self.assertEqual(
208-
traceback.format_exception(self.sysmod.last_exc, no_timestamp=True),
208+
traceback.format_exception(self.sysmod.last_exc, timestamps=False),
209209
[
210210
' File "<console>", line 1\n',
211211
' 1\n',

0 commit comments

Comments
 (0)