Skip to content

Commit bcc720b

Browse files
committed
Timestamp format configurability.
1 parent c119a02 commit bcc720b

1 file changed

Lines changed: 35 additions & 18 deletions

File tree

Lib/traceback.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
'walk_stack', 'walk_tb', 'print_list']
2020

2121

22-
ENABLE_TRACEBACK_TIMESTAMPS = os.environ.get("PYTHON_TRACEBACK_TIMESTAMPS", "") == "1"
23-
24-
2522
#
2623
# Formatting and printing lists of traceback lines.
2724
#
@@ -182,23 +179,43 @@ def format_exception_only(exc, /, value=_sentinel, *, show_group=False, **kwargs
182179
return list(te.format_exception_only(show_group=show_group, colorize=colorize))
183180

184181

182+
_TIMESTAMP_FORMAT = os.environ.get("PYTHON_TRACEBACK_TIMESTAMPS", "")
183+
match _TIMESTAMP_FORMAT:
184+
case "us" | "1":
185+
def _timestamp_formatter(ns):
186+
return f"<@{ns/1e9:.6f}>"
187+
case "ns":
188+
def _timestamp_formatter(ns):
189+
return f"<@{ns}ns>"
190+
case "iso":
191+
def _timestamp_formatter(ns):
192+
from datetime import datetime
193+
return f"<@{datetime.fromtimestamp(ns/1e9).isoformat()}>"
194+
case _:
195+
_TIMESTAMP_FORMAT = ""
196+
197+
185198
# -- not official API but folk probably use these two functions.
186199

187-
def _format_final_exc_line(etype, value, *, insert_final_newline=True, colorize=False, timestamp=0):
200+
def _format_final_exc_line(etype, value, *, insert_final_newline=True, colorize=False, timestamp_ns=0):
188201
valuestr = _safe_string(value, 'exception')
189-
end_char = "\n" if insert_final_newline else ""
190-
ts = f" <@T={timestamp:.6f}>" if timestamp else ""
202+
try:
203+
ts = _timestamp_formatter(timestamp_ns) if timestamp_ns else ""
204+
except Exception:
205+
ts = ""
206+
end = f"\n" if insert_final_newline else ""
191207
if colorize:
192-
timestamp = f"{ANSIColors.GREY}{ts}{ANSIColors.RESET}" if timestamp else ""
208+
end = f" {ANSIColors.GREY}{ts}{ANSIColors.RESET}{end}" if ts else end
193209
if value is None or not valuestr:
194-
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}{ts}{end_char}"
210+
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}{end}"
195211
else:
196-
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}: {ANSIColors.MAGENTA}{valuestr}{ANSIColors.RESET}{ts}{end_char}"
212+
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}: {ANSIColors.MAGENTA}{valuestr}{ANSIColors.RESET}{end}"
197213
else:
214+
end = f" {ts}{end}" if ts else end
198215
if value is None or not valuestr:
199-
line = f"{etype}{ts}{end_char}"
216+
line = f"{etype}{end}"
200217
else:
201-
line = f"{etype}: {valuestr}{ts}{end_char}"
218+
line = f"{etype}: {valuestr}{end}"
202219
return line
203220

204221

@@ -1012,11 +1029,11 @@ class TracebackException:
10121029
- :attr:`__cause__` A TracebackException of the original *__cause__*.
10131030
- :attr:`__context__` A TracebackException of the original *__context__*.
10141031
- :attr:`__notes__` A reference to the original *__notes__* list.
1015-
- :attr:`_timestamp` When the exception was created (seconds), if enabled.
10161032
- :attr:`exceptions` For exception groups - a list of TracebackException
10171033
instances for the nested *exceptions*. ``None`` for other exceptions.
10181034
- :attr:`__suppress_context__` The *__suppress_context__* value from the
10191035
original exception.
1036+
- :attr:`_timestamp_ns` When the exception was created if enabled, or 0.
10201037
- :attr:`stack` A `StackSummary` representing the traceback.
10211038
- :attr:`exc_type` (deprecated) The class of the original traceback.
10221039
- :attr:`exc_type_str` String display of exc_type
@@ -1066,10 +1083,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
10661083
self.__notes__ = [
10671084
f'Ignored error getting __notes__: {_safe_string(e, '__notes__', repr)}']
10681085

1069-
if ENABLE_TRACEBACK_TIMESTAMPS:
1070-
self._timestamp = exc_value.__timestamp_ns__ / 1_000_000_000
1086+
if _TIMESTAMP_FORMAT:
1087+
self._timestamp_ns = exc_value.__timestamp_ns__
10711088
else:
1072-
self._timestamp = 0
1089+
self._timestamp_ns = 0
10731090

10741091
self._is_syntax_error = False
10751092
self._have_exc_type = exc_type is not None
@@ -1242,22 +1259,22 @@ def format_exception_only(self, *, show_group=False, _depth=0, **kwargs):
12421259

12431260
indent = 3 * _depth * ' '
12441261
if not self._have_exc_type:
1245-
yield indent + _format_final_exc_line(None, self._str, colorize=colorize, timestamp=self._timestamp)
1262+
yield indent + _format_final_exc_line(None, self._str, colorize=colorize, timestamp_ns=self._timestamp_ns)
12461263
return
12471264

12481265
stype = self.exc_type_str
12491266
if not self._is_syntax_error:
12501267
if _depth > 0:
12511268
# Nested exceptions needs correct handling of multiline messages.
12521269
formatted = _format_final_exc_line(
1253-
stype, self._str, insert_final_newline=False, colorize=colorize, timestamp=self._timestamp
1270+
stype, self._str, insert_final_newline=False, colorize=colorize, timestamp_ns=self._timestamp_ns
12541271
).split('\n')
12551272
yield from [
12561273
indent + l + '\n'
12571274
for l in formatted
12581275
]
12591276
else:
1260-
yield _format_final_exc_line(stype, self._str, colorize=colorize, timestamp=self._timestamp)
1277+
yield _format_final_exc_line(stype, self._str, colorize=colorize, timestamp_ns=self._timestamp_ns)
12611278
else:
12621279
yield from [indent + l for l in self._format_syntax_error(stype, colorize=colorize)]
12631280

0 commit comments

Comments
 (0)