Open
Conversation
…dback - Clarified that __timestamp_ns__ is UTC, that clock-read failure yields 0, and how free-list and singleton MemoryError instances are timestamped. - Clarified that str(exc) and repr(exc) are unchanged, and that the iso display format has microsecond resolution. - Changed the ns display format from an integer with an ns suffix to seconds with nine decimal digits, allowing direct use with datetime.fromtimestamp(). Dropped the us format; ns is now the default format when the feature is enabled via 1 or with no explicit format value. - Added Rejected Ideas entries for returning None when unset and for using a coarse-resolution clock. - Made the Motivation example self-contained.
Frame it as an operator-level setting and note that runtime configurability can be added later if there is demand.
…tion Explain why the timestamp is appended to the message line rather than the Traceback header (the header is absent for exceptions without a traceback, as with ProcessPoolExecutor's _RemoteTraceback), and add an Open Issues section noting display location remains open to revision.
Rename the traceback formatting parameter from no_timestamp (a double-negative boolean) to timestamps, and make it tri-state: None follows the global configuration (default), False suppresses, True displays any non-zero __timestamp_ns__ regardless of the global setting.
CPython's PyObject_GetOptionalAttr and the suppress paths in generic attribute lookup already return "not found" without instantiating an exception object, and the dict miss paths never create a KeyError internally, so these idioms do not need to be excluded from timestamp collection.
The hook fires at display time, once for the whole ExceptionGroup, so it cannot record per-sub-exception creation times; caught exceptions never reach it.
Explain why the timestamp is recorded at instantiation rather than raise: the two coincide in the common case, instantiation time is the more useful value for re-raise and collect-then-group patterns, and instantiation has a clean two-point funnel in CPython while raising does not. Defer "time of first raise" to Open Issues.
Describe a viable third-party design using a RAISE callback and its costs: per-frame (not per-exception) dispatch through vectorcall, instance dict and PyLongObject (or list and string for add_note) allocation on every raise, consuming a tool ID, and needing excepthook or a traceback monkeypatch to display the attribute variant. Also describe a hybrid that keeps the struct field and traceback display but uses monitoring for collection. Leave a short Open Issues entry offering to prototype and benchmark if there is demand.
Break up two adjacent "rather than" pairs (Rationale and sys.monitoring paragraphs) and reorder/consolidate the Change History bullets so spec changes lead, followed by Rationale, a single Rejected Ideas bullet, a single Open Issues bullet, and housekeeping.
The original TaskGroup example only ever produced one sub-exception because TaskGroup cancels siblings on first failure. Switch to a three-backend asyncio.gather(..., return_exceptions=True) pattern that collects every failure, and replace the illustrative output with real output captured from the reference implementation. Update the sys.excepthook rejection to drop the now-stale TaskGroup reference.
gpshead
added a commit
to gpshead/cpython
that referenced
this pull request
Apr 19, 2026
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.
gpshead
commented
Apr 19, 2026
| preserves the original timestamp on re-raise. | ||
|
|
||
| This is expected to cost more than the struct-field approach. ``RAISE`` | ||
| fires once per Python frame during unwind rather than once per exception, so |
Member
Author
There was a problem hiding this comment.
Some sample code to demonstrate this once per frame RAISE event in this gist produces:
One `raise`, RAISE callback fired 5 times:
in frame 'level_d' offset=22 exc id=0x7f4c881e8700
in frame 'level_c' offset=10 exc id=0x7f4c881e8700
in frame 'level_b' offset=10 exc id=0x7f4c881e8700
in frame 'level_a' offset=10 exc id=0x7f4c881e8700
in frame '<module>' offset=320 exc id=0x7f4c881e8700
Distinct exception objects seen: 1 (same object passed to every call)
Member
Author
There was a problem hiding this comment.
I believe due to https://github.com/python/cpython/blob/4b3330813760a3e3c75cd03023d252742168683b/Python/bytecodes.c#L6391 being called on each frame on the way up.
Shorten the None-when-unset and coarse-clock rejections, and replace the "can be added later" closer in the time-of-first-raise open issue with a note that early-construction patterns are not common in practice.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is just the Change History section repeated here. Please only make editorial comments on this PR. Discussion needs to happen solely in the Discuss thread.
nsdisplay format from an integer with annssuffix to seconds with nine decimal digits, allowing direct use withdatetime.fromtimestamp(). Dropped theusformat;nsis now the default when enabled via1or with no explicit format value.tracebackmoduleno_timestampparameter with a tri-statetimestamps(defaultNone, follow the global setting).__timestamp_ns__is UTC, that clock-read failure yields0, and how free-list and singletonMemoryErrorinstances are timestamped; thatstr(exc)andrepr(exc)are unchanged; and that theisodisplay format has microsecond resolution.hasattr, three-argumentgetattr, and the dict miss paths do not instantiate exceptions in CPython's hot paths and need no special handling.sys.excepthook,sys.monitoring, placing the timestamp in theTracebackheader line, returningNonewhen unset, separate ms/us display formats, and using a coarse-resolution clock; reworded the Runtime API rejection.sys.monitoringalternative, and recording time of first raise.📚 Documentation preview 📚: https://pep-previews--4928.org.readthedocs.build/