1 # Test the most dynamic corner cases of Python's runtime semantics. 2 3 import builtins 4 import unittest 5 6 from test.support import swap_item, swap_attr 7 8 9 class RebindBuiltinsTests(unittest.TestCase): 10 11 """Test all the ways that we can change/shadow globals/builtins.""" 12 13 def configure_func(self, func, *args): 14 """Perform TestCase-specific configuration on a function before testing. 15 16 By default, this does nothing. Example usage: spinning a function so 17 that a JIT will optimize it. Subclasses should override this as needed. 18 19 Args: 20 func: function to configure. 21 *args: any arguments that should be passed to func, if calling it. 22 23 Returns: 24 Nothing. Work will be performed on func in-place. 25 """ 26 pass 27 28 def test_globals_shadow_builtins(self): 29 # Modify globals() to shadow an entry in builtins. 30 def foo(): 31 return len([1, 2, 3]) 32 self.configure_func(foo) 33 34 self.assertEqual(foo(), 3) 35 with swap_item(globals(), "len", lambda x: 7): 36 self.assertEqual(foo(), 7) 37 38 def test_modify_builtins(self): 39 # Modify the builtins module directly. 40 def foo(): 41 return len([1, 2, 3]) 42 self.configure_func(foo) 43 44 self.assertEqual(foo(), 3) 45 with swap_attr(builtins, "len", lambda x: 7): 46 self.assertEqual(foo(), 7) 47 48 def test_modify_builtins_while_generator_active(self): 49 # Modify the builtins out from under a live generator. 50 def foo(): 51 x = range(3) 52 yield len(x) 53 yield len(x) 54 self.configure_func(foo) 55 56 g = foo() 57 self.assertEqual(next(g), 3) 58 with swap_attr(builtins, "len", lambda x: 7): 59 self.assertEqual(next(g), 7) 60 61 def test_modify_builtins_from_leaf_function(self): 62 # Verify that modifications made by leaf functions percolate up the 63 # callstack. 64 with swap_attr(builtins, "len", len): 65 def bar(): 66 builtins.len = lambda x: 4 67 68 def foo(modifier): 69 l = [] 70 l.append(len(range(7))) 71 modifier() 72 l.append(len(range(7))) 73 return l 74 self.configure_func(foo, lambda: None) 75 76 self.assertEqual(foo(bar), [7, 4]) 77 78 def test_cannot_change_globals_or_builtins_with_eval(self): 79 def foo(): 80 return len([1, 2, 3]) 81 self.configure_func(foo) 82 83 # Note that this *doesn't* change the definition of len() seen by foo(). 84 builtins_dict = {"len": lambda x: 7} 85 globals_dict = {"foo": foo, "__builtins__": builtins_dict, 86 "len": lambda x: 8} 87 self.assertEqual(eval("foo()", globals_dict), 3) 88 89 self.assertEqual(eval("foo()", {"foo": foo}), 3) 90 91 def test_cannot_change_globals_or_builtins_with_exec(self): 92 def foo(): 93 return len([1, 2, 3]) 94 self.configure_func(foo) 95 96 globals_dict = {"foo": foo} 97 exec("x = foo()", globals_dict) 98 self.assertEqual(globals_dict["x"], 3) 99 100 # Note that this *doesn't* change the definition of len() seen by foo(). 101 builtins_dict = {"len": lambda x: 7} 102 globals_dict = {"foo": foo, "__builtins__": builtins_dict, 103 "len": lambda x: 8} 104 105 exec("x = foo()", globals_dict) 106 self.assertEqual(globals_dict["x"], 3) 107 108 def test_cannot_replace_builtins_dict_while_active(self): 109 def foo(): 110 x = range(3) 111 yield len(x) 112 yield len(x) 113 self.configure_func(foo) 114 115 g = foo() 116 self.assertEqual(next(g), 3) 117 with swap_item(globals(), "__builtins__", {"len": lambda x: 7}): 118 self.assertEqual(next(g), 3) 119 120 def test_cannot_replace_builtins_dict_between_calls(self): 121 def foo(): 122 return len([1, 2, 3]) 123 self.configure_func(foo) 124 125 self.assertEqual(foo(), 3) 126 with swap_item(globals(), "__builtins__", {"len": lambda x: 7}): 127 self.assertEqual(foo(), 3) 128 129 def test_eval_gives_lambda_custom_globals(self): 130 globals_dict = {"len": lambda x: 7} 131 foo = eval("lambda: len([])", globals_dict) 132 self.configure_func(foo) 133 134 self.assertEqual(foo(), 7) 135 136 137 if __name__ == "__main__": 138 unittest.main() 139