@@ -733,21 +733,27 @@ class CxWrapper:
733733 def __init__ (self , cx ):
734734 self .cx = cx
735735
736+ def side_effect (self ):
737+ self .cx .close ()
736738
737- class EvilParamsWithIter (CxWrapper ):
738739
740+ class ParamsCxCloseInIterMany (CxWrapper ):
739741 def __iter__ (self ):
740- self .cx . close ()
741- return iter ([(1 ,)])
742+ self .side_effect ()
743+ return iter ([(1 ,), ( 2 ,), ( 3 ,) ])
742744
743745
744- class EvilParamsWithNext (CxWrapper ):
746+ class ParamsCxCloseInNext (CxWrapper ):
747+ def __init__ (self , cx ):
748+ super ().__init__ (cx )
749+ self .r = iter (range (10 ))
750+
745751 def __iter__ (self ):
746752 return self
747753
748754 def __next__ (self ):
749- self .cx . close ()
750- return (1 ,)
755+ self .side_effect ()
756+ return (next ( self . r ) ,)
751757
752758
753759class CursorTests (unittest .TestCase ):
@@ -764,16 +770,6 @@ def tearDown(self):
764770 self .cu .close ()
765771 self .cx .close ()
766772
767- def do_test_connection_use_after_close (self , method_name , params_class ):
768- # Prevent SIGSEGV with iterable of parameters closing the connection.
769- # Regression test for https://github.com/python/cpython/issues/143198.
770- cx = sqlite .connect (":memory:" )
771- self .addCleanup (cx .close )
772- cu = cx .cursor ()
773- params = params_class (cx )
774- method = operator .methodcaller (method_name , "SELECT ?" , params )
775- self .assertRaises (sqlite .ProgrammingError , method , cu )
776-
777773 def test_execute_no_args (self ):
778774 self .cu .execute ("delete from test" )
779775
@@ -845,10 +841,6 @@ def test_execute_non_iterable(self):
845841 self .cu .execute ("insert into test(id) values (?)" , 42 )
846842 self .assertEqual (str (cm .exception ), 'parameters are of unsupported type' )
847843
848- @subTests ("params_class" , (EvilParamsWithIter , EvilParamsWithNext ))
849- def test_execute_use_after_close (self , params_class ):
850- self .do_test_connection_use_after_close ("execute" , params_class )
851-
852844 def test_execute_wrong_no_of_args1 (self ):
853845 # too many parameters
854846 with self .assertRaises (sqlite .ProgrammingError ):
@@ -1066,9 +1058,17 @@ def test_execute_many_not_iterable(self):
10661058 with self .assertRaises (TypeError ):
10671059 self .cu .executemany ("insert into test(income) values (?)" , 42 )
10681060
1069- @subTests ("params_class" , (EvilParamsWithIter , EvilParamsWithNext ))
1061+ @subTests ("params_class" , (ParamsCxCloseInIterMany , ParamsCxCloseInNext ))
10701062 def test_executemany_use_after_close (self , params_class ):
1071- self .do_test_connection_use_after_close ("executemany" , params_class )
1063+ # Prevent SIGSEGV with iterable of parameters closing the connection.
1064+ # Regression test for https://github.com/python/cpython/issues/143198.
1065+ cx = sqlite .connect (":memory:" )
1066+ cx .execute ("create table tmp(a number)" )
1067+ self .addCleanup (cx .close )
1068+ cu = cx .cursor ()
1069+ msg = r"Cannot operate on a closed database\."
1070+ with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1071+ cu .executemany ("insert into tmp(a) values (?)" , params_class (cx ))
10721072
10731073 def test_fetch_iter (self ):
10741074 # Optional DB-API extension.
@@ -1685,15 +1685,6 @@ def tearDown(self):
16851685 self .cur .close ()
16861686 self .con .close ()
16871687
1688- def do_test_connection_use_after_close (self , method_name , params_class ):
1689- # Prevent SIGSEGV with iterable of parameters closing the connection.
1690- # Regression test for https://github.com/python/cpython/issues/143198.
1691- cx = sqlite .connect (":memory:" )
1692- self .addCleanup (cx .close )
1693- params = params_class (cx )
1694- method = operator .methodcaller (method_name , "SELECT ?" , params )
1695- self .assertRaises (sqlite .ProgrammingError , method , cx )
1696-
16971688 def test_script_string_sql (self ):
16981689 cur = self .cur
16991690 cur .executescript ("""
@@ -1760,10 +1751,6 @@ def test_connection_execute(self):
17601751 result = self .con .execute ("select 5" ).fetchone ()[0 ]
17611752 self .assertEqual (result , 5 , "Basic test of Connection.execute" )
17621753
1763- @subTests ("params_class" , (EvilParamsWithIter , EvilParamsWithNext ))
1764- def test_connection_execute_use_after_close (self , params_class ):
1765- self .do_test_connection_use_after_close ("execute" , params_class )
1766-
17671754 def test_connection_executemany (self ):
17681755 con = self .con
17691756 con .execute ("create table test(foo)" )
@@ -1772,9 +1759,16 @@ def test_connection_executemany(self):
17721759 self .assertEqual (result [0 ][0 ], 3 , "Basic test of Connection.executemany" )
17731760 self .assertEqual (result [1 ][0 ], 4 , "Basic test of Connection.executemany" )
17741761
1775- @subTests ("params_class" , (EvilParamsWithIter , EvilParamsWithNext ))
1762+ @subTests ("params_class" , (ParamsCxCloseInIterMany , ParamsCxCloseInNext ))
17761763 def test_connection_executemany_use_after_close (self , params_class ):
1777- self .do_test_connection_use_after_close ("executemany" , params_class )
1764+ # Prevent SIGSEGV with iterable of parameters closing the connection.
1765+ # Regression test for https://github.com/python/cpython/issues/143198.
1766+ cx = sqlite .connect (":memory:" )
1767+ cx .execute ("create table tmp(a number)" )
1768+ self .addCleanup (cx .close )
1769+ msg = r"Cannot operate on a closed database\."
1770+ with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1771+ cx .executemany ("insert into tmp(a) values (?)" , params_class (cx ))
17781772
17791773 def test_connection_executescript (self ):
17801774 con = self .con
0 commit comments