mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
	
	
		
			144 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			144 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								# Test the most dynamic corner cases of Python's runtime semantics.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import builtins
							 | 
						||
| 
								 | 
							
								import contextlib
							 | 
						||
| 
								 | 
							
								import unittest
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from test.support import run_unittest, swap_item, swap_attr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RebindBuiltinsTests(unittest.TestCase):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Test all the ways that we can change/shadow globals/builtins."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def configure_func(self, func, *args):
							 | 
						||
| 
								 | 
							
								        """Perform TestCase-specific configuration on a function before testing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        By default, this does nothing. Example usage: spinning a function so
							 | 
						||
| 
								 | 
							
								        that a JIT will optimize it. Subclasses should override this as needed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Args:
							 | 
						||
| 
								 | 
							
								            func: function to configure.
							 | 
						||
| 
								 | 
							
								            *args: any arguments that should be passed to func, if calling it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Returns:
							 | 
						||
| 
								 | 
							
								            Nothing. Work will be performed on func in-place.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_globals_shadow_builtins(self):
							 | 
						||
| 
								 | 
							
								        # Modify globals() to shadow an entry in builtins.
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            return len([1, 2, 3])
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(foo(), 3)
							 | 
						||
| 
								 | 
							
								        with swap_item(globals(), "len", lambda x: 7):
							 | 
						||
| 
								 | 
							
								            self.assertEqual(foo(), 7)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_modify_builtins(self):
							 | 
						||
| 
								 | 
							
								        # Modify the builtins module directly.
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            return len([1, 2, 3])
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(foo(), 3)
							 | 
						||
| 
								 | 
							
								        with swap_attr(builtins, "len", lambda x: 7):
							 | 
						||
| 
								 | 
							
								            self.assertEqual(foo(), 7)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_modify_builtins_while_generator_active(self):
							 | 
						||
| 
								 | 
							
								        # Modify the builtins out from under a live generator.
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            x = range(3)
							 | 
						||
| 
								 | 
							
								            yield len(x)
							 | 
						||
| 
								 | 
							
								            yield len(x)
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        g = foo()
							 | 
						||
| 
								 | 
							
								        self.assertEqual(next(g), 3)
							 | 
						||
| 
								 | 
							
								        with swap_attr(builtins, "len", lambda x: 7):
							 | 
						||
| 
								 | 
							
								            self.assertEqual(next(g), 7)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_modify_builtins_from_leaf_function(self):
							 | 
						||
| 
								 | 
							
								        # Verify that modifications made by leaf functions percolate up the
							 | 
						||
| 
								 | 
							
								        # callstack.
							 | 
						||
| 
								 | 
							
								        with swap_attr(builtins, "len", len):
							 | 
						||
| 
								 | 
							
								            def bar():
							 | 
						||
| 
								 | 
							
								                builtins.len = lambda x: 4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            def foo(modifier):
							 | 
						||
| 
								 | 
							
								                l = []
							 | 
						||
| 
								 | 
							
								                l.append(len(range(7)))
							 | 
						||
| 
								 | 
							
								                modifier()
							 | 
						||
| 
								 | 
							
								                l.append(len(range(7)))
							 | 
						||
| 
								 | 
							
								                return l
							 | 
						||
| 
								 | 
							
								            self.configure_func(foo, lambda: None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            self.assertEqual(foo(bar), [7, 4])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_cannot_change_globals_or_builtins_with_eval(self):
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            return len([1, 2, 3])
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Note that this *doesn't* change the definition of len() seen by foo().
							 | 
						||
| 
								 | 
							
								        builtins_dict = {"len": lambda x: 7}
							 | 
						||
| 
								 | 
							
								        globals_dict = {"foo": foo, "__builtins__": builtins_dict,
							 | 
						||
| 
								 | 
							
								                        "len": lambda x: 8}
							 | 
						||
| 
								 | 
							
								        self.assertEqual(eval("foo()", globals_dict), 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(eval("foo()", {"foo": foo}), 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_cannot_change_globals_or_builtins_with_exec(self):
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            return len([1, 2, 3])
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        globals_dict = {"foo": foo}
							 | 
						||
| 
								 | 
							
								        exec("x = foo()", globals_dict)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(globals_dict["x"], 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Note that this *doesn't* change the definition of len() seen by foo().
							 | 
						||
| 
								 | 
							
								        builtins_dict = {"len": lambda x: 7}
							 | 
						||
| 
								 | 
							
								        globals_dict = {"foo": foo, "__builtins__": builtins_dict,
							 | 
						||
| 
								 | 
							
								                        "len": lambda x: 8}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        exec("x = foo()", globals_dict)
							 | 
						||
| 
								 | 
							
								        self.assertEqual(globals_dict["x"], 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_cannot_replace_builtins_dict_while_active(self):
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            x = range(3)
							 | 
						||
| 
								 | 
							
								            yield len(x)
							 | 
						||
| 
								 | 
							
								            yield len(x)
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        g = foo()
							 | 
						||
| 
								 | 
							
								        self.assertEqual(next(g), 3)
							 | 
						||
| 
								 | 
							
								        with swap_item(globals(), "__builtins__", {"len": lambda x: 7}):
							 | 
						||
| 
								 | 
							
								            self.assertEqual(next(g), 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_cannot_replace_builtins_dict_between_calls(self):
							 | 
						||
| 
								 | 
							
								        def foo():
							 | 
						||
| 
								 | 
							
								            return len([1, 2, 3])
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(foo(), 3)
							 | 
						||
| 
								 | 
							
								        with swap_item(globals(), "__builtins__", {"len": lambda x: 7}):
							 | 
						||
| 
								 | 
							
								            self.assertEqual(foo(), 3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def test_eval_gives_lambda_custom_globals(self):
							 | 
						||
| 
								 | 
							
								        globals_dict = {"len": lambda x: 7}
							 | 
						||
| 
								 | 
							
								        foo = eval("lambda: len([])", globals_dict)
							 | 
						||
| 
								 | 
							
								        self.configure_func(foo)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.assertEqual(foo(), 7)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def test_main():
							 | 
						||
| 
								 | 
							
								    run_unittest(RebindBuiltinsTests)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if __name__ == "__main__":
							 | 
						||
| 
								 | 
							
								    test_main()
							 |