17db96d56Sopenharmony_ci# Test the most dynamic corner cases of Python's runtime semantics. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciimport builtins 47db96d56Sopenharmony_ciimport sys 57db96d56Sopenharmony_ciimport unittest 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_cifrom test.support import swap_item, swap_attr 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciclass RebindBuiltinsTests(unittest.TestCase): 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci """Test all the ways that we can change/shadow globals/builtins.""" 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci def configure_func(self, func, *args): 157db96d56Sopenharmony_ci """Perform TestCase-specific configuration on a function before testing. 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci By default, this does nothing. Example usage: spinning a function so 187db96d56Sopenharmony_ci that a JIT will optimize it. Subclasses should override this as needed. 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci Args: 217db96d56Sopenharmony_ci func: function to configure. 227db96d56Sopenharmony_ci *args: any arguments that should be passed to func, if calling it. 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci Returns: 257db96d56Sopenharmony_ci Nothing. Work will be performed on func in-place. 267db96d56Sopenharmony_ci """ 277db96d56Sopenharmony_ci pass 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci def test_globals_shadow_builtins(self): 307db96d56Sopenharmony_ci # Modify globals() to shadow an entry in builtins. 317db96d56Sopenharmony_ci def foo(): 327db96d56Sopenharmony_ci return len([1, 2, 3]) 337db96d56Sopenharmony_ci self.configure_func(foo) 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci self.assertEqual(foo(), 3) 367db96d56Sopenharmony_ci with swap_item(globals(), "len", lambda x: 7): 377db96d56Sopenharmony_ci self.assertEqual(foo(), 7) 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci def test_modify_builtins(self): 407db96d56Sopenharmony_ci # Modify the builtins module directly. 417db96d56Sopenharmony_ci def foo(): 427db96d56Sopenharmony_ci return len([1, 2, 3]) 437db96d56Sopenharmony_ci self.configure_func(foo) 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci self.assertEqual(foo(), 3) 467db96d56Sopenharmony_ci with swap_attr(builtins, "len", lambda x: 7): 477db96d56Sopenharmony_ci self.assertEqual(foo(), 7) 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci def test_modify_builtins_while_generator_active(self): 507db96d56Sopenharmony_ci # Modify the builtins out from under a live generator. 517db96d56Sopenharmony_ci def foo(): 527db96d56Sopenharmony_ci x = range(3) 537db96d56Sopenharmony_ci yield len(x) 547db96d56Sopenharmony_ci yield len(x) 557db96d56Sopenharmony_ci self.configure_func(foo) 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci g = foo() 587db96d56Sopenharmony_ci self.assertEqual(next(g), 3) 597db96d56Sopenharmony_ci with swap_attr(builtins, "len", lambda x: 7): 607db96d56Sopenharmony_ci self.assertEqual(next(g), 7) 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci def test_modify_builtins_from_leaf_function(self): 637db96d56Sopenharmony_ci # Verify that modifications made by leaf functions percolate up the 647db96d56Sopenharmony_ci # callstack. 657db96d56Sopenharmony_ci with swap_attr(builtins, "len", len): 667db96d56Sopenharmony_ci def bar(): 677db96d56Sopenharmony_ci builtins.len = lambda x: 4 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci def foo(modifier): 707db96d56Sopenharmony_ci l = [] 717db96d56Sopenharmony_ci l.append(len(range(7))) 727db96d56Sopenharmony_ci modifier() 737db96d56Sopenharmony_ci l.append(len(range(7))) 747db96d56Sopenharmony_ci return l 757db96d56Sopenharmony_ci self.configure_func(foo, lambda: None) 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci self.assertEqual(foo(bar), [7, 4]) 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci def test_cannot_change_globals_or_builtins_with_eval(self): 807db96d56Sopenharmony_ci def foo(): 817db96d56Sopenharmony_ci return len([1, 2, 3]) 827db96d56Sopenharmony_ci self.configure_func(foo) 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci # Note that this *doesn't* change the definition of len() seen by foo(). 857db96d56Sopenharmony_ci builtins_dict = {"len": lambda x: 7} 867db96d56Sopenharmony_ci globals_dict = {"foo": foo, "__builtins__": builtins_dict, 877db96d56Sopenharmony_ci "len": lambda x: 8} 887db96d56Sopenharmony_ci self.assertEqual(eval("foo()", globals_dict), 3) 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci self.assertEqual(eval("foo()", {"foo": foo}), 3) 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci def test_cannot_change_globals_or_builtins_with_exec(self): 937db96d56Sopenharmony_ci def foo(): 947db96d56Sopenharmony_ci return len([1, 2, 3]) 957db96d56Sopenharmony_ci self.configure_func(foo) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci globals_dict = {"foo": foo} 987db96d56Sopenharmony_ci exec("x = foo()", globals_dict) 997db96d56Sopenharmony_ci self.assertEqual(globals_dict["x"], 3) 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci # Note that this *doesn't* change the definition of len() seen by foo(). 1027db96d56Sopenharmony_ci builtins_dict = {"len": lambda x: 7} 1037db96d56Sopenharmony_ci globals_dict = {"foo": foo, "__builtins__": builtins_dict, 1047db96d56Sopenharmony_ci "len": lambda x: 8} 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci exec("x = foo()", globals_dict) 1077db96d56Sopenharmony_ci self.assertEqual(globals_dict["x"], 3) 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci def test_cannot_replace_builtins_dict_while_active(self): 1107db96d56Sopenharmony_ci def foo(): 1117db96d56Sopenharmony_ci x = range(3) 1127db96d56Sopenharmony_ci yield len(x) 1137db96d56Sopenharmony_ci yield len(x) 1147db96d56Sopenharmony_ci self.configure_func(foo) 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci g = foo() 1177db96d56Sopenharmony_ci self.assertEqual(next(g), 3) 1187db96d56Sopenharmony_ci with swap_item(globals(), "__builtins__", {"len": lambda x: 7}): 1197db96d56Sopenharmony_ci self.assertEqual(next(g), 3) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci def test_cannot_replace_builtins_dict_between_calls(self): 1227db96d56Sopenharmony_ci def foo(): 1237db96d56Sopenharmony_ci return len([1, 2, 3]) 1247db96d56Sopenharmony_ci self.configure_func(foo) 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci self.assertEqual(foo(), 3) 1277db96d56Sopenharmony_ci with swap_item(globals(), "__builtins__", {"len": lambda x: 7}): 1287db96d56Sopenharmony_ci self.assertEqual(foo(), 3) 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci def test_eval_gives_lambda_custom_globals(self): 1317db96d56Sopenharmony_ci globals_dict = {"len": lambda x: 7} 1327db96d56Sopenharmony_ci foo = eval("lambda: len([])", globals_dict) 1337db96d56Sopenharmony_ci self.configure_func(foo) 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci self.assertEqual(foo(), 7) 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci def test_load_global_specialization_failure_keeps_oparg(self): 1387db96d56Sopenharmony_ci # https://github.com/python/cpython/issues/91625 1397db96d56Sopenharmony_ci class MyGlobals(dict): 1407db96d56Sopenharmony_ci def __missing__(self, key): 1417db96d56Sopenharmony_ci return int(key.removeprefix("_number_")) 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci code = "lambda: " + "+".join(f"_number_{i}" for i in range(1000)) 1447db96d56Sopenharmony_ci sum_1000 = eval(code, MyGlobals()) 1457db96d56Sopenharmony_ci expected = sum(range(1000)) 1467db96d56Sopenharmony_ci # Warm up the the function for quickening (PEP 659) 1477db96d56Sopenharmony_ci for _ in range(30): 1487db96d56Sopenharmony_ci self.assertEqual(sum_1000(), expected) 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ciclass TestTracing(unittest.TestCase): 1527db96d56Sopenharmony_ci 1537db96d56Sopenharmony_ci def setUp(self): 1547db96d56Sopenharmony_ci self.addCleanup(sys.settrace, sys.gettrace()) 1557db96d56Sopenharmony_ci sys.settrace(None) 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci def test_after_specialization(self): 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci def trace(frame, event, arg): 1607db96d56Sopenharmony_ci return trace 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci turn_on_trace = False 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci class C: 1657db96d56Sopenharmony_ci def __init__(self, x): 1667db96d56Sopenharmony_ci self.x = x 1677db96d56Sopenharmony_ci def __del__(self): 1687db96d56Sopenharmony_ci if turn_on_trace: 1697db96d56Sopenharmony_ci sys.settrace(trace) 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci def f(): 1727db96d56Sopenharmony_ci # LOAD_GLOBAL[_BUILTIN] immediately follows the call to C.__del__ 1737db96d56Sopenharmony_ci C(0).x, len 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci def g(): 1767db96d56Sopenharmony_ci # BINARY_SUSCR[_LIST_INT] immediately follows the call to C.__del__ 1777db96d56Sopenharmony_ci [0][C(0).x] 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci def h(): 1807db96d56Sopenharmony_ci # BINARY_OP[_ADD_INT] immediately follows the call to C.__del__ 1817db96d56Sopenharmony_ci 0 + C(0).x 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci for func in (f, g, h): 1847db96d56Sopenharmony_ci with self.subTest(func.__name__): 1857db96d56Sopenharmony_ci for _ in range(58): 1867db96d56Sopenharmony_ci func() 1877db96d56Sopenharmony_ci turn_on_trace = True 1887db96d56Sopenharmony_ci func() 1897db96d56Sopenharmony_ci sys.settrace(None) 1907db96d56Sopenharmony_ci turn_on_trace = False 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ciif __name__ == "__main__": 1947db96d56Sopenharmony_ci unittest.main() 195