@@ -246,24 +246,6 @@ def CheckPragmaAutocommit(self):
246246 cur .execute ("pragma page_size" )
247247 row = cur .fetchone ()
248248
249- def CheckSetDict (self ):
250- """
251- See http://bugs.python.org/issue7478
252-
253- It was possible to successfully register callbacks that could not be
254- hashed. Return codes of PyDict_SetItem were not checked properly.
255- """
256- class NotHashable :
257- def __call__ (self , * args , ** kw ):
258- pass
259- def __hash__ (self ):
260- raise TypeError ()
261- var = NotHashable ()
262- self .assertRaises (TypeError , self .con .create_function , var )
263- self .assertRaises (TypeError , self .con .create_aggregate , var )
264- self .assertRaises (TypeError , self .con .set_authorizer , var )
265- self .assertRaises (TypeError , self .con .set_progress_handler , var )
266-
267249 def CheckConnectionCall (self ):
268250 """
269251 Call a connection with a non-string SQL request: check error handling
@@ -380,9 +362,73 @@ def callback(*args):
380362 support .gc_collect ()
381363
382364
365+ class UnhashableFunc :
366+ def __hash__ (self ):
367+ raise TypeError ('unhashable type' )
368+
369+ def __init__ (self , return_value = None ):
370+ self .calls = 0
371+ self .return_value = return_value
372+
373+ def __call__ (self , * args , ** kwargs ):
374+ self .calls += 1
375+ return self .return_value
376+
377+
378+ class UnhashableCallbacksTestCase (unittest .TestCase ):
379+ """
380+ https://bugs.python.org/issue34052
381+
382+ Registering unhashable callbacks raises TypeError, callbacks are not
383+ registered in SQLite after such registration attempt.
384+ """
385+ def setUp (self ):
386+ self .con = sqlite .connect (':memory:' )
387+
388+ def tearDown (self ):
389+ self .con .close ()
390+
391+ def test_progress_handler (self ):
392+ f = UnhashableFunc (return_value = 0 )
393+ with self .assertRaisesRegexp (TypeError , 'unhashable type' ):
394+ self .con .set_progress_handler (f , 1 )
395+ self .con .execute ('SELECT 1' )
396+ self .assertFalse (f .calls )
397+
398+ def test_func (self ):
399+ func_name = 'func_name'
400+ f = UnhashableFunc ()
401+ with self .assertRaisesRegexp (TypeError , 'unhashable type' ):
402+ self .con .create_function (func_name , 0 , f )
403+ msg = 'no such function: %s' % func_name
404+ with self .assertRaisesRegexp (sqlite .OperationalError , msg ):
405+ self .con .execute ('SELECT %s()' % func_name )
406+ self .assertFalse (f .calls )
407+
408+ def test_authorizer (self ):
409+ f = UnhashableFunc (return_value = sqlite .SQLITE_DENY )
410+ with self .assertRaisesRegexp (TypeError , 'unhashable type' ):
411+ self .con .set_authorizer (f )
412+ self .con .execute ('SELECT 1' )
413+ self .assertFalse (f .calls )
414+
415+ def test_aggr (self ):
416+ class UnhashableType (type ):
417+ __hash__ = None
418+ aggr_name = 'aggr_name'
419+ with self .assertRaisesRegexp (TypeError , 'unhashable type' ):
420+ self .con .create_aggregate (aggr_name , 0 , UnhashableType ('Aggr' , (), {}))
421+ msg = 'no such function: %s' % aggr_name
422+ with self .assertRaisesRegexp (sqlite .OperationalError , msg ):
423+ self .con .execute ('SELECT %s()' % aggr_name )
424+
425+
383426def suite ():
384427 regression_suite = unittest .makeSuite (RegressionTests , "Check" )
385- return unittest .TestSuite ((regression_suite ,))
428+ return unittest .TestSuite ((
429+ regression_suite ,
430+ unittest .makeSuite (UnhashableCallbacksTestCase ),
431+ ))
386432
387433def test ():
388434 runner = unittest .TextTestRunner ()
0 commit comments