@@ -2812,17 +2812,17 @@ class Y(X, ET.Element):
28122812 def test_remove_with_clear_assume_missing (self ):
28132813 # gh-126033: Check that a concurrent clear() for an assumed-to-be
28142814 # missing element does not make the interpreter crash.
2815- self .do_test_remove_with_clear (raises = True )
2815+ self .do_test_remove_with_clear (existing = False )
28162816
28172817 def test_remove_with_clear_assume_existing (self ):
28182818 # gh-126033: Check that a concurrent clear() for an assumed-to-be
28192819 # existing element raises RuntimeError but does not crash.
2820- self .do_test_remove_with_clear (raises = False )
2820+ self .do_test_remove_with_clear (existing = True )
28212821
2822- def do_test_remove_with_clear (self , * , raises ):
2822+ def do_test_remove_with_clear (self , * , existing ):
28232823 # 'del root[:]' mutates the children list in-place, while
28242824 # 'root.clear()' replaces self._children with a new list. When
2825- # raises=False (element "found"), the in-place mutation is detected
2825+ # existing=True (element "found"), the in-place mutation is detected
28262826 # by list.remove and raises RuntimeError, whereas root.clear() is
28272827 # invisible to list.remove (the old list is unchanged).
28282828
@@ -2832,12 +2832,12 @@ class E(ET.Element):
28322832 class X (E ):
28332833 def __eq__ (self , o ):
28342834 del root [:]
2835- return not raises
2835+ return existing
28362836
28372837 class Y (E ):
28382838 def __eq__ (self , o ):
28392839 root .clear ()
2840- return not raises
2840+ return existing
28412841
28422842 self .assertIs (E .__eq__ , object .__eq__ )
28432843
@@ -2846,12 +2846,14 @@ def __eq__(self, o):
28462846 self .enterContext (self .subTest (side_effect = side_effect ))
28472847
28482848 # X uses 'del root[:]' which mutates the list in-place; this is
2849- # detected by list.remove when raises=False (element "found").
2849+ # detected by list.remove (pure Python implementation) when existing=False.
2850+ # The C implementation does not detect this mutation and silently
2851+ # returns None.
28502852 # Y uses 'root.clear()' which swaps out self._children; the old
28512853 # list that list.remove is iterating is untouched, so no error.
2852- if raises :
2854+ if not existing :
28532855 get_checker_context = lambda : self .assertRaises (ValueError )
2854- elif Z is X :
2856+ elif Z is X and is_python_implementation () :
28552857 get_checker_context = lambda : self .assertRaises (RuntimeError )
28562858 else :
28572859 get_checker_context = nullcontext
@@ -2890,7 +2892,7 @@ def __eq__(self, o):
28902892 g .assert_not_called ()
28912893
28922894 # Test removing root[1] (of type R) from [U(), R()].
2893- if is_python_implementation () and raises and Z is Y :
2895+ if is_python_implementation () and not existing and Z is Y :
28942896 # In pure Python, using root.clear() sets the children
28952897 # list to [] without calling list.clear().
28962898 #
@@ -2915,25 +2917,32 @@ def __eq__(self, o):
29152917 def test_remove_with_mutate_root_assume_missing (self ):
29162918 # gh-126033: Check that a concurrent mutation for an assumed-to-be
29172919 # missing element does not make the interpreter crash.
2918- self .do_test_remove_with_mutate_root (raises = True )
2920+ self .do_test_remove_with_mutate_root (existing = False )
29192921
29202922 def test_remove_with_mutate_root_assume_existing (self ):
29212923 # gh-126033: Check that a concurrent mutation for an assumed-to-be
2922- # existing element raises RuntimeError.
2923- self .do_test_remove_with_mutate_root (raises = False )
2924+ # existing element raises RuntimeError when using the pure Python
2925+ # implementation; the C implementation silently returns None).
2926+ self .do_test_remove_with_mutate_root (existing = True )
29242927
2925- def do_test_remove_with_mutate_root (self , * , raises ):
2928+ def do_test_remove_with_mutate_root (self , * , existing ):
29262929 E = ET .Element
29272930
29282931 class Z (E ):
29292932 def __eq__ (self , o ):
29302933 del root [0 ]
2931- return not raises
2934+ return existing
29322935
2933- if raises :
2936+ if not existing :
29342937 get_checker_context = lambda : self .assertRaises (ValueError )
2935- else :
2938+ elif is_python_implementation ():
2939+ # The Python implementation is based on list.remove, which raises
2940+ # RuntimeError if the list is mutated during the __eq__ comparison.
29362941 get_checker_context = lambda : self .assertRaises (RuntimeError )
2942+ else :
2943+ # The C implementation does not detect in-place mutations during
2944+ # remove and silently returns None.
2945+ get_checker_context = nullcontext
29372946
29382947 # test removing R() from [U(), V()]
29392948 cases = self .cases_for_remove_missing_with_mutations (E , Z )
0 commit comments