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