|
18 | 18 | from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, |
19 | 19 | requires_debug_ranges, has_no_debug_ranges, |
20 | 20 | requires_subprocess) |
21 | | -from test.support.os_helper import TESTFN, unlink |
| 21 | +from test.support.os_helper import TESTFN, temp_dir, unlink |
22 | 22 | from test.support.script_helper import assert_python_ok, assert_python_failure, make_script |
23 | 23 | from test.support.import_helper import forget |
24 | 24 | from test.support import force_not_colorized, force_not_colorized_test_class |
@@ -524,6 +524,33 @@ def __del__(self): |
524 | 524 | b'ZeroDivisionError: division by zero'] |
525 | 525 | self.assertEqual(stderr.splitlines(), expected) |
526 | 526 |
|
| 527 | + @cpython_only |
| 528 | + def test_lost_io_open(self): |
| 529 | + # GH-142737: Display the traceback even if io.open is lost |
| 530 | + crasher = textwrap.dedent("""\ |
| 531 | + import io |
| 532 | + import traceback |
| 533 | + # Trigger fallback mode |
| 534 | + traceback._print_exception_bltin = None |
| 535 | + del io.open |
| 536 | + raise RuntimeError("should not crash") |
| 537 | + """) |
| 538 | + |
| 539 | + # Create a temporary script to exercise _Py_FindSourceFile |
| 540 | + with temp_dir() as script_dir: |
| 541 | + script = make_script( |
| 542 | + script_dir=script_dir, |
| 543 | + script_basename='tb_test_no_io_open', |
| 544 | + source=crasher) |
| 545 | + rc, stdout, stderr = assert_python_failure(script) |
| 546 | + |
| 547 | + self.assertEqual(rc, 1) # Make sure it's not a crash |
| 548 | + |
| 549 | + expected = [b'Traceback (most recent call last):', |
| 550 | + f' File "{script}", line 6, in <module>'.encode(), |
| 551 | + b'RuntimeError: should not crash'] |
| 552 | + self.assertEqual(stderr.splitlines(), expected) |
| 553 | + |
527 | 554 | def test_print_exception(self): |
528 | 555 | output = StringIO() |
529 | 556 | traceback.print_exception( |
|
0 commit comments