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