@@ -692,28 +692,31 @@ def test_iterparse(self):
692692 it = iterparse (TESTFN )
693693 action , elem = next (it )
694694 self .assertEqual ((action , elem .tag ), ('end' , 'document' ))
695- with warnings_helper . check_no_resource_warning ( self ) :
696- with self . assertRaises ( ET . ParseError ) as cm :
697- next ( it )
698- self . assertEqual ( str ( cm . exception ),
699- 'junk after document element: line 1, column 12' )
700- del cm , it
695+ with self . assertRaises ( ET . ParseError ) as cm :
696+ next ( it )
697+ self . assertEqual ( str ( cm . exception ),
698+ 'junk after document element: line 1, column 12' )
699+ it . close () # Close to avoid ResourceWarning
700+ del cm , it
701701
702- # Not exhausting the iterator still closes the resource (bpo-43292)
703- with warnings_helper .check_no_resource_warning (self ):
704- it = iterparse (SIMPLE_XMLFILE )
705- del it
702+ # Deleting iterator without close() should emit ResourceWarning (bpo-43292)
703+ it = iterparse (SIMPLE_XMLFILE )
704+ del it
705+ import gc
706+ gc .collect () # Ensure previous iterator is cleaned up
706707
708+ # Explicitly calling close() should not emit warning
707709 with warnings_helper .check_no_resource_warning (self ):
708710 it = iterparse (SIMPLE_XMLFILE )
709711 it .close ()
710712 del it
711713
712- with warnings_helper .check_no_resource_warning (self ):
713- it = iterparse (SIMPLE_XMLFILE )
714- action , elem = next (it )
715- self .assertEqual ((action , elem .tag ), ('end' , 'element' ))
716- del it , elem
714+ # Not closing before del should emit ResourceWarning
715+ it = iterparse (SIMPLE_XMLFILE )
716+ action , elem = next (it )
717+ self .assertEqual ((action , elem .tag ), ('end' , 'element' ))
718+ del it , elem
719+ gc .collect () # Ensure previous iterator is cleaned up
717720
718721 with warnings_helper .check_no_resource_warning (self ):
719722 it = iterparse (SIMPLE_XMLFILE )
@@ -725,6 +728,63 @@ def test_iterparse(self):
725728 with self .assertRaises (FileNotFoundError ):
726729 iterparse ("nonexistent" )
727730
731+ def test_iterparse_resource_warning (self ):
732+ # Test ResourceWarning when iterparse with filename is not closed
733+ import gc
734+ import warnings
735+
736+ # Should emit warning when not closed
737+ with warnings .catch_warnings (record = True ) as w :
738+ warnings .simplefilter ("always" , ResourceWarning )
739+
740+ def create_unclosed ():
741+ context = ET .iterparse (SIMPLE_XMLFILE )
742+ next (context )
743+ # Don't close - should warn
744+
745+ create_unclosed ()
746+ gc .collect ()
747+
748+ resource_warnings = [x for x in w
749+ if issubclass (x .category , ResourceWarning )]
750+ self .assertGreater (len (resource_warnings ), 0 ,
751+ "Expected ResourceWarning when iterparse is not closed" )
752+
753+ # Should NOT warn when explicitly closed
754+ with warnings .catch_warnings (record = True ) as w :
755+ warnings .simplefilter ("always" , ResourceWarning )
756+
757+ def create_closed ():
758+ context = ET .iterparse (SIMPLE_XMLFILE )
759+ next (context )
760+ context .close ()
761+
762+ create_closed ()
763+ gc .collect ()
764+
765+ resource_warnings = [x for x in w
766+ if issubclass (x .category , ResourceWarning )]
767+ self .assertEqual (len (resource_warnings ), 0 ,
768+ "No warning expected when iterparse is properly closed" )
769+
770+ # Should NOT warn for file objects (externally managed)
771+ with open (SIMPLE_XMLFILE , 'rb' ) as source :
772+ with warnings .catch_warnings (record = True ) as w :
773+ warnings .simplefilter ("always" , ResourceWarning )
774+
775+ def create_with_fileobj ():
776+ context = ET .iterparse (source )
777+ next (context )
778+ # Don't close - file object managed externally
779+
780+ create_with_fileobj ()
781+ gc .collect ()
782+
783+ resource_warnings = [x for x in w
784+ if issubclass (x .category , ResourceWarning )]
785+ self .assertEqual (len (resource_warnings ), 0 ,
786+ "No warning for file objects managed externally" )
787+
728788 def test_iterparse_close (self ):
729789 iterparse = ET .iterparse
730790
0 commit comments