@@ -256,24 +256,6 @@ def CheckPragmaAutocommit(self):
256256 cur .execute ("pragma page_size" )
257257 row = cur .fetchone ()
258258
259- def CheckSetDict (self ):
260- """
261- See http://bugs.python.org/issue7478
262-
263- It was possible to successfully register callbacks that could not be
264- hashed. Return codes of PyDict_SetItem were not checked properly.
265- """
266- class NotHashable :
267- def __call__ (self , * args , ** kw ):
268- pass
269- def __hash__ (self ):
270- raise TypeError ()
271- var = NotHashable ()
272- self .assertRaises (TypeError , self .con .create_function , var )
273- self .assertRaises (TypeError , self .con .create_aggregate , var )
274- self .assertRaises (TypeError , self .con .set_authorizer , var )
275- self .assertRaises (TypeError , self .con .set_progress_handler , var )
276-
277259 def CheckConnectionCall (self ):
278260 """
279261 Call a connection with a non-string SQL request: check error handling
@@ -398,9 +380,72 @@ def callback(*args):
398380 support .gc_collect ()
399381
400382
383+ class UnhashableFunc :
384+ __hash__ = None
385+
386+ def __init__ (self , return_value = None ):
387+ self .calls = 0
388+ self .return_value = return_value
389+
390+ def __call__ (self , * args , ** kwargs ):
391+ self .calls += 1
392+ return self .return_value
393+
394+
395+ class UnhashableCallbacksTestCase (unittest .TestCase ):
396+ """
397+ https://bugs.python.org/issue34052
398+
399+ Registering unhashable callbacks raises TypeError, callbacks are not
400+ registered in SQLite after such registration attempt.
401+ """
402+ def setUp (self ):
403+ self .con = sqlite .connect (':memory:' )
404+
405+ def tearDown (self ):
406+ self .con .close ()
407+
408+ def test_progress_handler (self ):
409+ f = UnhashableFunc (return_value = 0 )
410+ with self .assertRaisesRegex (TypeError , 'unhashable type' ):
411+ self .con .set_progress_handler (f , 1 )
412+ self .con .execute ('SELECT 1' )
413+ self .assertFalse (f .calls )
414+
415+ def test_func (self ):
416+ func_name = 'func_name'
417+ f = UnhashableFunc ()
418+ with self .assertRaisesRegex (TypeError , 'unhashable type' ):
419+ self .con .create_function (func_name , 0 , f )
420+ msg = 'no such function: %s' % func_name
421+ with self .assertRaisesRegex (sqlite .OperationalError , msg ):
422+ self .con .execute ('SELECT %s()' % func_name )
423+ self .assertFalse (f .calls )
424+
425+ def test_authorizer (self ):
426+ f = UnhashableFunc (return_value = sqlite .SQLITE_DENY )
427+ with self .assertRaisesRegex (TypeError , 'unhashable type' ):
428+ self .con .set_authorizer (f )
429+ self .con .execute ('SELECT 1' )
430+ self .assertFalse (f .calls )
431+
432+ def test_aggr (self ):
433+ class UnhashableType (type ):
434+ __hash__ = None
435+ aggr_name = 'aggr_name'
436+ with self .assertRaisesRegex (TypeError , 'unhashable type' ):
437+ self .con .create_aggregate (aggr_name , 0 , UnhashableType ('Aggr' , (), {}))
438+ msg = 'no such function: %s' % aggr_name
439+ with self .assertRaisesRegex (sqlite .OperationalError , msg ):
440+ self .con .execute ('SELECT %s()' % aggr_name )
441+
442+
401443def suite ():
402444 regression_suite = unittest .makeSuite (RegressionTests , "Check" )
403- return unittest .TestSuite ((regression_suite ,))
445+ return unittest .TestSuite ((
446+ regression_suite ,
447+ unittest .makeSuite (UnhashableCallbacksTestCase ),
448+ ))
404449
405450def test ():
406451 runner = unittest .TextTestRunner ()
0 commit comments