@@ -589,13 +589,43 @@ def test_unbounded_file(self):
589
589
with self .open (zero , "r" ) as f :
590
590
self .assertRaises (OverflowError , f .read )
591
591
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 = []
594
597
def bad_flush ():
598
+ closed [:] = [f .closed ]
595
599
raise OSError ()
596
600
f .flush = bad_flush
597
601
self .assertRaises (OSError , f .close ) # exception not swallowed
598
602
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 )
599
629
600
630
def test_multi_close (self ):
601
631
f = self .open (support .TESTFN , "wb" , buffering = 0 )
@@ -784,13 +814,21 @@ def test_repr(self):
784
814
self .assertEqual (repr (b ), "<%s name=b'dummy'>" % clsname )
785
815
786
816
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.
787
819
raw = self .MockRawIO ()
820
+ closed = []
788
821
def bad_flush ():
822
+ closed [:] = [b .closed , raw .closed ]
789
823
raise OSError ()
790
824
raw .flush = bad_flush
791
825
b = self .tp (raw )
792
826
self .assertRaises (OSError , b .close ) # exception not swallowed
793
827
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 ])
794
832
795
833
def test_close_error_on_close (self ):
796
834
raw = self .MockRawIO ()
@@ -2679,12 +2717,20 @@ def run(n):
2679
2717
self .assertEqual (content .count ("Thread%03d\n " % n ), 1 )
2680
2718
2681
2719
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.
2682
2722
txt = self .TextIOWrapper (self .BytesIO (self .testdata ), encoding = "ascii" )
2723
+ closed = []
2683
2724
def bad_flush ():
2725
+ closed [:] = [txt .closed , txt .buffer .closed ]
2684
2726
raise OSError ()
2685
2727
txt .flush = bad_flush
2686
2728
self .assertRaises (OSError , txt .close ) # exception not swallowed
2687
2729
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 ])
2688
2734
2689
2735
def test_close_error_on_close (self ):
2690
2736
buffer = self .BytesIO (self .testdata )
0 commit comments