@@ -737,6 +737,7 @@ def test_exec_globals(self):
737737 self .assertRaises (TypeError ,
738738 exec , code , {'__builtins__' : 123 })
739739
740+ def test_exec_globals_frozen (self ):
740741 class frozendict_error (Exception ):
741742 pass
742743
@@ -768,6 +769,36 @@ def __setitem__(self, key, value):
768769 self .assertRaises (frozendict_error ,
769770 exec , code , namespace )
770771
772+ def test_exec_globals_error_on_get (self ):
773+ # custom `globals` or `builtins` can raise errors on item access
774+ class setonlyerror (Exception ):
775+ pass
776+
777+ class setonlydict (dict ):
778+ def __getitem__ (self , key ):
779+ raise setonlyerror
780+
781+ # globals' `__getitem__` raises
782+ code = compile ("globalname" , "test" , "exec" )
783+ self .assertRaises (setonlyerror ,
784+ exec , code , setonlydict ({'globalname' : 1 }))
785+
786+ # builtins' `__getitem__` raises
787+ code = compile ("superglobal" , "test" , "exec" )
788+ self .assertRaises (setonlyerror , exec , code ,
789+ {'__builtins__' : setonlydict ({'superglobal' : 1 })})
790+
791+ def test_exec_globals_dict_subclass (self ):
792+ class customdict (dict ): # this one should not do anything fancy
793+ pass
794+
795+ code = compile ("superglobal" , "test" , "exec" )
796+ # works correctly
797+ exec (code , {'__builtins__' : customdict ({'superglobal' : 1 })})
798+ # custom builtins dict subclass is missing key
799+ self .assertRaisesRegex (NameError , "name 'superglobal' is not defined" ,
800+ exec , code , {'__builtins__' : customdict ()})
801+
771802 def test_exec_redirected (self ):
772803 savestdout = sys .stdout
773804 sys .stdout = None # Whatever that cannot flush()
0 commit comments