(root)/
Python-3.12.0/
Lib/
test/
test_dynamic.py
       1  # Test the most dynamic corner cases of Python's runtime semantics.
       2  
       3  import builtins
       4  import sys
       5  import unittest
       6  
       7  from test.support import swap_item, swap_attr
       8  
       9  
      10  class ESC[4;38;5;81mRebindBuiltinsTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      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      def test_load_global_specialization_failure_keeps_oparg(self):
     138          # https://github.com/python/cpython/issues/91625
     139          class MyGlobals(dict):
     140              def __missing__(self, key):
     141                  return int(key.removeprefix("_number_"))
     142  
     143          # Need more than 256 variables to use EXTENDED_ARGS
     144          variables = 400
     145          code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables))
     146          sum_func = eval(code, MyGlobals())
     147          expected = sum(range(variables))
     148          # Warm up the the function for quickening (PEP 659)
     149          for _ in range(30):
     150              self.assertEqual(sum_func(), expected)
     151  
     152  
     153  class TestTracing(unittest.TestCase):
     154  
     155      def setUp(self):
     156          self.addCleanup(sys.settrace, sys.gettrace())
     157          sys.settrace(None)
     158  
     159      def test_after_specialization(self):
     160  
     161          def trace(frame, event, arg):
     162              return trace
     163  
     164          turn_on_trace = False
     165  
     166          class C:
     167              def __init__(self, x):
     168                  self.x = x
     169              def __del__(self):
     170                  if turn_on_trace:
     171                      sys.settrace(trace)
     172  
     173          def f():
     174              # LOAD_GLOBAL[_BUILTIN] immediately follows the call to C.__del__
     175              C(0).x, len
     176  
     177          def g():
     178              # BINARY_SUSCR[_LIST_INT] immediately follows the call to C.__del__
     179              [0][C(0).x]
     180  
     181          def h():
     182              # BINARY_OP[_ADD_INT] immediately follows the call to C.__del__
     183              0 + C(0).x
     184  
     185          for func in (f, g, h):
     186              with self.subTest(func.__name__):
     187                  for _ in range(58):
     188                      func()
     189                  turn_on_trace = True
     190                  func()
     191                  sys.settrace(None)
     192                  turn_on_trace = False
     193  
     194  
     195  if __name__ == "__main__":
     196      unittest.main()