python (3.11.7)

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