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