@@ -593,13 +593,43 @@ def test_unbounded_file(self):
593593 with self .open (zero , "r" ) as f :
594594 self .assertRaises (OverflowError , f .read )
595595
596- def test_flush_error_on_close (self ):
597- f = self .open (support .TESTFN , "wb" , buffering = 0 )
596+ def check_flush_error_on_close (self , * args , ** kwargs ):
597+ # Test that the file is closed despite failed flush
598+ # and that flush() is called before file closed.
599+ f = self .open (* args , ** kwargs )
600+ closed = []
598601 def bad_flush ():
602+ closed [:] = [f .closed ]
599603 raise OSError ()
600604 f .flush = bad_flush
601605 self .assertRaises (OSError , f .close ) # exception not swallowed
602606 self .assertTrue (f .closed )
607+ self .assertTrue (closed ) # flush() called
608+ self .assertFalse (closed [0 ]) # flush() called before file closed
609+
610+ def test_flush_error_on_close (self ):
611+ # raw file
612+ # Issue #5700: io.FileIO calls flush() after file closed
613+ self .check_flush_error_on_close (support .TESTFN , 'wb' , buffering = 0 )
614+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
615+ self .check_flush_error_on_close (fd , 'wb' , buffering = 0 )
616+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
617+ self .check_flush_error_on_close (fd , 'wb' , buffering = 0 , closefd = False )
618+ os .close (fd )
619+ # buffered io
620+ self .check_flush_error_on_close (support .TESTFN , 'wb' )
621+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
622+ self .check_flush_error_on_close (fd , 'wb' )
623+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
624+ self .check_flush_error_on_close (fd , 'wb' , closefd = False )
625+ os .close (fd )
626+ # text io
627+ self .check_flush_error_on_close (support .TESTFN , 'w' )
628+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
629+ self .check_flush_error_on_close (fd , 'w' )
630+ fd = os .open (support .TESTFN , os .O_WRONLY | os .O_CREAT )
631+ self .check_flush_error_on_close (fd , 'w' , closefd = False )
632+ os .close (fd )
603633
604634 def test_multi_close (self ):
605635 f = self .open (support .TESTFN , "wb" , buffering = 0 )
@@ -788,13 +818,21 @@ def test_repr(self):
788818 self .assertEqual (repr (b ), "<%s name=b'dummy'>" % clsname )
789819
790820 def test_flush_error_on_close (self ):
821+ # Test that buffered file is closed despite failed flush
822+ # and that flush() is called before file closed.
791823 raw = self .MockRawIO ()
824+ closed = []
792825 def bad_flush ():
826+ closed [:] = [b .closed , raw .closed ]
793827 raise OSError ()
794828 raw .flush = bad_flush
795829 b = self .tp (raw )
796830 self .assertRaises (OSError , b .close ) # exception not swallowed
797831 self .assertTrue (b .closed )
832+ self .assertTrue (raw .closed )
833+ self .assertTrue (closed ) # flush() called
834+ self .assertFalse (closed [0 ]) # flush() called before file closed
835+ self .assertFalse (closed [1 ])
798836
799837 def test_close_error_on_close (self ):
800838 raw = self .MockRawIO ()
@@ -2618,12 +2656,20 @@ def run(n):
26182656 self .assertEqual (content .count ("Thread%03d\n " % n ), 1 )
26192657
26202658 def test_flush_error_on_close (self ):
2659+ # Test that text file is closed despite failed flush
2660+ # and that flush() is called before file closed.
26212661 txt = self .TextIOWrapper (self .BytesIO (self .testdata ), encoding = "ascii" )
2662+ closed = []
26222663 def bad_flush ():
2664+ closed [:] = [txt .closed , txt .buffer .closed ]
26232665 raise OSError ()
26242666 txt .flush = bad_flush
26252667 self .assertRaises (OSError , txt .close ) # exception not swallowed
26262668 self .assertTrue (txt .closed )
2669+ self .assertTrue (txt .buffer .closed )
2670+ self .assertTrue (closed ) # flush() called
2671+ self .assertFalse (closed [0 ]) # flush() called before file closed
2672+ self .assertFalse (closed [1 ])
26272673
26282674 def test_close_error_on_close (self ):
26292675 buffer = self .BytesIO (self .testdata )
0 commit comments