@@ -589,13 +589,43 @@ def test_unbounded_file(self):
589589 with self .open (zero , "r" ) as f :
590590 self .assertRaises (OverflowError , f .read )
591591
592- def test_flush_error_on_close (self ):
593- f = self .open (support .TESTFN , "wb" , buffering = 0 )
592+ def check_flush_error_on_close (self , * args , ** kwargs ):
593+ # Test that the file is closed despite failed flush
594+ # and that flush() is called before file closed.
595+ f = self .open (* args , ** kwargs )
596+ closed = []
594597 def bad_flush ():
598+ closed [:] = [f .closed ]
595599 raise OSError ()
596600 f .flush = bad_flush
597601 self .assertRaises (OSError , f .close ) # exception not swallowed
598602 self .assertTrue (f .closed )
603+ self .assertTrue (closed ) # flush() called
604+ self .assertFalse (closed [0 ]) # flush() called before file closed
605+
606+ def test_flush_error_on_close (self ):
607+ # raw file
608+ # Issue #5700: io.FileIO calls flush() after file closed
609+ self .check_flush_error_on_close (support .TESTFN , 'wb' , buffering = 0 )
610+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
611+ self .check_flush_error_on_close (fd , 'wb' , buffering = 0 )
612+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
613+ self .check_flush_error_on_close (fd , 'wb' , buffering = 0 , closefd = False )
614+ os .close (fd )
615+ # buffered io
616+ self .check_flush_error_on_close (support .TESTFN , 'wb' )
617+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
618+ self .check_flush_error_on_close (fd , 'wb' )
619+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
620+ self .check_flush_error_on_close (fd , 'wb' , closefd = False )
621+ os .close (fd )
622+ # text io
623+ self .check_flush_error_on_close (support .TESTFN , 'w' )
624+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
625+ self .check_flush_error_on_close (fd , 'w' )
626+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
627+ self .check_flush_error_on_close (fd , 'w' , closefd = False )
628+ os .close (fd )
599629
600630 def test_multi_close (self ):
601631 f = self .open (support .TESTFN , "wb" , buffering = 0 )
@@ -784,13 +814,21 @@ def test_repr(self):
784814 self .assertEqual (repr (b ), "<%s name=b'dummy'>" % clsname )
785815
786816 def test_flush_error_on_close (self ):
817+ # Test that buffered file is closed despite failed flush
818+ # and that flush() is called before file closed.
787819 raw = self .MockRawIO ()
820+ closed = []
788821 def bad_flush ():
822+ closed [:] = [b .closed , raw .closed ]
789823 raise OSError ()
790824 raw .flush = bad_flush
791825 b = self .tp (raw )
792826 self .assertRaises (OSError , b .close ) # exception not swallowed
793827 self .assertTrue (b .closed )
828+ self .assertTrue (raw .closed )
829+ self .assertTrue (closed ) # flush() called
830+ self .assertFalse (closed [0 ]) # flush() called before file closed
831+ self .assertFalse (closed [1 ])
794832
795833 def test_close_error_on_close (self ):
796834 raw = self .MockRawIO ()
@@ -2679,12 +2717,20 @@ def run(n):
26792717 self .assertEqual (content .count ("Thread%03d\n " % n ), 1 )
26802718
26812719 def test_flush_error_on_close (self ):
2720+ # Test that text file is closed despite failed flush
2721+ # and that flush() is called before file closed.
26822722 txt = self .TextIOWrapper (self .BytesIO (self .testdata ), encoding = "ascii" )
2723+ closed = []
26832724 def bad_flush ():
2725+ closed [:] = [txt .closed , txt .buffer .closed ]
26842726 raise OSError ()
26852727 txt .flush = bad_flush
26862728 self .assertRaises (OSError , txt .close ) # exception not swallowed
26872729 self .assertTrue (txt .closed )
2730+ self .assertTrue (txt .buffer .closed )
2731+ self .assertTrue (closed ) # flush() called
2732+ self .assertFalse (closed [0 ]) # flush() called before file closed
2733+ self .assertFalse (closed [1 ])
26882734
26892735 def test_close_error_on_close (self ):
26902736 buffer = self .BytesIO (self .testdata )
0 commit comments