@@ -18,7 +18,7 @@
1818fromtest.supportimport (Error, captured_output, cpython_only, ALWAYS_EQ,
1919requires_debug_ranges, has_no_debug_ranges,
2020requires_subprocess)
21-fromtest.support.os_helperimportTESTFN, unlink
21+fromtest.support.os_helperimportTESTFN, temp_dir, unlink
2222fromtest.support.script_helperimportassert_python_ok, assert_python_failure, make_script
2323fromtest.support.import_helperimportforget
2424fromtest.supportimportforce_not_colorized, force_not_colorized_test_class
@@ -524,6 +524,33 @@ def __del__(self):
524524b'ZeroDivisionError: division by zero']
525525self.assertEqual(stderr.splitlines(), expected)
526526527+@cpython_only
528+deftest_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+withtemp_dir() asscript_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+527554deftest_print_exception(self):
528555output=StringIO()
529556traceback.print_exception(