Skip to content

Commit 4c031a6

Browse files
committed
fix stripping tests
1 parent e6199e3 commit 4c031a6

File tree

2 files changed

+155
-31
lines changed

2 files changed

+155
-31
lines changed

Lib/test/test_traceback_timestamps.py

Lines changed: 154 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
import sys
33
import unittest
44
import subprocess
5+
import re
56

67
from test.support import script_helper
78
from test.support.os_helper import TESTFN, unlink
89

10+
911
class TracebackTimestampsTests(unittest.TestCase):
1012
def setUp(self):
1113
self.script = """
@@ -20,8 +22,8 @@ def cause_exception():
2022
except Exception as e:
2123
traceback.print_exc()
2224
"""
23-
self.script_path = TESTFN + '.py'
24-
with open(self.script_path, 'w') as script_file:
25+
self.script_path = TESTFN + ".py"
26+
with open(self.script_path, "w") as script_file:
2527
script_file.write(self.script)
2628
self.addCleanup(unlink, self.script_path)
2729

@@ -30,8 +32,8 @@ def cause_exception():
3032
import sys
3133
print(repr(sys.flags.traceback_timestamps))
3234
"""
33-
self.flags_script_path = TESTFN + '_flag.py'
34-
with open(self.flags_script_path, 'w') as script_file:
35+
self.flags_script_path = TESTFN + "_flag.py"
36+
with open(self.flags_script_path, "w") as script_file:
3537
script_file.write(self.flags_script)
3638
self.addCleanup(unlink, self.flags_script_path)
3739

@@ -43,26 +45,34 @@ def test_no_traceback_timestamps(self):
4345

4446
def test_traceback_timestamps_env_var(self):
4547
"""Test that PYTHON_TRACEBACK_TIMESTAMPS env var enables timestamps"""
46-
result = script_helper.assert_python_ok(self.script_path, PYTHON_TRACEBACK_TIMESTAMPS="us")
48+
result = script_helper.assert_python_ok(
49+
self.script_path, PYTHON_TRACEBACK_TIMESTAMPS="us"
50+
)
4751
stderr = result.err.decode()
4852
self.assertIn("<@", stderr) # Timestamp should be present
4953

5054
def test_traceback_timestamps_flag_us(self):
5155
"""Test -X traceback_timestamps=us flag"""
52-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=us", self.script_path)
56+
result = script_helper.assert_python_ok(
57+
"-X", "traceback_timestamps=us", self.script_path
58+
)
5359
stderr = result.err.decode()
5460
self.assertIn("<@", stderr) # Timestamp should be present
5561

5662
def test_traceback_timestamps_flag_ns(self):
5763
"""Test -X traceback_timestamps=ns flag"""
58-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=ns", self.script_path)
64+
result = script_helper.assert_python_ok(
65+
"-X", "traceback_timestamps=ns", self.script_path
66+
)
5967
stderr = result.err.decode()
6068
self.assertIn("<@", stderr) # Timestamp should be present
6169
self.assertIn("ns>", stderr) # Should have ns format
6270

6371
def test_traceback_timestamps_flag_iso(self):
6472
"""Test -X traceback_timestamps=iso flag"""
65-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=iso", self.script_path)
73+
result = script_helper.assert_python_ok(
74+
"-X", "traceback_timestamps=iso", self.script_path
75+
)
6676
stderr = result.err.decode()
6777
self.assertIn("<@", stderr) # Timestamp should be present
6878
# ISO format with Z suffix for UTC
@@ -76,76 +86,190 @@ def test_traceback_timestamps_flag_value(self):
7686
self.assertEqual(stdout, "''")
7787

7888
# With us flag
79-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=us", self.flags_script_path)
89+
result = script_helper.assert_python_ok(
90+
"-X", "traceback_timestamps=us", self.flags_script_path
91+
)
8092
stdout = result.out.decode().strip()
8193
self.assertEqual(stdout, "'us'")
8294

8395
# With ns flag
84-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=ns", self.flags_script_path)
96+
result = script_helper.assert_python_ok(
97+
"-X", "traceback_timestamps=ns", self.flags_script_path
98+
)
8599
stdout = result.out.decode().strip()
86100
self.assertEqual(stdout, "'ns'")
87101

88102
# With iso flag
89-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=iso", self.flags_script_path)
103+
result = script_helper.assert_python_ok(
104+
"-X", "traceback_timestamps=iso", self.flags_script_path
105+
)
90106
stdout = result.out.decode().strip()
91107
self.assertEqual(stdout, "'iso'")
92108

93109
def test_traceback_timestamps_env_var_precedence(self):
94110
"""Test that -X flag takes precedence over env var"""
95-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=us",
96-
"-c", "import sys; print(repr(sys.flags.traceback_timestamps))",
97-
PYTHON_TRACEBACK_TIMESTAMPS="ns")
111+
result = script_helper.assert_python_ok(
112+
"-X",
113+
"traceback_timestamps=us",
114+
"-c",
115+
"import sys; print(repr(sys.flags.traceback_timestamps))",
116+
PYTHON_TRACEBACK_TIMESTAMPS="ns",
117+
)
98118
stdout = result.out.decode().strip()
99119
self.assertEqual(stdout, "'us'")
100-
120+
101121
def test_traceback_timestamps_flag_no_value(self):
102122
"""Test -X traceback_timestamps with no value defaults to 'us'"""
103-
result = script_helper.assert_python_ok("-X", "traceback_timestamps", self.flags_script_path)
123+
result = script_helper.assert_python_ok(
124+
"-X", "traceback_timestamps", self.flags_script_path
125+
)
104126
stdout = result.out.decode().strip()
105127
self.assertEqual(stdout, "'us'")
106-
128+
107129
def test_traceback_timestamps_flag_zero(self):
108130
"""Test -X traceback_timestamps=0 disables the feature"""
109131
# Check that setting to 0 results in empty string in sys.flags
110-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=0", self.flags_script_path)
132+
result = script_helper.assert_python_ok(
133+
"-X", "traceback_timestamps=0", self.flags_script_path
134+
)
111135
stdout = result.out.decode().strip()
112136
self.assertEqual(stdout, "''")
113-
137+
114138
# Check that no timestamps appear in traceback
115-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=0", self.script_path)
139+
result = script_helper.assert_python_ok(
140+
"-X", "traceback_timestamps=0", self.script_path
141+
)
116142
stderr = result.err.decode()
117143
self.assertNotIn("<@", stderr) # No timestamp should be present
118-
144+
119145
def test_traceback_timestamps_flag_one(self):
120146
"""Test -X traceback_timestamps=1 is equivalent to 'us'"""
121-
result = script_helper.assert_python_ok("-X", "traceback_timestamps=1", self.flags_script_path)
147+
result = script_helper.assert_python_ok(
148+
"-X", "traceback_timestamps=1", self.flags_script_path
149+
)
122150
stdout = result.out.decode().strip()
123151
self.assertEqual(stdout, "'us'")
124-
152+
125153
def test_traceback_timestamps_env_var_zero(self):
126154
"""Test PYTHON_TRACEBACK_TIMESTAMPS=0 disables the feature"""
127-
result = script_helper.assert_python_ok(self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="0")
155+
result = script_helper.assert_python_ok(
156+
self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="0"
157+
)
128158
stdout = result.out.decode().strip()
129159
self.assertEqual(stdout, "''")
130-
160+
131161
def test_traceback_timestamps_env_var_one(self):
132162
"""Test PYTHON_TRACEBACK_TIMESTAMPS=1 is equivalent to 'us'"""
133-
result = script_helper.assert_python_ok(self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="1")
163+
result = script_helper.assert_python_ok(
164+
self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="1"
165+
)
134166
stdout = result.out.decode().strip()
135167
self.assertEqual(stdout, "'us'")
136-
168+
137169
def test_traceback_timestamps_invalid_env_var(self):
138170
"""Test that invalid env var values are silently ignored"""
139-
result = script_helper.assert_python_ok(self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="invalid")
171+
result = script_helper.assert_python_ok(
172+
self.flags_script_path, PYTHON_TRACEBACK_TIMESTAMPS="invalid"
173+
)
140174
stdout = result.out.decode().strip()
141175
self.assertEqual(stdout, "''") # Should default to empty string
142-
176+
143177
def test_traceback_timestamps_invalid_flag(self):
144178
"""Test that invalid flag values cause an error"""
145-
result = script_helper.assert_python_failure("-X", "traceback_timestamps=invalid", self.flags_script_path)
179+
result = script_helper.assert_python_failure(
180+
"-X", "traceback_timestamps=invalid", self.flags_script_path
181+
)
146182
stderr = result.err.decode()
147183
self.assertIn("Invalid -X traceback_timestamps=value option", stderr)
148184

149185

186+
class StripExcTimestampsTests(unittest.TestCase):
187+
"""Tests for traceback.strip_exc_timestamps function"""
188+
189+
def setUp(self):
190+
self.script_strip_test = r"""
191+
import sys
192+
import traceback
193+
194+
def error():
195+
print("FakeError: not an exception <@1234567890.123456>\n")
196+
3/0
197+
198+
def strip(data):
199+
print(traceback.strip_exc_timestamps(data))
200+
201+
if __name__ == "__main__":
202+
if len(sys.argv) <= 1:
203+
error()
204+
else:
205+
strip(sys.argv[1])
206+
"""
207+
self.script_strip_path = TESTFN + "_strip.py"
208+
with open(self.script_strip_path, "w") as script_file:
209+
script_file.write(self.script_strip_test)
210+
self.addCleanup(unlink, self.script_strip_path)
211+
212+
def test_strip_exc_timestamps_function(self):
213+
"""Test the strip_exc_timestamps function with various inputs"""
214+
for mode in ("us", "ns", "iso"):
215+
with self.subTest(mode):
216+
result = script_helper.assert_python_failure(
217+
"-X", f"traceback_timestamps={mode}", self.script_strip_path
218+
)
219+
output = result.out.decode() + result.err.decode()
220+
221+
# call strip_exc_timestamps in a process using the same mode as what generated our output.
222+
result = script_helper.assert_python_ok(
223+
"-X", f"traceback_timestamps={mode}", self.script_strip_path, output
224+
)
225+
stripped_output = result.out.decode() + result.err.decode()
226+
227+
# Verify original strings have timestamps and stripped ones don't
228+
self.assertIn("ZeroDivisionError: division by zero <@", output)
229+
self.assertNotIn("ZeroDivisionError: division by zero\n", output)
230+
self.assertIn("ZeroDivisionError: division by zero\n", stripped_output)
231+
self.assertIn("FakeError: not an exception\n", stripped_output)
232+
233+
def test_strip_exc_timestamps_with_disabled_timestamps(self):
234+
"""Test the strip_exc_timestamps function when timestamps are disabled"""
235+
# Run with timestamps disabled
236+
result = script_helper.assert_python_failure(
237+
"-X", "traceback_timestamps=0", self.script_strip_path
238+
)
239+
output = result.out.decode() + result.err.decode()
240+
241+
# call strip_exc_timestamps in a process using the same mode as what generated our output.
242+
result = script_helper.assert_python_ok(
243+
"-X", "traceback_timestamps=0", self.script_strip_path, output
244+
)
245+
stripped_output = result.out.decode() + result.err.decode()
246+
247+
# All strings should be unchanged by the strip function
248+
self.assertIn("ZeroDivisionError: division by zero\n", stripped_output)
249+
# it fits the pattern but traceback timestamps were disabled to strip_exc_timestamps does nothing.
250+
self.assertIn(
251+
"FakeError: not an exception <@1234567890.123456>\n", stripped_output
252+
)
253+
254+
def test_timestamp_regex_pattern(self):
255+
"""Test the regex pattern used by strip_exc_timestamps"""
256+
# Get the pattern from traceback module
257+
from traceback import TIMESTAMP_AFTER_EXC_MSG_RE_GROUP
258+
259+
pattern = re.compile(TIMESTAMP_AFTER_EXC_MSG_RE_GROUP)
260+
261+
# Test microsecond format
262+
self.assertTrue(pattern.search(" <@1234567890.123456>"))
263+
# Test nanosecond format
264+
self.assertTrue(pattern.search(" <@1234567890123456789ns>"))
265+
# Test ISO format
266+
self.assertTrue(pattern.search(" <@2023-04-13T12:34:56.789012Z>"))
267+
268+
# Test what should not match
269+
self.assertFalse(pattern.search("<@>")) # Empty timestamp
270+
self.assertFalse(pattern.search(" <1234567890.123456>")) # Missing @ sign
271+
self.assertFalse(pattern.search("<@abc>")) # Non-numeric timestamp
272+
273+
150274
if __name__ == "__main__":
151275
unittest.main()

Lib/traceback.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def _timestamp_formatter(ns):
205205

206206
# The regular expression to match timestamps as formatted in tracebacks.
207207
# Not compiled to avoid importing the re module by default.
208-
TIMESTAMP_AFTER_EXC_MSG_RE_GROUP = r"(?P<timestamp> <@[0-9:.Tsnu-]{18,26}Z?>)"
208+
TIMESTAMP_AFTER_EXC_MSG_RE_GROUP = r"(?P<timestamp> <@[0-9:.Tsnu-]{17,26}Z?>)"
209209

210210

211211
def strip_exc_timestamps(output):

0 commit comments

Comments
 (0)