Home | History | Annotate | Download | only in test
      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