@@ -67,9 +67,9 @@ class EmptyStruct(ctypes.Structure):
67
67
'--with-memory-sanitizer' in _config_args
68
68
)
69
69
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 )
73
73
74
74
75
75
def _default_chunk_size ():
@@ -1098,23 +1098,18 @@ def test_error_through_destructor(self):
1098
1098
# Test that the exception state is not modified by a destructor,
1099
1099
# even if close() fails.
1100
1100
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
1118
1113
1119
1114
def test_repr (self ):
1120
1115
raw = self .MockRawIO ()
@@ -2859,23 +2854,18 @@ def test_error_through_destructor(self):
2859
2854
# Test that the exception state is not modified by a destructor,
2860
2855
# even if close() fails.
2861
2856
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
2879
2869
2880
2870
# Systematic tests of the text I/O API
2881
2871
0 commit comments