python (3.12.0)

(root)/
lib/
python3.12/
test/
test_compile.py
       1  import dis
       2  import math
       3  import os
       4  import unittest
       5  import sys
       6  import ast
       7  import _ast
       8  import tempfile
       9  import types
      10  import textwrap
      11  import warnings
      12  from test import support
      13  from test.support import (script_helper, requires_debug_ranges,
      14                            requires_specialization, C_RECURSION_LIMIT)
      15  from test.support.os_helper import FakePath
      16  
      17  class ESC[4;38;5;81mTestSpecifics(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      18  
      19      def compile_single(self, source):
      20          compile(source, "<single>", "single")
      21  
      22      def assertInvalidSingle(self, source):
      23          self.assertRaises(SyntaxError, self.compile_single, source)
      24  
      25      def test_no_ending_newline(self):
      26          compile("hi", "<test>", "exec")
      27          compile("hi\r", "<test>", "exec")
      28  
      29      def test_empty(self):
      30          compile("", "<test>", "exec")
      31  
      32      def test_other_newlines(self):
      33          compile("\r\n", "<test>", "exec")
      34          compile("\r", "<test>", "exec")
      35          compile("hi\r\nstuff\r\ndef f():\n    pass\r", "<test>", "exec")
      36          compile("this_is\rreally_old_mac\rdef f():\n    pass", "<test>", "exec")
      37  
      38      def test_debug_assignment(self):
      39          # catch assignments to __debug__
      40          self.assertRaises(SyntaxError, compile, '__debug__ = 1', '?', 'single')
      41          import builtins
      42          prev = builtins.__debug__
      43          setattr(builtins, '__debug__', 'sure')
      44          self.assertEqual(__debug__, prev)
      45          setattr(builtins, '__debug__', prev)
      46  
      47      def test_argument_handling(self):
      48          # detect duplicate positional and keyword arguments
      49          self.assertRaises(SyntaxError, eval, 'lambda a,a:0')
      50          self.assertRaises(SyntaxError, eval, 'lambda a,a=1:0')
      51          self.assertRaises(SyntaxError, eval, 'lambda a=1,a=1:0')
      52          self.assertRaises(SyntaxError, exec, 'def f(a, a): pass')
      53          self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass')
      54          self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
      55  
      56      def test_syntax_error(self):
      57          self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")
      58  
      59      def test_none_keyword_arg(self):
      60          self.assertRaises(SyntaxError, compile, "f(None=1)", "<string>", "exec")
      61  
      62      def test_duplicate_global_local(self):
      63          self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')
      64  
      65      def test_exec_with_general_mapping_for_locals(self):
      66  
      67          class ESC[4;38;5;81mM:
      68              "Test mapping interface versus possible calls from eval()."
      69              def __getitem__(self, key):
      70                  if key == 'a':
      71                      return 12
      72                  raise KeyError
      73              def __setitem__(self, key, value):
      74                  self.results = (key, value)
      75              def keys(self):
      76                  return list('xyz')
      77  
      78          m = M()
      79          g = globals()
      80          exec('z = a', g, m)
      81          self.assertEqual(m.results, ('z', 12))
      82          try:
      83              exec('z = b', g, m)
      84          except NameError:
      85              pass
      86          else:
      87              self.fail('Did not detect a KeyError')
      88          exec('z = dir()', g, m)
      89          self.assertEqual(m.results, ('z', list('xyz')))
      90          exec('z = globals()', g, m)
      91          self.assertEqual(m.results, ('z', g))
      92          exec('z = locals()', g, m)
      93          self.assertEqual(m.results, ('z', m))
      94          self.assertRaises(TypeError, exec, 'z = b', m)
      95  
      96          class ESC[4;38;5;81mA:
      97              "Non-mapping"
      98              pass
      99          m = A()
     100          self.assertRaises(TypeError, exec, 'z = a', g, m)
     101  
     102          # Verify that dict subclasses work as well
     103          class ESC[4;38;5;81mD(ESC[4;38;5;149mdict):
     104              def __getitem__(self, key):
     105                  if key == 'a':
     106                      return 12
     107                  return dict.__getitem__(self, key)
     108          d = D()
     109          exec('z = a', g, d)
     110          self.assertEqual(d['z'], 12)
     111  
     112      @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
     113      def test_extended_arg(self):
     114          repeat = int(C_RECURSION_LIMIT * 0.9)
     115          longexpr = 'x = x or ' + '-x' * repeat
     116          g = {}
     117          code = textwrap.dedent('''
     118              def f(x):
     119                  %s
     120                  %s
     121                  %s
     122                  %s
     123                  %s
     124                  %s
     125                  %s
     126                  %s
     127                  %s
     128                  %s
     129                  # the expressions above have no effect, x == argument
     130                  while x:
     131                      x -= 1
     132                      # EXTENDED_ARG/JUMP_ABSOLUTE here
     133                  return x
     134              ''' % ((longexpr,)*10))
     135          exec(code, g)
     136          self.assertEqual(g['f'](5), 0)
     137  
     138      def test_argument_order(self):
     139          self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass')
     140  
     141      def test_float_literals(self):
     142          # testing bad float literals
     143          self.assertRaises(SyntaxError, eval, "2e")
     144          self.assertRaises(SyntaxError, eval, "2.0e+")
     145          self.assertRaises(SyntaxError, eval, "1e-")
     146          self.assertRaises(SyntaxError, eval, "3-4e/21")
     147  
     148      def test_indentation(self):
     149          # testing compile() of indented block w/o trailing newline"
     150          s = textwrap.dedent("""
     151              if 1:
     152                  if 2:
     153                      pass
     154              """)
     155          compile(s, "<string>", "exec")
     156  
     157      # This test is probably specific to CPython and may not generalize
     158      # to other implementations.  We are trying to ensure that when
     159      # the first line of code starts after 256, correct line numbers
     160      # in tracebacks are still produced.
     161      def test_leading_newlines(self):
     162          s256 = "".join(["\n"] * 256 + ["spam"])
     163          co = compile(s256, 'fn', 'exec')
     164          self.assertEqual(co.co_firstlineno, 1)
     165          lines = [line for _, _, line in co.co_lines()]
     166          self.assertEqual(lines, [0, 257])
     167  
     168      def test_literals_with_leading_zeroes(self):
     169          for arg in ["077787", "0xj", "0x.", "0e",  "090000000000000",
     170                      "080000000000000", "000000000000009", "000000000000008",
     171                      "0b42", "0BADCAFE", "0o123456789", "0b1.1", "0o4.2",
     172                      "0b101j", "0o153j", "0b100e1", "0o777e1", "0777",
     173                      "000777", "000000000000007"]:
     174              self.assertRaises(SyntaxError, eval, arg)
     175  
     176          self.assertEqual(eval("0xff"), 255)
     177          self.assertEqual(eval("0777."), 777)
     178          self.assertEqual(eval("0777.0"), 777)
     179          self.assertEqual(eval("000000000000000000000000000000000000000000000000000777e0"), 777)
     180          self.assertEqual(eval("0777e1"), 7770)
     181          self.assertEqual(eval("0e0"), 0)
     182          self.assertEqual(eval("0000e-012"), 0)
     183          self.assertEqual(eval("09.5"), 9.5)
     184          self.assertEqual(eval("0777j"), 777j)
     185          self.assertEqual(eval("000"), 0)
     186          self.assertEqual(eval("00j"), 0j)
     187          self.assertEqual(eval("00.0"), 0)
     188          self.assertEqual(eval("0e3"), 0)
     189          self.assertEqual(eval("090000000000000."), 90000000000000.)
     190          self.assertEqual(eval("090000000000000.0000000000000000000000"), 90000000000000.)
     191          self.assertEqual(eval("090000000000000e0"), 90000000000000.)
     192          self.assertEqual(eval("090000000000000e-0"), 90000000000000.)
     193          self.assertEqual(eval("090000000000000j"), 90000000000000j)
     194          self.assertEqual(eval("000000000000008."), 8.)
     195          self.assertEqual(eval("000000000000009."), 9.)
     196          self.assertEqual(eval("0b101010"), 42)
     197          self.assertEqual(eval("-0b000000000010"), -2)
     198          self.assertEqual(eval("0o777"), 511)
     199          self.assertEqual(eval("-0o0000010"), -8)
     200  
     201      def test_int_literals_too_long(self):
     202          n = 3000
     203          source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4"
     204          with support.adjust_int_max_str_digits(n):
     205              compile(source, "<long_int_pass>", "exec")  # no errors.
     206          with support.adjust_int_max_str_digits(n-1):
     207              with self.assertRaises(SyntaxError) as err_ctx:
     208                  compile(source, "<long_int_fail>", "exec")
     209              exc = err_ctx.exception
     210              self.assertEqual(exc.lineno, 3)
     211              self.assertIn('Exceeds the limit ', str(exc))
     212              self.assertIn(' Consider hexadecimal ', str(exc))
     213  
     214      def test_unary_minus(self):
     215          # Verify treatment of unary minus on negative numbers SF bug #660455
     216          if sys.maxsize == 2147483647:
     217              # 32-bit machine
     218              all_one_bits = '0xffffffff'
     219              self.assertEqual(eval(all_one_bits), 4294967295)
     220              self.assertEqual(eval("-" + all_one_bits), -4294967295)
     221          elif sys.maxsize == 9223372036854775807:
     222              # 64-bit machine
     223              all_one_bits = '0xffffffffffffffff'
     224              self.assertEqual(eval(all_one_bits), 18446744073709551615)
     225              self.assertEqual(eval("-" + all_one_bits), -18446744073709551615)
     226          else:
     227              self.fail("How many bits *does* this machine have???")
     228          # Verify treatment of constant folding on -(sys.maxsize+1)
     229          # i.e. -2147483648 on 32 bit platforms.  Should return int.
     230          self.assertIsInstance(eval("%s" % (-sys.maxsize - 1)), int)
     231          self.assertIsInstance(eval("%s" % (-sys.maxsize - 2)), int)
     232  
     233      if sys.maxsize == 9223372036854775807:
     234          def test_32_63_bit_values(self):
     235              a = +4294967296  # 1 << 32
     236              b = -4294967296  # 1 << 32
     237              c = +281474976710656  # 1 << 48
     238              d = -281474976710656  # 1 << 48
     239              e = +4611686018427387904  # 1 << 62
     240              f = -4611686018427387904  # 1 << 62
     241              g = +9223372036854775807  # 1 << 63 - 1
     242              h = -9223372036854775807  # 1 << 63 - 1
     243  
     244              for variable in self.test_32_63_bit_values.__code__.co_consts:
     245                  if variable is not None:
     246                      self.assertIsInstance(variable, int)
     247  
     248      def test_sequence_unpacking_error(self):
     249          # Verify sequence packing/unpacking with "or".  SF bug #757818
     250          i,j = (1, -1) or (-1, 1)
     251          self.assertEqual(i, 1)
     252          self.assertEqual(j, -1)
     253  
     254      def test_none_assignment(self):
     255          stmts = [
     256              'None = 0',
     257              'None += 0',
     258              '__builtins__.None = 0',
     259              'def None(): pass',
     260              'class None: pass',
     261              '(a, None) = 0, 0',
     262              'for None in range(10): pass',
     263              'def f(None): pass',
     264              'import None',
     265              'import x as None',
     266              'from x import None',
     267              'from x import y as None'
     268          ]
     269          for stmt in stmts:
     270              stmt += "\n"
     271              self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single')
     272              self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
     273  
     274      def test_import(self):
     275          succeed = [
     276              'import sys',
     277              'import os, sys',
     278              'import os as bar',
     279              'import os.path as bar',
     280              'from __future__ import nested_scopes, generators',
     281              'from __future__ import (nested_scopes,\ngenerators)',
     282              'from __future__ import (nested_scopes,\ngenerators,)',
     283              'from sys import stdin, stderr, stdout',
     284              'from sys import (stdin, stderr,\nstdout)',
     285              'from sys import (stdin, stderr,\nstdout,)',
     286              'from sys import (stdin\n, stderr, stdout)',
     287              'from sys import (stdin\n, stderr, stdout,)',
     288              'from sys import stdin as si, stdout as so, stderr as se',
     289              'from sys import (stdin as si, stdout as so, stderr as se)',
     290              'from sys import (stdin as si, stdout as so, stderr as se,)',
     291              ]
     292          fail = [
     293              'import (os, sys)',
     294              'import (os), (sys)',
     295              'import ((os), (sys))',
     296              'import (sys',
     297              'import sys)',
     298              'import (os,)',
     299              'import os As bar',
     300              'import os.path a bar',
     301              'from sys import stdin As stdout',
     302              'from sys import stdin a stdout',
     303              'from (sys) import stdin',
     304              'from __future__ import (nested_scopes',
     305              'from __future__ import nested_scopes)',
     306              'from __future__ import nested_scopes,\ngenerators',
     307              'from sys import (stdin',
     308              'from sys import stdin)',
     309              'from sys import stdin, stdout,\nstderr',
     310              'from sys import stdin si',
     311              'from sys import stdin,',
     312              'from sys import (*)',
     313              'from sys import (stdin,, stdout, stderr)',
     314              'from sys import (stdin, stdout),',
     315              ]
     316          for stmt in succeed:
     317              compile(stmt, 'tmp', 'exec')
     318          for stmt in fail:
     319              self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec')
     320  
     321      def test_for_distinct_code_objects(self):
     322          # SF bug 1048870
     323          def f():
     324              f1 = lambda x=1: x
     325              f2 = lambda x=2: x
     326              return f1, f2
     327          f1, f2 = f()
     328          self.assertNotEqual(id(f1.__code__), id(f2.__code__))
     329  
     330      def test_lambda_doc(self):
     331          l = lambda: "foo"
     332          self.assertIsNone(l.__doc__)
     333  
     334      def test_encoding(self):
     335          code = b'# -*- coding: badencoding -*-\npass\n'
     336          self.assertRaises(SyntaxError, compile, code, 'tmp', 'exec')
     337          code = '# -*- coding: badencoding -*-\n"\xc2\xa4"\n'
     338          compile(code, 'tmp', 'exec')
     339          self.assertEqual(eval(code), '\xc2\xa4')
     340          code = '"\xc2\xa4"\n'
     341          self.assertEqual(eval(code), '\xc2\xa4')
     342          code = b'"\xc2\xa4"\n'
     343          self.assertEqual(eval(code), '\xa4')
     344          code = b'# -*- coding: latin1 -*-\n"\xc2\xa4"\n'
     345          self.assertEqual(eval(code), '\xc2\xa4')
     346          code = b'# -*- coding: utf-8 -*-\n"\xc2\xa4"\n'
     347          self.assertEqual(eval(code), '\xa4')
     348          code = b'# -*- coding: iso8859-15 -*-\n"\xc2\xa4"\n'
     349          self.assertEqual(eval(code), '\xc2\u20ac')
     350          code = '"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
     351          self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xc2\xa4')
     352          code = b'"""\\\n# -*- coding: iso8859-15 -*-\n\xc2\xa4"""\n'
     353          self.assertEqual(eval(code), '# -*- coding: iso8859-15 -*-\n\xa4')
     354  
     355      def test_subscripts(self):
     356          # SF bug 1448804
     357          # Class to make testing subscript results easy
     358          class ESC[4;38;5;81mstr_map(ESC[4;38;5;149mobject):
     359              def __init__(self):
     360                  self.data = {}
     361              def __getitem__(self, key):
     362                  return self.data[str(key)]
     363              def __setitem__(self, key, value):
     364                  self.data[str(key)] = value
     365              def __delitem__(self, key):
     366                  del self.data[str(key)]
     367              def __contains__(self, key):
     368                  return str(key) in self.data
     369          d = str_map()
     370          # Index
     371          d[1] = 1
     372          self.assertEqual(d[1], 1)
     373          d[1] += 1
     374          self.assertEqual(d[1], 2)
     375          del d[1]
     376          self.assertNotIn(1, d)
     377          # Tuple of indices
     378          d[1, 1] = 1
     379          self.assertEqual(d[1, 1], 1)
     380          d[1, 1] += 1
     381          self.assertEqual(d[1, 1], 2)
     382          del d[1, 1]
     383          self.assertNotIn((1, 1), d)
     384          # Simple slice
     385          d[1:2] = 1
     386          self.assertEqual(d[1:2], 1)
     387          d[1:2] += 1
     388          self.assertEqual(d[1:2], 2)
     389          del d[1:2]
     390          self.assertNotIn(slice(1, 2), d)
     391          # Tuple of simple slices
     392          d[1:2, 1:2] = 1
     393          self.assertEqual(d[1:2, 1:2], 1)
     394          d[1:2, 1:2] += 1
     395          self.assertEqual(d[1:2, 1:2], 2)
     396          del d[1:2, 1:2]
     397          self.assertNotIn((slice(1, 2), slice(1, 2)), d)
     398          # Extended slice
     399          d[1:2:3] = 1
     400          self.assertEqual(d[1:2:3], 1)
     401          d[1:2:3] += 1
     402          self.assertEqual(d[1:2:3], 2)
     403          del d[1:2:3]
     404          self.assertNotIn(slice(1, 2, 3), d)
     405          # Tuple of extended slices
     406          d[1:2:3, 1:2:3] = 1
     407          self.assertEqual(d[1:2:3, 1:2:3], 1)
     408          d[1:2:3, 1:2:3] += 1
     409          self.assertEqual(d[1:2:3, 1:2:3], 2)
     410          del d[1:2:3, 1:2:3]
     411          self.assertNotIn((slice(1, 2, 3), slice(1, 2, 3)), d)
     412          # Ellipsis
     413          d[...] = 1
     414          self.assertEqual(d[...], 1)
     415          d[...] += 1
     416          self.assertEqual(d[...], 2)
     417          del d[...]
     418          self.assertNotIn(Ellipsis, d)
     419          # Tuple of Ellipses
     420          d[..., ...] = 1
     421          self.assertEqual(d[..., ...], 1)
     422          d[..., ...] += 1
     423          self.assertEqual(d[..., ...], 2)
     424          del d[..., ...]
     425          self.assertNotIn((Ellipsis, Ellipsis), d)
     426  
     427      def test_annotation_limit(self):
     428          # more than 255 annotations, should compile ok
     429          s = "def f(%s): pass"
     430          s %= ', '.join('a%d:%d' % (i,i) for i in range(300))
     431          compile(s, '?', 'exec')
     432  
     433      def test_mangling(self):
     434          class ESC[4;38;5;81mA:
     435              def f():
     436                  __mangled = 1
     437                  __not_mangled__ = 2
     438                  import __mangled_mod
     439                  import __package__.module
     440  
     441          self.assertIn("_A__mangled", A.f.__code__.co_varnames)
     442          self.assertIn("__not_mangled__", A.f.__code__.co_varnames)
     443          self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames)
     444          self.assertIn("__package__", A.f.__code__.co_varnames)
     445  
     446      def test_compile_ast(self):
     447          fname = __file__
     448          if fname.lower().endswith('pyc'):
     449              fname = fname[:-1]
     450          with open(fname, encoding='utf-8') as f:
     451              fcontents = f.read()
     452          sample_code = [
     453              ['<assign>', 'x = 5'],
     454              ['<ifblock>', """if True:\n    pass\n"""],
     455              ['<forblock>', """for n in [1, 2, 3]:\n    print(n)\n"""],
     456              ['<deffunc>', """def foo():\n    pass\nfoo()\n"""],
     457              [fname, fcontents],
     458          ]
     459  
     460          for fname, code in sample_code:
     461              co1 = compile(code, '%s1' % fname, 'exec')
     462              ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
     463              self.assertTrue(type(ast) == _ast.Module)
     464              co2 = compile(ast, '%s3' % fname, 'exec')
     465              self.assertEqual(co1, co2)
     466              # the code object's filename comes from the second compilation step
     467              self.assertEqual(co2.co_filename, '%s3' % fname)
     468  
     469          # raise exception when node type doesn't match with compile mode
     470          co1 = compile('print(1)', '<string>', 'exec', _ast.PyCF_ONLY_AST)
     471          self.assertRaises(TypeError, compile, co1, '<ast>', 'eval')
     472  
     473          # raise exception when node type is no start node
     474          self.assertRaises(TypeError, compile, _ast.If(), '<ast>', 'exec')
     475  
     476          # raise exception when node has invalid children
     477          ast = _ast.Module()
     478          ast.body = [_ast.BoolOp()]
     479          self.assertRaises(TypeError, compile, ast, '<ast>', 'exec')
     480  
     481      def test_compile_invalid_typealias(self):
     482          # gh-109341
     483          m = ast.Module(
     484              body=[
     485                  ast.TypeAlias(
     486                      name=ast.Subscript(
     487                          value=ast.Name(id="foo", ctx=ast.Load()),
     488                          slice=ast.Constant(value="x"),
     489                          ctx=ast.Store(),
     490                      ),
     491                      type_params=[],
     492                      value=ast.Name(id="Callable", ctx=ast.Load()),
     493                  )
     494              ],
     495              type_ignores=[],
     496          )
     497  
     498          with self.assertRaisesRegex(TypeError, "TypeAlias with non-Name name"):
     499              compile(ast.fix_missing_locations(m), "<file>", "exec")
     500  
     501      def test_dict_evaluation_order(self):
     502          i = 0
     503  
     504          def f():
     505              nonlocal i
     506              i += 1
     507              return i
     508  
     509          d = {f(): f(), f(): f()}
     510          self.assertEqual(d, {1: 2, 3: 4})
     511  
     512      def test_compile_filename(self):
     513          for filename in 'file.py', b'file.py':
     514              code = compile('pass', filename, 'exec')
     515              self.assertEqual(code.co_filename, 'file.py')
     516          for filename in bytearray(b'file.py'), memoryview(b'file.py'):
     517              with self.assertRaises(TypeError):
     518                  compile('pass', filename, 'exec')
     519          self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec')
     520  
     521      @support.cpython_only
     522      def test_same_filename_used(self):
     523          s = """def f(): pass\ndef g(): pass"""
     524          c = compile(s, "myfile", "exec")
     525          for obj in c.co_consts:
     526              if isinstance(obj, types.CodeType):
     527                  self.assertIs(obj.co_filename, c.co_filename)
     528  
     529      def test_single_statement(self):
     530          self.compile_single("1 + 2")
     531          self.compile_single("\n1 + 2")
     532          self.compile_single("1 + 2\n")
     533          self.compile_single("1 + 2\n\n")
     534          self.compile_single("1 + 2\t\t\n")
     535          self.compile_single("1 + 2\t\t\n        ")
     536          self.compile_single("1 + 2 # one plus two")
     537          self.compile_single("1; 2")
     538          self.compile_single("import sys; sys")
     539          self.compile_single("def f():\n   pass")
     540          self.compile_single("while False:\n   pass")
     541          self.compile_single("if x:\n   f(x)")
     542          self.compile_single("if x:\n   f(x)\nelse:\n   g(x)")
     543          self.compile_single("class T:\n   pass")
     544          self.compile_single("c = '''\na=1\nb=2\nc=3\n'''")
     545  
     546      def test_bad_single_statement(self):
     547          self.assertInvalidSingle('1\n2')
     548          self.assertInvalidSingle('def f(): pass')
     549          self.assertInvalidSingle('a = 13\nb = 187')
     550          self.assertInvalidSingle('del x\ndel y')
     551          self.assertInvalidSingle('f()\ng()')
     552          self.assertInvalidSingle('f()\n# blah\nblah()')
     553          self.assertInvalidSingle('f()\nxy # blah\nblah()')
     554          self.assertInvalidSingle('x = 5 # comment\nx = 6\n')
     555          self.assertInvalidSingle("c = '''\nd=1\n'''\na = 1\n\nb = 2\n")
     556  
     557      def test_particularly_evil_undecodable(self):
     558          # Issue 24022
     559          src = b'0000\x00\n00000000000\n\x00\n\x9e\n'
     560          with tempfile.TemporaryDirectory() as tmpd:
     561              fn = os.path.join(tmpd, "bad.py")
     562              with open(fn, "wb") as fp:
     563                  fp.write(src)
     564              res = script_helper.run_python_until_end(fn)[0]
     565          self.assertIn(b"source code cannot contain null bytes", res.err)
     566  
     567      def test_yet_more_evil_still_undecodable(self):
     568          # Issue #25388
     569          src = b"#\x00\n#\xfd\n"
     570          with tempfile.TemporaryDirectory() as tmpd:
     571              fn = os.path.join(tmpd, "bad.py")
     572              with open(fn, "wb") as fp:
     573                  fp.write(src)
     574              res = script_helper.run_python_until_end(fn)[0]
     575          self.assertIn(b"source code cannot contain null bytes", res.err)
     576  
     577      @support.cpython_only
     578      @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
     579      def test_compiler_recursion_limit(self):
     580          # Expected limit is C_RECURSION_LIMIT * 2
     581          # Duplicating the limit here is a little ugly.
     582          # Perhaps it should be exposed somewhere...
     583          fail_depth = C_RECURSION_LIMIT * 2 + 1
     584          crash_depth = C_RECURSION_LIMIT * 100
     585          success_depth = int(C_RECURSION_LIMIT * 1.8)
     586  
     587          def check_limit(prefix, repeated, mode="single"):
     588              expect_ok = prefix + repeated * success_depth
     589              compile(expect_ok, '<test>', mode)
     590              for depth in (fail_depth, crash_depth):
     591                  broken = prefix + repeated * depth
     592                  details = "Compiling ({!r} + {!r} * {})".format(
     593                              prefix, repeated, depth)
     594                  with self.assertRaises(RecursionError, msg=details):
     595                      compile(broken, '<test>', mode)
     596  
     597          check_limit("a", "()")
     598          check_limit("a", ".b")
     599          check_limit("a", "[0]")
     600          check_limit("a", "*a")
     601          # XXX Crashes in the parser.
     602          # check_limit("a", " if a else a")
     603          # check_limit("if a: pass", "\nelif a: pass", mode="exec")
     604  
     605      def test_null_terminated(self):
     606          # The source code is null-terminated internally, but bytes-like
     607          # objects are accepted, which could be not terminated.
     608          with self.assertRaisesRegex(SyntaxError, "cannot contain null"):
     609              compile("123\x00", "<dummy>", "eval")
     610          with self.assertRaisesRegex(SyntaxError, "cannot contain null"):
     611              compile(memoryview(b"123\x00"), "<dummy>", "eval")
     612          code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval")
     613          self.assertEqual(eval(code), 23)
     614          code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval")
     615          self.assertEqual(eval(code), 23)
     616          code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval")
     617          self.assertEqual(eval(code), 23)
     618  
     619          # Also test when eval() and exec() do the compilation step
     620          self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23)
     621          namespace = dict()
     622          exec(memoryview(b"ax = 123")[1:-1], namespace)
     623          self.assertEqual(namespace['x'], 12)
     624  
     625      def check_constant(self, func, expected):
     626          for const in func.__code__.co_consts:
     627              if repr(const) == repr(expected):
     628                  break
     629          else:
     630              self.fail("unable to find constant %r in %r"
     631                        % (expected, func.__code__.co_consts))
     632  
     633      # Merging equal constants is not a strict requirement for the Python
     634      # semantics, it's a more an implementation detail.
     635      @support.cpython_only
     636      def test_merge_constants(self):
     637          # Issue #25843: compile() must merge constants which are equal
     638          # and have the same type.
     639  
     640          def check_same_constant(const):
     641              ns = {}
     642              code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
     643              exec(code, ns)
     644              f1 = ns['f1']
     645              f2 = ns['f2']
     646              self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
     647              self.check_constant(f1, const)
     648              self.assertEqual(repr(f1()), repr(const))
     649  
     650          check_same_constant(None)
     651          check_same_constant(0)
     652          check_same_constant(0.0)
     653          check_same_constant(b'abc')
     654          check_same_constant('abc')
     655  
     656          # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
     657          # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
     658          f1, f2 = lambda: ..., lambda: ...
     659          self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
     660          self.check_constant(f1, Ellipsis)
     661          self.assertEqual(repr(f1()), repr(Ellipsis))
     662  
     663          # Merge constants in tuple or frozenset
     664          f1, f2 = lambda: "not a name", lambda: ("not a name",)
     665          f3 = lambda x: x in {("not a name",)}
     666          self.assertIs(f1.__code__.co_consts[1],
     667                        f2.__code__.co_consts[1][0])
     668          self.assertIs(next(iter(f3.__code__.co_consts[1])),
     669                        f2.__code__.co_consts[1])
     670  
     671          # {0} is converted to a constant frozenset({0}) by the peephole
     672          # optimizer
     673          f1, f2 = lambda x: x in {0}, lambda x: x in {0}
     674          self.assertIs(f1.__code__.co_consts, f2.__code__.co_consts)
     675          self.check_constant(f1, frozenset({0}))
     676          self.assertTrue(f1(0))
     677  
     678      # Merging equal co_linetable is not a strict requirement
     679      # for the Python semantics, it's a more an implementation detail.
     680      @support.cpython_only
     681      def test_merge_code_attrs(self):
     682          # See https://bugs.python.org/issue42217
     683          f1 = lambda x: x.y.z
     684          f2 = lambda a: a.b.c
     685  
     686          self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable)
     687  
     688      @support.cpython_only
     689      def test_remove_unused_consts(self):
     690          def f():
     691              "docstring"
     692              if True:
     693                  return "used"
     694              else:
     695                  return "unused"
     696  
     697          self.assertEqual(f.__code__.co_consts,
     698                           ("docstring", "used"))
     699  
     700      @support.cpython_only
     701      def test_remove_unused_consts_no_docstring(self):
     702          # the first item (None for no docstring in this case) is
     703          # always retained.
     704          def f():
     705              if True:
     706                  return "used"
     707              else:
     708                  return "unused"
     709  
     710          self.assertEqual(f.__code__.co_consts,
     711                           (None, "used"))
     712  
     713      @support.cpython_only
     714      def test_remove_unused_consts_extended_args(self):
     715          N = 1000
     716          code = ["def f():\n"]
     717          code.append("\ts = ''\n")
     718          code.append("\tfor i in range(1):\n")
     719          for i in range(N):
     720              code.append(f"\t\tif True: s += 't{i}'\n")
     721              code.append(f"\t\tif False: s += 'f{i}'\n")
     722          code.append("\treturn s\n")
     723  
     724          code = "".join(code)
     725          g = {}
     726          eval(compile(code, "file.py", "exec"), g)
     727          exec(code, g)
     728          f = g['f']
     729          expected = tuple([None, '', 1] + [f't{i}' for i in range(N)])
     730          self.assertEqual(f.__code__.co_consts, expected)
     731          expected = "".join(expected[3:])
     732          self.assertEqual(expected, f())
     733  
     734      # Stripping unused constants is not a strict requirement for the
     735      # Python semantics, it's a more an implementation detail.
     736      @support.cpython_only
     737      def test_strip_unused_None(self):
     738          # Python 3.10rc1 appended None to co_consts when None is not used
     739          # at all. See bpo-45056.
     740          def f1():
     741              "docstring"
     742              return 42
     743          self.assertEqual(f1.__code__.co_consts, ("docstring", 42))
     744  
     745      # This is a regression test for a CPython specific peephole optimizer
     746      # implementation bug present in a few releases.  It's assertion verifies
     747      # that peephole optimization was actually done though that isn't an
     748      # indication of the bugs presence or not (crashing is).
     749      @support.cpython_only
     750      def test_peephole_opt_unreachable_code_array_access_in_bounds(self):
     751          """Regression test for issue35193 when run under clang msan."""
     752          def unused_code_at_end():
     753              return 3
     754              raise RuntimeError("unreachable")
     755          # The above function definition will trigger the out of bounds
     756          # bug in the peephole optimizer as it scans opcodes past the
     757          # RETURN_VALUE opcode.  This does not always crash an interpreter.
     758          # When you build with the clang memory sanitizer it reliably aborts.
     759          self.assertEqual(
     760              'RETURN_CONST',
     761              list(dis.get_instructions(unused_code_at_end))[-1].opname)
     762  
     763      def test_dont_merge_constants(self):
     764          # Issue #25843: compile() must not merge constants which are equal
     765          # but have a different type.
     766  
     767          def check_different_constants(const1, const2):
     768              ns = {}
     769              exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
     770              f1 = ns['f1']
     771              f2 = ns['f2']
     772              self.assertIsNot(f1.__code__, f2.__code__)
     773              self.assertNotEqual(f1.__code__, f2.__code__)
     774              self.check_constant(f1, const1)
     775              self.check_constant(f2, const2)
     776              self.assertEqual(repr(f1()), repr(const1))
     777              self.assertEqual(repr(f2()), repr(const2))
     778  
     779          check_different_constants(0, 0.0)
     780          check_different_constants(+0.0, -0.0)
     781          check_different_constants((0,), (0.0,))
     782          check_different_constants('a', b'a')
     783          check_different_constants(('a',), (b'a',))
     784  
     785          # check_different_constants() cannot be used because repr(-0j) is
     786          # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
     787          f1, f2 = lambda: +0.0j, lambda: -0.0j
     788          self.assertIsNot(f1.__code__, f2.__code__)
     789          self.check_constant(f1, +0.0j)
     790          self.check_constant(f2, -0.0j)
     791          self.assertEqual(repr(f1()), repr(+0.0j))
     792          self.assertEqual(repr(f2()), repr(-0.0j))
     793  
     794          # {0} is converted to a constant frozenset({0}) by the peephole
     795          # optimizer
     796          f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
     797          self.assertIsNot(f1.__code__, f2.__code__)
     798          self.check_constant(f1, frozenset({0}))
     799          self.check_constant(f2, frozenset({0.0}))
     800          self.assertTrue(f1(0))
     801          self.assertTrue(f2(0.0))
     802  
     803      def test_path_like_objects(self):
     804          # An implicit test for PyUnicode_FSDecoder().
     805          compile("42", FakePath("test_compile_pathlike"), "single")
     806  
     807      @support.requires_resource('cpu')
     808      def test_stack_overflow(self):
     809          # bpo-31113: Stack overflow when compile a long sequence of
     810          # complex statements.
     811          compile("if a: b\n" * 200000, "<dummy>", "exec")
     812  
     813      # Multiple users rely on the fact that CPython does not generate
     814      # bytecode for dead code blocks. See bpo-37500 for more context.
     815      @support.cpython_only
     816      def test_dead_blocks_do_not_generate_bytecode(self):
     817          def unused_block_if():
     818              if 0:
     819                  return 42
     820  
     821          def unused_block_while():
     822              while 0:
     823                  return 42
     824  
     825          def unused_block_if_else():
     826              if 1:
     827                  return None
     828              else:
     829                  return 42
     830  
     831          def unused_block_while_else():
     832              while 1:
     833                  return None
     834              else:
     835                  return 42
     836  
     837          funcs = [unused_block_if, unused_block_while,
     838                   unused_block_if_else, unused_block_while_else]
     839  
     840          for func in funcs:
     841              opcodes = list(dis.get_instructions(func))
     842              self.assertLessEqual(len(opcodes), 3)
     843              self.assertEqual('RETURN_CONST', opcodes[-1].opname)
     844              self.assertEqual(None, opcodes[-1].argval)
     845  
     846      def test_false_while_loop(self):
     847          def break_in_while():
     848              while False:
     849                  break
     850  
     851          def continue_in_while():
     852              while False:
     853                  continue
     854  
     855          funcs = [break_in_while, continue_in_while]
     856  
     857          # Check that we did not raise but we also don't generate bytecode
     858          for func in funcs:
     859              opcodes = list(dis.get_instructions(func))
     860              self.assertEqual(2, len(opcodes))
     861              self.assertEqual('RETURN_CONST', opcodes[1].opname)
     862              self.assertEqual(None, opcodes[1].argval)
     863  
     864      def test_consts_in_conditionals(self):
     865          def and_true(x):
     866              return True and x
     867  
     868          def and_false(x):
     869              return False and x
     870  
     871          def or_true(x):
     872              return True or x
     873  
     874          def or_false(x):
     875              return False or x
     876  
     877          funcs = [and_true, and_false, or_true, or_false]
     878  
     879          # Check that condition is removed.
     880          for func in funcs:
     881              with self.subTest(func=func):
     882                  opcodes = list(dis.get_instructions(func))
     883                  self.assertLessEqual(len(opcodes), 3)
     884                  self.assertIn('LOAD_', opcodes[-2].opname)
     885                  self.assertEqual('RETURN_VALUE', opcodes[-1].opname)
     886  
     887      def test_imported_load_method(self):
     888          sources = [
     889              """\
     890              import os
     891              def foo():
     892                  return os.uname()
     893              """,
     894              """\
     895              import os as operating_system
     896              def foo():
     897                  return operating_system.uname()
     898              """,
     899              """\
     900              from os import path
     901              def foo(x):
     902                  return path.join(x)
     903              """,
     904              """\
     905              from os import path as os_path
     906              def foo(x):
     907                  return os_path.join(x)
     908              """
     909          ]
     910          for source in sources:
     911              namespace = {}
     912              exec(textwrap.dedent(source), namespace)
     913              func = namespace['foo']
     914              with self.subTest(func=func.__name__):
     915                  opcodes = list(dis.get_instructions(func))
     916                  instructions = [opcode.opname for opcode in opcodes]
     917                  self.assertNotIn('LOAD_METHOD', instructions)
     918                  self.assertIn('LOAD_ATTR', instructions)
     919                  self.assertIn('CALL', instructions)
     920  
     921      def test_lineno_procedure_call(self):
     922          def call():
     923              (
     924                  print()
     925              )
     926          line1 = call.__code__.co_firstlineno + 1
     927          assert line1 not in [line for (_, _, line) in call.__code__.co_lines()]
     928  
     929      def test_lineno_after_implicit_return(self):
     930          TRUE = True
     931          # Don't use constant True or False, as compiler will remove test
     932          def if1(x):
     933              x()
     934              if TRUE:
     935                  pass
     936          def if2(x):
     937              x()
     938              if TRUE:
     939                  pass
     940              else:
     941                  pass
     942          def if3(x):
     943              x()
     944              if TRUE:
     945                  pass
     946              else:
     947                  return None
     948          def if4(x):
     949              x()
     950              if not TRUE:
     951                  pass
     952          funcs = [ if1, if2, if3, if4]
     953          lastlines = [ 3, 3, 3, 2]
     954          frame = None
     955          def save_caller_frame():
     956              nonlocal frame
     957              frame = sys._getframe(1)
     958          for func, lastline in zip(funcs, lastlines, strict=True):
     959              with self.subTest(func=func):
     960                  func(save_caller_frame)
     961                  self.assertEqual(frame.f_lineno-frame.f_code.co_firstlineno, lastline)
     962  
     963      def test_lineno_after_no_code(self):
     964          def no_code1():
     965              "doc string"
     966  
     967          def no_code2():
     968              a: int
     969  
     970          for func in (no_code1, no_code2):
     971              with self.subTest(func=func):
     972                  code = func.__code__
     973                  [(start, end, line)] = code.co_lines()
     974                  self.assertEqual(start, 0)
     975                  self.assertEqual(end, len(code.co_code))
     976                  self.assertEqual(line, code.co_firstlineno)
     977  
     978      def get_code_lines(self, code):
     979          last_line = -2
     980          res = []
     981          for _, _, line in code.co_lines():
     982              if line is not None and line != last_line:
     983                  res.append(line - code.co_firstlineno)
     984                  last_line = line
     985          return res
     986  
     987      def test_lineno_attribute(self):
     988          def load_attr():
     989              return (
     990                  o.
     991                  a
     992              )
     993          load_attr_lines = [ 0, 2, 3, 1 ]
     994  
     995          def load_method():
     996              return (
     997                  o.
     998                  m(
     999                      0
    1000                  )
    1001              )
    1002          load_method_lines = [ 0, 2, 3, 4, 3, 1 ]
    1003  
    1004          def store_attr():
    1005              (
    1006                  o.
    1007                  a
    1008              ) = (
    1009                  v
    1010              )
    1011          store_attr_lines = [ 0, 5, 2, 3 ]
    1012  
    1013          def aug_store_attr():
    1014              (
    1015                  o.
    1016                  a
    1017              ) += (
    1018                  v
    1019              )
    1020          aug_store_attr_lines = [ 0, 2, 3, 5, 1, 3 ]
    1021  
    1022          funcs = [ load_attr, load_method, store_attr, aug_store_attr]
    1023          func_lines = [ load_attr_lines, load_method_lines,
    1024                   store_attr_lines, aug_store_attr_lines]
    1025  
    1026          for func, lines in zip(funcs, func_lines, strict=True):
    1027              with self.subTest(func=func):
    1028                  code_lines = self.get_code_lines(func.__code__)
    1029                  self.assertEqual(lines, code_lines)
    1030  
    1031      def test_line_number_genexp(self):
    1032  
    1033          def return_genexp():
    1034              return (1
    1035                      for
    1036                      x
    1037                      in
    1038                      y)
    1039          genexp_lines = [0, 2, 0]
    1040  
    1041          genexp_code = return_genexp.__code__.co_consts[1]
    1042          code_lines = self.get_code_lines(genexp_code)
    1043          self.assertEqual(genexp_lines, code_lines)
    1044  
    1045      def test_line_number_implicit_return_after_async_for(self):
    1046  
    1047          async def test(aseq):
    1048              async for i in aseq:
    1049                  body
    1050  
    1051          expected_lines = [0, 1, 2, 1]
    1052          code_lines = self.get_code_lines(test.__code__)
    1053          self.assertEqual(expected_lines, code_lines)
    1054  
    1055      def test_lineno_of_backward_jump(self):
    1056          # Issue gh-107901
    1057          def f():
    1058              for i in x:
    1059                  if y:
    1060                      pass
    1061  
    1062          linenos = list(inst.positions.lineno
    1063                         for inst in dis.get_instructions(f.__code__)
    1064                         if inst.opname == 'JUMP_BACKWARD')
    1065  
    1066          self.assertTrue(len(linenos) > 0)
    1067          self.assertTrue(all(l is not None for l in linenos))
    1068  
    1069      def test_big_dict_literal(self):
    1070          # The compiler has a flushing point in "compiler_dict" that calls compiles
    1071          # a portion of the dictionary literal when the loop that iterates over the items
    1072          # reaches 0xFFFF elements but the code was not including the boundary element,
    1073          # dropping the key at position 0xFFFF. See bpo-41531 for more information
    1074  
    1075          dict_size = 0xFFFF + 1
    1076          the_dict = "{" + ",".join(f"{x}:{x}" for x in range(dict_size)) + "}"
    1077          self.assertEqual(len(eval(the_dict)), dict_size)
    1078  
    1079      def test_redundant_jump_in_if_else_break(self):
    1080          # Check if bytecode containing jumps that simply point to the next line
    1081          # is generated around if-else-break style structures. See bpo-42615.
    1082  
    1083          def if_else_break():
    1084              val = 1
    1085              while True:
    1086                  if val > 0:
    1087                      val -= 1
    1088                  else:
    1089                      break
    1090                  val = -1
    1091  
    1092          INSTR_SIZE = 2
    1093          HANDLED_JUMPS = (
    1094              'POP_JUMP_IF_FALSE',
    1095              'POP_JUMP_IF_TRUE',
    1096              'JUMP_ABSOLUTE',
    1097              'JUMP_FORWARD',
    1098          )
    1099  
    1100          for line, instr in enumerate(
    1101              dis.Bytecode(if_else_break, show_caches=True)
    1102          ):
    1103              if instr.opname == 'JUMP_FORWARD':
    1104                  self.assertNotEqual(instr.arg, 0)
    1105              elif instr.opname in HANDLED_JUMPS:
    1106                  self.assertNotEqual(instr.arg, (line + 1)*INSTR_SIZE)
    1107  
    1108      def test_no_wraparound_jump(self):
    1109          # See https://bugs.python.org/issue46724
    1110  
    1111          def while_not_chained(a, b, c):
    1112              while not (a < b < c):
    1113                  pass
    1114  
    1115          for instr in dis.Bytecode(while_not_chained):
    1116              self.assertNotEqual(instr.opname, "EXTENDED_ARG")
    1117  
    1118      @support.cpython_only
    1119      def test_uses_slice_instructions(self):
    1120  
    1121          def check_op_count(func, op, expected):
    1122              actual = 0
    1123              for instr in dis.Bytecode(func):
    1124                  if instr.opname == op:
    1125                      actual += 1
    1126              self.assertEqual(actual, expected)
    1127  
    1128          def load():
    1129              return x[a:b] + x [a:] + x[:b] + x[:]
    1130  
    1131          def store():
    1132              x[a:b] = y
    1133              x [a:] = y
    1134              x[:b] = y
    1135              x[:] = y
    1136  
    1137          def long_slice():
    1138              return x[a:b:c]
    1139  
    1140          def aug():
    1141              x[a:b] += y
    1142  
    1143          check_op_count(load, "BINARY_SLICE", 4)
    1144          check_op_count(load, "BUILD_SLICE", 0)
    1145          check_op_count(store, "STORE_SLICE", 4)
    1146          check_op_count(store, "BUILD_SLICE", 0)
    1147          check_op_count(long_slice, "BUILD_SLICE", 1)
    1148          check_op_count(long_slice, "BINARY_SLICE", 0)
    1149          check_op_count(aug, "BINARY_SLICE", 1)
    1150          check_op_count(aug, "STORE_SLICE", 1)
    1151          check_op_count(aug, "BUILD_SLICE", 0)
    1152  
    1153      def test_compare_positions(self):
    1154          for opname_prefix, op in [
    1155              ("COMPARE_", "<"),
    1156              ("COMPARE_", "<="),
    1157              ("COMPARE_", ">"),
    1158              ("COMPARE_", ">="),
    1159              ("CONTAINS_OP", "in"),
    1160              ("CONTAINS_OP", "not in"),
    1161              ("IS_OP", "is"),
    1162              ("IS_OP", "is not"),
    1163          ]:
    1164              expr = f'a {op} b {op} c'
    1165              expected_positions = 2 * [(2, 2, 0, len(expr))]
    1166              for source in [
    1167                  f"\\\n{expr}", f'if \\\n{expr}: x', f"x if \\\n{expr} else y"
    1168              ]:
    1169                  code = compile(source, "<test>", "exec")
    1170                  actual_positions = [
    1171                      instruction.positions
    1172                      for instruction in dis.get_instructions(code)
    1173                      if instruction.opname.startswith(opname_prefix)
    1174                  ]
    1175                  with self.subTest(source):
    1176                      self.assertEqual(actual_positions, expected_positions)
    1177  
    1178      def test_if_expression_expression_empty_block(self):
    1179          # See regression in gh-99708
    1180          exprs = [
    1181              "assert (False if 1 else True)",
    1182              "def f():\n\tif not (False if 1 else True): raise AssertionError",
    1183              "def f():\n\tif not (False if 1 else True): return 12",
    1184          ]
    1185          for expr in exprs:
    1186              with self.subTest(expr=expr):
    1187                  compile(expr, "<single>", "exec")
    1188  
    1189      def test_multi_line_lambda_as_argument(self):
    1190          # See gh-101928
    1191          code = textwrap.dedent("""
    1192              def foo(param, lambda_exp):
    1193                  pass
    1194  
    1195              foo(param=0,
    1196                  lambda_exp=lambda:
    1197                  1)
    1198          """)
    1199          compile(code, "<test>", "exec")
    1200  
    1201      def test_apply_static_swaps(self):
    1202          def f(x, y):
    1203              a, a = x, y
    1204              return a
    1205          self.assertEqual(f("x", "y"), "y")
    1206  
    1207      def test_apply_static_swaps_2(self):
    1208          def f(x, y, z):
    1209              a, b, a = x, y, z
    1210              return a
    1211          self.assertEqual(f("x", "y", "z"), "z")
    1212  
    1213      def test_apply_static_swaps_3(self):
    1214          def f(x, y, z):
    1215              a, a, b = x, y, z
    1216              return a
    1217          self.assertEqual(f("x", "y", "z"), "y")
    1218  
    1219      def test_duplicated_small_exit_block(self):
    1220          # See gh-109627
    1221          def f():
    1222              while element and something:
    1223                  try:
    1224                      return something
    1225                  except:
    1226                      pass
    1227  
    1228      def test_cold_block_moved_to_end(self):
    1229          # See gh-109719
    1230          def f():
    1231              while name:
    1232                  try:
    1233                      break
    1234                  except:
    1235                      pass
    1236              else:
    1237                  1 if 1 else 1
    1238  
    1239      def test_remove_empty_basic_block_with_jump_target_label(self):
    1240          # See gh-109823
    1241          def f(x):
    1242              while x:
    1243                  0 if 1 else 0
    1244  
    1245  @requires_debug_ranges()
    1246  class ESC[4;38;5;81mTestSourcePositions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1247      # Ensure that compiled code snippets have correct line and column numbers
    1248      # in `co_positions()`.
    1249  
    1250      def check_positions_against_ast(self, snippet):
    1251          # Basic check that makes sure each line and column is at least present
    1252          # in one of the AST nodes of the source code.
    1253          code = compile(snippet, 'test_compile.py', 'exec')
    1254          ast_tree = compile(snippet, 'test_compile.py', 'exec', _ast.PyCF_ONLY_AST)
    1255          self.assertTrue(type(ast_tree) == _ast.Module)
    1256  
    1257          # Use an AST visitor that notes all the offsets.
    1258          lines, end_lines, columns, end_columns = set(), set(), set(), set()
    1259          class ESC[4;38;5;81mSourceOffsetVisitor(ESC[4;38;5;149mastESC[4;38;5;149m.ESC[4;38;5;149mNodeVisitor):
    1260              def generic_visit(self, node):
    1261                  super().generic_visit(node)
    1262                  if not isinstance(node, (ast.expr, ast.stmt, ast.pattern)):
    1263                      return
    1264                  lines.add(node.lineno)
    1265                  end_lines.add(node.end_lineno)
    1266                  columns.add(node.col_offset)
    1267                  end_columns.add(node.end_col_offset)
    1268  
    1269          SourceOffsetVisitor().visit(ast_tree)
    1270  
    1271          # Check against the positions in the code object.
    1272          for (line, end_line, col, end_col) in code.co_positions():
    1273              if line == 0:
    1274                  continue # This is an artificial module-start line
    1275              # If the offset is not None (indicating missing data), ensure that
    1276              # it was part of one of the AST nodes.
    1277              if line is not None:
    1278                  self.assertIn(line, lines)
    1279              if end_line is not None:
    1280                  self.assertIn(end_line, end_lines)
    1281              if col is not None:
    1282                  self.assertIn(col, columns)
    1283              if end_col is not None:
    1284                  self.assertIn(end_col, end_columns)
    1285  
    1286          return code, ast_tree
    1287  
    1288      def assertOpcodeSourcePositionIs(self, code, opcode,
    1289              line, end_line, column, end_column, occurrence=1):
    1290  
    1291          for instr, position in zip(
    1292              dis.Bytecode(code, show_caches=True), code.co_positions(), strict=True
    1293          ):
    1294              if instr.opname == opcode:
    1295                  occurrence -= 1
    1296                  if not occurrence:
    1297                      self.assertEqual(position[0], line)
    1298                      self.assertEqual(position[1], end_line)
    1299                      self.assertEqual(position[2], column)
    1300                      self.assertEqual(position[3], end_column)
    1301                      return
    1302  
    1303          self.fail(f"Opcode {opcode} not found in code")
    1304  
    1305      def test_simple_assignment(self):
    1306          snippet = "x = 1"
    1307          self.check_positions_against_ast(snippet)
    1308  
    1309      def test_compiles_to_extended_op_arg(self):
    1310          # Make sure we still have valid positions when the code compiles to an
    1311          # EXTENDED_ARG by performing a loop which needs a JUMP_ABSOLUTE after
    1312          # a bunch of opcodes.
    1313          snippet = "x = x\n" * 10_000
    1314          snippet += ("while x != 0:\n"
    1315                      "  x -= 1\n"
    1316                      "while x != 0:\n"
    1317                      "  x +=  1\n"
    1318                     )
    1319  
    1320          compiled_code, _ = self.check_positions_against_ast(snippet)
    1321  
    1322          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1323              line=10_000 + 2, end_line=10_000 + 2,
    1324              column=2, end_column=8, occurrence=1)
    1325          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1326              line=10_000 + 4, end_line=10_000 + 4,
    1327              column=2, end_column=9, occurrence=2)
    1328  
    1329      def test_multiline_expression(self):
    1330          snippet = textwrap.dedent("""\
    1331              f(
    1332                  1, 2, 3, 4
    1333              )
    1334              """)
    1335          compiled_code, _ = self.check_positions_against_ast(snippet)
    1336          self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
    1337              line=1, end_line=3, column=0, end_column=1)
    1338  
    1339      @requires_specialization
    1340      def test_multiline_boolean_expression(self):
    1341          snippet = textwrap.dedent("""\
    1342              if (a or
    1343                  (b and not c) or
    1344                  not (
    1345                      d > 0)):
    1346                  x = 42
    1347              """)
    1348          compiled_code, _ = self.check_positions_against_ast(snippet)
    1349          # jump if a is true:
    1350          self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE',
    1351              line=1, end_line=1, column=4, end_column=5, occurrence=1)
    1352          # jump if b is false:
    1353          self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE',
    1354              line=2, end_line=2, column=5, end_column=6, occurrence=1)
    1355          # jump if c is false:
    1356          self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE',
    1357              line=2, end_line=2, column=15, end_column=16, occurrence=2)
    1358          # compare d and 0
    1359          self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_OP',
    1360              line=4, end_line=4, column=8, end_column=13, occurrence=1)
    1361          # jump if comparison it True
    1362          self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE',
    1363              line=4, end_line=4, column=8, end_column=13, occurrence=2)
    1364  
    1365      def test_multiline_assert(self):
    1366          snippet = textwrap.dedent("""\
    1367              assert (a > 0 and
    1368                      bb > 0 and
    1369                      ccc == 4), "error msg"
    1370              """)
    1371          compiled_code, _ = self.check_positions_against_ast(snippet)
    1372          self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_ASSERTION_ERROR',
    1373              line=1, end_line=3, column=0, end_column=30, occurrence=1)
    1374          #  The "error msg":
    1375          self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_CONST',
    1376              line=3, end_line=3, column=19, end_column=30, occurrence=4)
    1377          self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
    1378              line=1, end_line=3, column=0, end_column=30, occurrence=1)
    1379          self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS',
    1380              line=1, end_line=3, column=0, end_column=30, occurrence=1)
    1381  
    1382      def test_multiline_generator_expression(self):
    1383          snippet = textwrap.dedent("""\
    1384              ((x,
    1385                  2*x)
    1386                  for x
    1387                  in [1,2,3] if (x > 0
    1388                                 and x < 100
    1389                                 and x != 50))
    1390              """)
    1391          compiled_code, _ = self.check_positions_against_ast(snippet)
    1392          compiled_code = compiled_code.co_consts[0]
    1393          self.assertIsInstance(compiled_code, types.CodeType)
    1394          self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE',
    1395              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1396          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1397              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1398          self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
    1399              line=1, end_line=6, column=0, end_column=32, occurrence=1)
    1400  
    1401      def test_multiline_async_generator_expression(self):
    1402          snippet = textwrap.dedent("""\
    1403              ((x,
    1404                  2*x)
    1405                  async for x
    1406                  in [1,2,3] if (x > 0
    1407                                 and x < 100
    1408                                 and x != 50))
    1409              """)
    1410          compiled_code, _ = self.check_positions_against_ast(snippet)
    1411          compiled_code = compiled_code.co_consts[0]
    1412          self.assertIsInstance(compiled_code, types.CodeType)
    1413          self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE',
    1414              line=1, end_line=2, column=1, end_column=8, occurrence=2)
    1415          self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
    1416              line=1, end_line=6, column=0, end_column=32, occurrence=1)
    1417  
    1418      def test_multiline_list_comprehension(self):
    1419          snippet = textwrap.dedent("""\
    1420              [(x,
    1421                  2*x)
    1422                  for x
    1423                  in [1,2,3] if (x > 0
    1424                                 and x < 100
    1425                                 and x != 50)]
    1426              """)
    1427          compiled_code, _ = self.check_positions_against_ast(snippet)
    1428          self.assertIsInstance(compiled_code, types.CodeType)
    1429          self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND',
    1430              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1431          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1432              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1433  
    1434      def test_multiline_async_list_comprehension(self):
    1435          snippet = textwrap.dedent("""\
    1436              async def f():
    1437                  [(x,
    1438                      2*x)
    1439                      async for x
    1440                      in [1,2,3] if (x > 0
    1441                                     and x < 100
    1442                                     and x != 50)]
    1443              """)
    1444          compiled_code, _ = self.check_positions_against_ast(snippet)
    1445          g = {}
    1446          eval(compiled_code, g)
    1447          compiled_code = g['f'].__code__
    1448          self.assertIsInstance(compiled_code, types.CodeType)
    1449          self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND',
    1450              line=2, end_line=3, column=5, end_column=12, occurrence=1)
    1451          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1452              line=2, end_line=3, column=5, end_column=12, occurrence=1)
    1453          self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
    1454              line=2, end_line=7, column=4, end_column=36, occurrence=1)
    1455  
    1456      def test_multiline_set_comprehension(self):
    1457          snippet = textwrap.dedent("""\
    1458              {(x,
    1459                  2*x)
    1460                  for x
    1461                  in [1,2,3] if (x > 0
    1462                                 and x < 100
    1463                                 and x != 50)}
    1464              """)
    1465          compiled_code, _ = self.check_positions_against_ast(snippet)
    1466          self.assertIsInstance(compiled_code, types.CodeType)
    1467          self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD',
    1468              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1469          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1470              line=1, end_line=2, column=1, end_column=8, occurrence=1)
    1471  
    1472      def test_multiline_async_set_comprehension(self):
    1473          snippet = textwrap.dedent("""\
    1474              async def f():
    1475                  {(x,
    1476                      2*x)
    1477                      async for x
    1478                      in [1,2,3] if (x > 0
    1479                                     and x < 100
    1480                                     and x != 50)}
    1481              """)
    1482          compiled_code, _ = self.check_positions_against_ast(snippet)
    1483          g = {}
    1484          eval(compiled_code, g)
    1485          compiled_code = g['f'].__code__
    1486          self.assertIsInstance(compiled_code, types.CodeType)
    1487          self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD',
    1488              line=2, end_line=3, column=5, end_column=12, occurrence=1)
    1489          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1490              line=2, end_line=3, column=5, end_column=12, occurrence=1)
    1491          self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
    1492              line=2, end_line=7, column=4, end_column=36, occurrence=1)
    1493  
    1494      def test_multiline_dict_comprehension(self):
    1495          snippet = textwrap.dedent("""\
    1496              {x:
    1497                  2*x
    1498                  for x
    1499                  in [1,2,3] if (x > 0
    1500                                 and x < 100
    1501                                 and x != 50)}
    1502              """)
    1503          compiled_code, _ = self.check_positions_against_ast(snippet)
    1504          self.assertIsInstance(compiled_code, types.CodeType)
    1505          self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD',
    1506              line=1, end_line=2, column=1, end_column=7, occurrence=1)
    1507          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1508              line=1, end_line=2, column=1, end_column=7, occurrence=1)
    1509  
    1510      def test_multiline_async_dict_comprehension(self):
    1511          snippet = textwrap.dedent("""\
    1512              async def f():
    1513                  {x:
    1514                      2*x
    1515                      async for x
    1516                      in [1,2,3] if (x > 0
    1517                                     and x < 100
    1518                                     and x != 50)}
    1519              """)
    1520          compiled_code, _ = self.check_positions_against_ast(snippet)
    1521          g = {}
    1522          eval(compiled_code, g)
    1523          compiled_code = g['f'].__code__
    1524          self.assertIsInstance(compiled_code, types.CodeType)
    1525          self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD',
    1526              line=2, end_line=3, column=5, end_column=11, occurrence=1)
    1527          self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
    1528              line=2, end_line=3, column=5, end_column=11, occurrence=1)
    1529          self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
    1530              line=2, end_line=7, column=4, end_column=36, occurrence=1)
    1531  
    1532      def test_matchcase_sequence(self):
    1533          snippet = textwrap.dedent("""\
    1534              match x:
    1535                  case a, b:
    1536                      pass
    1537              """)
    1538          compiled_code, _ = self.check_positions_against_ast(snippet)
    1539          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_SEQUENCE',
    1540              line=2, end_line=2, column=9, end_column=13, occurrence=1)
    1541          self.assertOpcodeSourcePositionIs(compiled_code, 'UNPACK_SEQUENCE',
    1542              line=2, end_line=2, column=9, end_column=13, occurrence=1)
    1543          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1544              line=2, end_line=2, column=9, end_column=13, occurrence=1)
    1545          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1546              line=2, end_line=2, column=9, end_column=13, occurrence=2)
    1547  
    1548      def test_matchcase_sequence_wildcard(self):
    1549          snippet = textwrap.dedent("""\
    1550              match x:
    1551                  case a, *b, c:
    1552                      pass
    1553              """)
    1554          compiled_code, _ = self.check_positions_against_ast(snippet)
    1555          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_SEQUENCE',
    1556              line=2, end_line=2, column=9, end_column=17, occurrence=1)
    1557          self.assertOpcodeSourcePositionIs(compiled_code, 'UNPACK_EX',
    1558              line=2, end_line=2, column=9, end_column=17, occurrence=1)
    1559          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1560              line=2, end_line=2, column=9, end_column=17, occurrence=1)
    1561          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1562              line=2, end_line=2, column=9, end_column=17, occurrence=2)
    1563          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1564              line=2, end_line=2, column=9, end_column=17, occurrence=3)
    1565  
    1566      def test_matchcase_mapping(self):
    1567          snippet = textwrap.dedent("""\
    1568              match x:
    1569                  case {"a" : a, "b": b}:
    1570                      pass
    1571              """)
    1572          compiled_code, _ = self.check_positions_against_ast(snippet)
    1573          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_MAPPING',
    1574              line=2, end_line=2, column=9, end_column=26, occurrence=1)
    1575          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_KEYS',
    1576              line=2, end_line=2, column=9, end_column=26, occurrence=1)
    1577          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1578              line=2, end_line=2, column=9, end_column=26, occurrence=1)
    1579          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1580              line=2, end_line=2, column=9, end_column=26, occurrence=2)
    1581  
    1582      def test_matchcase_mapping_wildcard(self):
    1583          snippet = textwrap.dedent("""\
    1584              match x:
    1585                  case {"a" : a, "b": b, **c}:
    1586                      pass
    1587              """)
    1588          compiled_code, _ = self.check_positions_against_ast(snippet)
    1589          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_MAPPING',
    1590              line=2, end_line=2, column=9, end_column=31, occurrence=1)
    1591          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_KEYS',
    1592              line=2, end_line=2, column=9, end_column=31, occurrence=1)
    1593          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1594              line=2, end_line=2, column=9, end_column=31, occurrence=1)
    1595          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1596              line=2, end_line=2, column=9, end_column=31, occurrence=2)
    1597  
    1598      def test_matchcase_class(self):
    1599          snippet = textwrap.dedent("""\
    1600              match x:
    1601                  case C(a, b):
    1602                      pass
    1603              """)
    1604          compiled_code, _ = self.check_positions_against_ast(snippet)
    1605          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_CLASS',
    1606              line=2, end_line=2, column=9, end_column=16, occurrence=1)
    1607          self.assertOpcodeSourcePositionIs(compiled_code, 'UNPACK_SEQUENCE',
    1608              line=2, end_line=2, column=9, end_column=16, occurrence=1)
    1609          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1610              line=2, end_line=2, column=9, end_column=16, occurrence=1)
    1611          self.assertOpcodeSourcePositionIs(compiled_code, 'STORE_NAME',
    1612              line=2, end_line=2, column=9, end_column=16, occurrence=2)
    1613  
    1614      def test_matchcase_or(self):
    1615          snippet = textwrap.dedent("""\
    1616              match x:
    1617                  case C(1) | C(2):
    1618                      pass
    1619              """)
    1620          compiled_code, _ = self.check_positions_against_ast(snippet)
    1621          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_CLASS',
    1622              line=2, end_line=2, column=9, end_column=13, occurrence=1)
    1623          self.assertOpcodeSourcePositionIs(compiled_code, 'MATCH_CLASS',
    1624              line=2, end_line=2, column=16, end_column=20, occurrence=2)
    1625  
    1626      def test_very_long_line_end_offset(self):
    1627          # Make sure we get the correct column offset for offsets
    1628          # too large to store in a byte.
    1629          long_string = "a" * 1000
    1630          snippet = f"g('{long_string}')"
    1631  
    1632          compiled_code, _ = self.check_positions_against_ast(snippet)
    1633          self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
    1634              line=1, end_line=1, column=0, end_column=1005)
    1635  
    1636      def test_complex_single_line_expression(self):
    1637          snippet = "a - b @ (c * x['key'] + 23)"
    1638  
    1639          compiled_code, _ = self.check_positions_against_ast(snippet)
    1640          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_SUBSCR',
    1641              line=1, end_line=1, column=13, end_column=21)
    1642          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1643              line=1, end_line=1, column=9, end_column=21, occurrence=1)
    1644          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1645              line=1, end_line=1, column=9, end_column=26, occurrence=2)
    1646          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1647              line=1, end_line=1, column=4, end_column=27, occurrence=3)
    1648          self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
    1649              line=1, end_line=1, column=0, end_column=27, occurrence=4)
    1650  
    1651      def test_multiline_assert_rewritten_as_method_call(self):
    1652          # GH-94694: Don't crash if pytest rewrites a multiline assert as a
    1653          # method call with the same location information:
    1654          tree = ast.parse("assert (\n42\n)")
    1655          old_node = tree.body[0]
    1656          new_node = ast.Expr(
    1657              ast.Call(
    1658                  ast.Attribute(
    1659                      ast.Name("spam", ast.Load()),
    1660                      "eggs",
    1661                      ast.Load(),
    1662                  ),
    1663                  [],
    1664                  [],
    1665              )
    1666          )
    1667          ast.copy_location(new_node, old_node)
    1668          ast.fix_missing_locations(new_node)
    1669          tree.body[0] = new_node
    1670          compile(tree, "<test>", "exec")
    1671  
    1672      def test_push_null_load_global_positions(self):
    1673          source_template = """
    1674          import abc, dis
    1675          import ast as art
    1676  
    1677          abc = None
    1678          dix = dis
    1679          ast = art
    1680  
    1681          def f():
    1682          {}
    1683          """
    1684          for body in [
    1685              "    abc.a()",
    1686              "    art.a()",
    1687              "    ast.a()",
    1688              "    dis.a()",
    1689              "    dix.a()",
    1690              "    abc[...]()",
    1691              "    art()()",
    1692              "   (ast or ...)()",
    1693              "   [dis]()",
    1694              "   (dix + ...)()",
    1695          ]:
    1696              with self.subTest(body):
    1697                  namespace = {}
    1698                  source = textwrap.dedent(source_template.format(body))
    1699                  with warnings.catch_warnings():
    1700                      warnings.simplefilter('ignore', SyntaxWarning)
    1701                      exec(source, namespace)
    1702                  code = namespace["f"].__code__
    1703                  self.assertOpcodeSourcePositionIs(
    1704                      code,
    1705                      "LOAD_GLOBAL",
    1706                      line=10,
    1707                      end_line=10,
    1708                      column=4,
    1709                      end_column=7,
    1710                  )
    1711  
    1712      def test_attribute_augassign(self):
    1713          source = "(\n lhs  \n   .    \n     rhs      \n       ) += 42"
    1714          code = compile(source, "<test>", "exec")
    1715          self.assertOpcodeSourcePositionIs(
    1716              code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
    1717          )
    1718          self.assertOpcodeSourcePositionIs(
    1719              code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
    1720          )
    1721  
    1722      def test_attribute_del(self):
    1723          source = "del (\n lhs  \n   .    \n     rhs      \n       )"
    1724          code = compile(source, "<test>", "exec")
    1725          self.assertOpcodeSourcePositionIs(
    1726              code, "DELETE_ATTR", line=4, end_line=4, column=5, end_column=8
    1727          )
    1728  
    1729      def test_attribute_load(self):
    1730          source = "(\n lhs  \n   .    \n     rhs      \n       )"
    1731          code = compile(source, "<test>", "exec")
    1732          self.assertOpcodeSourcePositionIs(
    1733              code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
    1734          )
    1735  
    1736      def test_attribute_store(self):
    1737          source = "(\n lhs  \n   .    \n     rhs      \n       ) = 42"
    1738          code = compile(source, "<test>", "exec")
    1739          self.assertOpcodeSourcePositionIs(
    1740              code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
    1741          )
    1742  
    1743      def test_method_call(self):
    1744          source = "(\n lhs  \n   .    \n     rhs      \n       )()"
    1745          code = compile(source, "<test>", "exec")
    1746          self.assertOpcodeSourcePositionIs(
    1747              code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
    1748          )
    1749          self.assertOpcodeSourcePositionIs(
    1750              code, "CALL", line=4, end_line=5, column=5, end_column=10
    1751          )
    1752  
    1753      def test_weird_attribute_position_regressions(self):
    1754          def f():
    1755              (bar.
    1756          baz)
    1757              (bar.
    1758          baz(
    1759          ))
    1760              files().setdefault(
    1761                  0
    1762              ).setdefault(
    1763                  0
    1764              )
    1765          for line, end_line, column, end_column in f.__code__.co_positions():
    1766              self.assertIsNotNone(line)
    1767              self.assertIsNotNone(end_line)
    1768              self.assertIsNotNone(column)
    1769              self.assertIsNotNone(end_column)
    1770              self.assertLessEqual((line, column), (end_line, end_column))
    1771  
    1772      @support.cpython_only
    1773      def test_column_offset_deduplication(self):
    1774          # GH-95150: Code with different column offsets shouldn't be merged!
    1775          for source in [
    1776              "lambda: a",
    1777              "(a for b in c)",
    1778          ]:
    1779              with self.subTest(source):
    1780                  code = compile(f"{source}, {source}", "<test>", "eval")
    1781                  self.assertEqual(len(code.co_consts), 2)
    1782                  self.assertIsInstance(code.co_consts[0], types.CodeType)
    1783                  self.assertIsInstance(code.co_consts[1], types.CodeType)
    1784                  self.assertNotEqual(code.co_consts[0], code.co_consts[1])
    1785                  self.assertNotEqual(
    1786                      list(code.co_consts[0].co_positions()),
    1787                      list(code.co_consts[1].co_positions()),
    1788                  )
    1789  
    1790      def test_load_super_attr(self):
    1791          source = "class C:\n  def __init__(self):\n    super().__init__()"
    1792          code = compile(source, "<test>", "exec").co_consts[0].co_consts[1]
    1793          self.assertOpcodeSourcePositionIs(
    1794              code, "LOAD_GLOBAL", line=3, end_line=3, column=4, end_column=9
    1795          )
    1796  
    1797  
    1798  class ESC[4;38;5;81mTestExpressionStackSize(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1799      # These tests check that the computed stack size for a code object
    1800      # stays within reasonable bounds (see issue #21523 for an example
    1801      # dysfunction).
    1802      N = 100
    1803  
    1804      def check_stack_size(self, code):
    1805          # To assert that the alleged stack size is not O(N), we
    1806          # check that it is smaller than log(N).
    1807          if isinstance(code, str):
    1808              code = compile(code, "<foo>", "single")
    1809          max_size = math.ceil(math.log(len(code.co_code)))
    1810          self.assertLessEqual(code.co_stacksize, max_size)
    1811  
    1812      def test_and(self):
    1813          self.check_stack_size("x and " * self.N + "x")
    1814  
    1815      def test_or(self):
    1816          self.check_stack_size("x or " * self.N + "x")
    1817  
    1818      def test_and_or(self):
    1819          self.check_stack_size("x and x or " * self.N + "x")
    1820  
    1821      def test_chained_comparison(self):
    1822          self.check_stack_size("x < " * self.N + "x")
    1823  
    1824      def test_if_else(self):
    1825          self.check_stack_size("x if x else " * self.N + "x")
    1826  
    1827      def test_binop(self):
    1828          self.check_stack_size("x + " * self.N + "x")
    1829  
    1830      def test_list(self):
    1831          self.check_stack_size("[" + "x, " * self.N + "x]")
    1832  
    1833      def test_tuple(self):
    1834          self.check_stack_size("(" + "x, " * self.N + "x)")
    1835  
    1836      def test_set(self):
    1837          self.check_stack_size("{" + "x, " * self.N + "x}")
    1838  
    1839      def test_dict(self):
    1840          self.check_stack_size("{" + "x:x, " * self.N + "x:x}")
    1841  
    1842      def test_func_args(self):
    1843          self.check_stack_size("f(" + "x, " * self.N + ")")
    1844  
    1845      def test_func_kwargs(self):
    1846          kwargs = (f'a{i}=x' for i in range(self.N))
    1847          self.check_stack_size("f(" +  ", ".join(kwargs) + ")")
    1848  
    1849      def test_meth_args(self):
    1850          self.check_stack_size("o.m(" + "x, " * self.N + ")")
    1851  
    1852      def test_meth_kwargs(self):
    1853          kwargs = (f'a{i}=x' for i in range(self.N))
    1854          self.check_stack_size("o.m(" +  ", ".join(kwargs) + ")")
    1855  
    1856      def test_func_and(self):
    1857          code = "def f(x):\n"
    1858          code += "   x and x\n" * self.N
    1859          self.check_stack_size(code)
    1860  
    1861      def test_stack_3050(self):
    1862          M = 3050
    1863          code = "x," * M + "=t"
    1864          # This raised on 3.10.0 to 3.10.5
    1865          compile(code, "<foo>", "single")
    1866  
    1867      def test_stack_3050_2(self):
    1868          M = 3050
    1869          args = ", ".join(f"arg{i}:type{i}" for i in range(M))
    1870          code = f"def f({args}):\n  pass"
    1871          # This raised on 3.10.0 to 3.10.5
    1872          compile(code, "<foo>", "single")
    1873  
    1874  
    1875  class ESC[4;38;5;81mTestStackSizeStability(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1876      # Check that repeating certain snippets doesn't increase the stack size
    1877      # beyond what a single snippet requires.
    1878  
    1879      def check_stack_size(self, snippet, async_=False):
    1880          def compile_snippet(i):
    1881              ns = {}
    1882              script = """def func():\n""" + i * snippet
    1883              if async_:
    1884                  script = "async " + script
    1885              code = compile(script, "<script>", "exec")
    1886              exec(code, ns, ns)
    1887              return ns['func'].__code__
    1888  
    1889          sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)]
    1890          if len(set(sizes)) != 1:
    1891              import dis, io
    1892              out = io.StringIO()
    1893              dis.dis(compile_snippet(1), file=out)
    1894              self.fail("stack sizes diverge with # of consecutive snippets: "
    1895                        "%s\n%s\n%s" % (sizes, snippet, out.getvalue()))
    1896  
    1897      def test_if(self):
    1898          snippet = """
    1899              if x:
    1900                  a
    1901              """
    1902          self.check_stack_size(snippet)
    1903  
    1904      def test_if_else(self):
    1905          snippet = """
    1906              if x:
    1907                  a
    1908              elif y:
    1909                  b
    1910              else:
    1911                  c
    1912              """
    1913          self.check_stack_size(snippet)
    1914  
    1915      def test_try_except_bare(self):
    1916          snippet = """
    1917              try:
    1918                  a
    1919              except:
    1920                  b
    1921              """
    1922          self.check_stack_size(snippet)
    1923  
    1924      def test_try_except_qualified(self):
    1925          snippet = """
    1926              try:
    1927                  a
    1928              except ImportError:
    1929                  b
    1930              except:
    1931                  c
    1932              else:
    1933                  d
    1934              """
    1935          self.check_stack_size(snippet)
    1936  
    1937      def test_try_except_as(self):
    1938          snippet = """
    1939              try:
    1940                  a
    1941              except ImportError as e:
    1942                  b
    1943              except:
    1944                  c
    1945              else:
    1946                  d
    1947              """
    1948          self.check_stack_size(snippet)
    1949  
    1950      def test_try_except_star_qualified(self):
    1951          snippet = """
    1952              try:
    1953                  a
    1954              except* ImportError:
    1955                  b
    1956              else:
    1957                  c
    1958              """
    1959          self.check_stack_size(snippet)
    1960  
    1961      def test_try_except_star_as(self):
    1962          snippet = """
    1963              try:
    1964                  a
    1965              except* ImportError as e:
    1966                  b
    1967              else:
    1968                  c
    1969              """
    1970          self.check_stack_size(snippet)
    1971  
    1972      def test_try_except_star_finally(self):
    1973          snippet = """
    1974                  try:
    1975                      a
    1976                  except* A:
    1977                      b
    1978                  finally:
    1979                      c
    1980              """
    1981          self.check_stack_size(snippet)
    1982  
    1983      def test_try_finally(self):
    1984          snippet = """
    1985                  try:
    1986                      a
    1987                  finally:
    1988                      b
    1989              """
    1990          self.check_stack_size(snippet)
    1991  
    1992      def test_with(self):
    1993          snippet = """
    1994              with x as y:
    1995                  a
    1996              """
    1997          self.check_stack_size(snippet)
    1998  
    1999      def test_while_else(self):
    2000          snippet = """
    2001              while x:
    2002                  a
    2003              else:
    2004                  b
    2005              """
    2006          self.check_stack_size(snippet)
    2007  
    2008      def test_for(self):
    2009          snippet = """
    2010              for x in y:
    2011                  a
    2012              """
    2013          self.check_stack_size(snippet)
    2014  
    2015      def test_for_else(self):
    2016          snippet = """
    2017              for x in y:
    2018                  a
    2019              else:
    2020                  b
    2021              """
    2022          self.check_stack_size(snippet)
    2023  
    2024      def test_for_break_continue(self):
    2025          snippet = """
    2026              for x in y:
    2027                  if z:
    2028                      break
    2029                  elif u:
    2030                      continue
    2031                  else:
    2032                      a
    2033              else:
    2034                  b
    2035              """
    2036          self.check_stack_size(snippet)
    2037  
    2038      def test_for_break_continue_inside_try_finally_block(self):
    2039          snippet = """
    2040              for x in y:
    2041                  try:
    2042                      if z:
    2043                          break
    2044                      elif u:
    2045                          continue
    2046                      else:
    2047                          a
    2048                  finally:
    2049                      f
    2050              else:
    2051                  b
    2052              """
    2053          self.check_stack_size(snippet)
    2054  
    2055      def test_for_break_continue_inside_finally_block(self):
    2056          snippet = """
    2057              for x in y:
    2058                  try:
    2059                      t
    2060                  finally:
    2061                      if z:
    2062                          break
    2063                      elif u:
    2064                          continue
    2065                      else:
    2066                          a
    2067              else:
    2068                  b
    2069              """
    2070          self.check_stack_size(snippet)
    2071  
    2072      def test_for_break_continue_inside_except_block(self):
    2073          snippet = """
    2074              for x in y:
    2075                  try:
    2076                      t
    2077                  except:
    2078                      if z:
    2079                          break
    2080                      elif u:
    2081                          continue
    2082                      else:
    2083                          a
    2084              else:
    2085                  b
    2086              """
    2087          self.check_stack_size(snippet)
    2088  
    2089      def test_for_break_continue_inside_with_block(self):
    2090          snippet = """
    2091              for x in y:
    2092                  with c:
    2093                      if z:
    2094                          break
    2095                      elif u:
    2096                          continue
    2097                      else:
    2098                          a
    2099              else:
    2100                  b
    2101              """
    2102          self.check_stack_size(snippet)
    2103  
    2104      def test_return_inside_try_finally_block(self):
    2105          snippet = """
    2106              try:
    2107                  if z:
    2108                      return
    2109                  else:
    2110                      a
    2111              finally:
    2112                  f
    2113              """
    2114          self.check_stack_size(snippet)
    2115  
    2116      def test_return_inside_finally_block(self):
    2117          snippet = """
    2118              try:
    2119                  t
    2120              finally:
    2121                  if z:
    2122                      return
    2123                  else:
    2124                      a
    2125              """
    2126          self.check_stack_size(snippet)
    2127  
    2128      def test_return_inside_except_block(self):
    2129          snippet = """
    2130              try:
    2131                  t
    2132              except:
    2133                  if z:
    2134                      return
    2135                  else:
    2136                      a
    2137              """
    2138          self.check_stack_size(snippet)
    2139  
    2140      def test_return_inside_with_block(self):
    2141          snippet = """
    2142              with c:
    2143                  if z:
    2144                      return
    2145                  else:
    2146                      a
    2147              """
    2148          self.check_stack_size(snippet)
    2149  
    2150      def test_async_with(self):
    2151          snippet = """
    2152              async with x as y:
    2153                  a
    2154              """
    2155          self.check_stack_size(snippet, async_=True)
    2156  
    2157      def test_async_for(self):
    2158          snippet = """
    2159              async for x in y:
    2160                  a
    2161              """
    2162          self.check_stack_size(snippet, async_=True)
    2163  
    2164      def test_async_for_else(self):
    2165          snippet = """
    2166              async for x in y:
    2167                  a
    2168              else:
    2169                  b
    2170              """
    2171          self.check_stack_size(snippet, async_=True)
    2172  
    2173      def test_for_break_continue_inside_async_with_block(self):
    2174          snippet = """
    2175              for x in y:
    2176                  async with c:
    2177                      if z:
    2178                          break
    2179                      elif u:
    2180                          continue
    2181                      else:
    2182                          a
    2183              else:
    2184                  b
    2185              """
    2186          self.check_stack_size(snippet, async_=True)
    2187  
    2188      def test_return_inside_async_with_block(self):
    2189          snippet = """
    2190              async with c:
    2191                  if z:
    2192                      return
    2193                  else:
    2194                      a
    2195              """
    2196          self.check_stack_size(snippet, async_=True)
    2197  
    2198  
    2199  if __name__ == "__main__":
    2200      unittest.main()