@@ -296,6 +296,51 @@ def test_truncating_filehandle_iter(self):
296296 self ._run_truncating_file_handle_iter_test ('aaa b cccccccccccccccccccc' )
297297 self ._run_truncating_file_handle_iter_test ('aaa b ccccccccccccccccc ' )
298298
299+ def test_truncating_filehandle_flush_on_closed_stream (self ):
300+ class ClosedFlushingStream (StringIO ):
301+ def flush (self ):
302+ if self .closed :
303+ raise ValueError ("I/O operation on closed file." )
304+ super ().flush ()
305+
306+ s = 'a b c'
307+ tracker = restriction_trackers .OffsetRestrictionTracker (
308+ restriction_trackers .OffsetRange (0 , len (s )))
309+ underlying = ClosedFlushingStream (s )
310+ handle = io ._TruncatingFileHandle (
311+ underlying , tracker , splitter = io ._DelimSplitter (' ' , 10 ))
312+
313+ # Verify that calling flush() when the underlying stream is closed
314+ # succeeds without raising ValueError.
315+ underlying .close ()
316+ handle .flush ()
317+ handle .close ()
318+
319+ def test_truncating_filehandle_exception_suppression (self ):
320+ class FaultyStream (StringIO ):
321+ @property
322+ def closed (self ):
323+ return False
324+
325+ def flush (self ):
326+ raise ValueError ("Simulated flush error" )
327+
328+ def close (self ):
329+ raise OSError ("Simulated close error" )
330+
331+ s = 'a b c'
332+ tracker = restriction_trackers .OffsetRestrictionTracker (
333+ restriction_trackers .OffsetRange (0 , len (s )))
334+ underlying = FaultyStream (s )
335+ handle = io ._TruncatingFileHandle (
336+ underlying , tracker , splitter = io ._DelimSplitter (' ' , 10 ))
337+
338+ # Verify that ValueError raised during flush() is safely suppressed.
339+ handle .flush ()
340+
341+ # Verify that OSError raised during close() is safely suppressed.
342+ handle .close ()
343+
299344 @parameterized .expand ([
300345 ('defaults' , {}),
301346 ('header' , dict (header = 1 )),
0 commit comments