@@ -67,9 +67,9 @@ class EmptyStruct(ctypes.Structure):
6767 '--with-memory-sanitizer' in _config_args
6868)
6969
70- # Does io.IOBase logs unhandled exceptions on calling close()?
71- # They are silenced by default in release build.
72- DESTRUCTOR_LOG_ERRORS = (hasattr (sys , "gettotalrefcount" ) or sys .flags .dev_mode )
70+ # Does io.IOBase finalizer log the exception if the close() method fails ?
71+ # The exception is ignored silently by default in release build.
72+ IOBASE_EMITS_UNRAISABLE = (hasattr (sys , "gettotalrefcount" ) or sys .flags .dev_mode )
7373
7474
7575def _default_chunk_size ():
@@ -1098,23 +1098,18 @@ def test_error_through_destructor(self):
10981098 # Test that the exception state is not modified by a destructor,
10991099 # even if close() fails.
11001100 rawio = self .CloseFailureIO ()
1101- def f ():
1102- self .tp (rawio ).xyzzy
1103- with support .captured_output ("stderr" ) as s :
1104- self .assertRaises (AttributeError , f )
1105- s = s .getvalue ().strip ()
1106- if s :
1107- # The destructor *may* have printed an unraisable error, check it
1108- lines = s .splitlines ()
1109- if DESTRUCTOR_LOG_ERRORS :
1110- self .assertEqual (len (lines ), 5 )
1111- self .assertTrue (lines [0 ].startswith ("Exception ignored in: " ), lines )
1112- self .assertEqual (lines [1 ], "Traceback (most recent call last):" , lines )
1113- self .assertEqual (lines [4 ], 'OSError:' , lines )
1114- else :
1115- self .assertEqual (len (lines ), 1 )
1116- self .assertTrue (lines [- 1 ].startswith ("Exception OSError: " ), lines )
1117- self .assertTrue (lines [- 1 ].endswith (" ignored" ), lines )
1101+ try :
1102+ with support .catch_unraisable_exception () as cm :
1103+ with self .assertRaises (AttributeError ):
1104+ self .tp (rawio ).xyzzy
1105+
1106+ if not IOBASE_EMITS_UNRAISABLE :
1107+ self .assertIsNone (cm .unraisable )
1108+ elif cm .unraisable is not None :
1109+ self .assertEqual (cm .unraisable .exc_type , OSError )
1110+ finally :
1111+ # Explicitly break reference cycle
1112+ cm = None
11181113
11191114 def test_repr (self ):
11201115 raw = self .MockRawIO ()
@@ -2859,23 +2854,18 @@ def test_error_through_destructor(self):
28592854 # Test that the exception state is not modified by a destructor,
28602855 # even if close() fails.
28612856 rawio = self .CloseFailureIO ()
2862- def f ():
2863- self .TextIOWrapper (rawio ).xyzzy
2864- with support .captured_output ("stderr" ) as s :
2865- self .assertRaises (AttributeError , f )
2866- s = s .getvalue ().strip ()
2867- if s :
2868- # The destructor *may* have printed an unraisable error, check it
2869- lines = s .splitlines ()
2870- if DESTRUCTOR_LOG_ERRORS :
2871- self .assertEqual (len (lines ), 5 )
2872- self .assertTrue (lines [0 ].startswith ("Exception ignored in: " ), lines )
2873- self .assertEqual (lines [1 ], "Traceback (most recent call last):" , lines )
2874- self .assertEqual (lines [4 ], 'OSError:' , lines )
2875- else :
2876- self .assertEqual (len (lines ), 1 )
2877- self .assertTrue (lines [- 1 ].startswith ("Exception OSError: " ), lines )
2878- self .assertTrue (lines [- 1 ].endswith (" ignored" ), lines )
2857+ try :
2858+ with support .catch_unraisable_exception () as cm :
2859+ with self .assertRaises (AttributeError ):
2860+ self .TextIOWrapper (rawio ).xyzzy
2861+
2862+ if not IOBASE_EMITS_UNRAISABLE :
2863+ self .assertIsNone (cm .unraisable )
2864+ elif cm .unraisable is not None :
2865+ self .assertEqual (cm .unraisable .exc_type , OSError )
2866+ finally :
2867+ # Explicitly break reference cycle
2868+ cm = None
28792869
28802870 # Systematic tests of the text I/O API
28812871
0 commit comments