python (3.11.7)

(root)/
lib/
python3.11/
test/
test_peepholer.py
       1  import dis
       2  from itertools import combinations, product
       3  import textwrap
       4  import unittest
       5  
       6  from test import support
       7  from test.support.bytecode_helper import BytecodeTestCase
       8  
       9  
      10  def compile_pattern_with_fast_locals(pattern):
      11      source = textwrap.dedent(
      12          f"""
      13          def f(x):
      14              match x:
      15                  case {pattern}:
      16                      pass
      17          """
      18      )
      19      namespace = {}
      20      exec(source, namespace)
      21      return namespace["f"].__code__
      22  
      23  
      24  def count_instr_recursively(f, opname):
      25      count = 0
      26      for instr in dis.get_instructions(f):
      27          if instr.opname == opname:
      28              count += 1
      29      if hasattr(f, '__code__'):
      30          f = f.__code__
      31      for c in f.co_consts:
      32          if hasattr(c, 'co_code'):
      33              count += count_instr_recursively(c, opname)
      34      return count
      35  
      36  
      37  class ESC[4;38;5;81mTestTranforms(ESC[4;38;5;149mBytecodeTestCase):
      38  
      39      def check_jump_targets(self, code):
      40          instructions = list(dis.get_instructions(code))
      41          targets = {instr.offset: instr for instr in instructions}
      42          for instr in instructions:
      43              if 'JUMP_' not in instr.opname:
      44                  continue
      45              tgt = targets[instr.argval]
      46              # jump to unconditional jump
      47              if tgt.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD'):
      48                  self.fail(f'{instr.opname} at {instr.offset} '
      49                            f'jumps to {tgt.opname} at {tgt.offset}')
      50              # unconditional jump to RETURN_VALUE
      51              if (instr.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD') and
      52                  tgt.opname == 'RETURN_VALUE'):
      53                  self.fail(f'{instr.opname} at {instr.offset} '
      54                            f'jumps to {tgt.opname} at {tgt.offset}')
      55              # JUMP_IF_*_OR_POP jump to conditional jump
      56              if '_OR_POP' in instr.opname and 'JUMP_IF_' in tgt.opname:
      57                  self.fail(f'{instr.opname} at {instr.offset} '
      58                            f'jumps to {tgt.opname} at {tgt.offset}')
      59  
      60      def check_lnotab(self, code):
      61          "Check that the lnotab byte offsets are sensible."
      62          code = dis._get_code_object(code)
      63          lnotab = list(dis.findlinestarts(code))
      64          # Don't bother checking if the line info is sensible, because
      65          # most of the line info we can get at comes from lnotab.
      66          min_bytecode = min(t[0] for t in lnotab)
      67          max_bytecode = max(t[0] for t in lnotab)
      68          self.assertGreaterEqual(min_bytecode, 0)
      69          self.assertLess(max_bytecode, len(code.co_code))
      70          # This could conceivably test more (and probably should, as there
      71          # aren't very many tests of lnotab), if peepholer wasn't scheduled
      72          # to be replaced anyway.
      73  
      74      def test_unot(self):
      75          # UNARY_NOT POP_JUMP_IF_FALSE  -->  POP_JUMP_IF_TRUE'
      76          def unot(x):
      77              if not x == 2:
      78                  del x
      79          self.assertNotInBytecode(unot, 'UNARY_NOT')
      80          self.assertNotInBytecode(unot, 'POP_JUMP_FORWARD_IF_FALSE')
      81          self.assertNotInBytecode(unot, 'POP_JUMP_BACKWARD_IF_FALSE')
      82          self.assertInBytecode(unot, 'POP_JUMP_FORWARD_IF_TRUE')
      83          self.check_lnotab(unot)
      84  
      85      def test_elim_inversion_of_is_or_in(self):
      86          for line, cmp_op, invert in (
      87              ('not a is b', 'IS_OP', 1,),
      88              ('not a is not b', 'IS_OP', 0,),
      89              ('not a in b', 'CONTAINS_OP', 1,),
      90              ('not a not in b', 'CONTAINS_OP', 0,),
      91              ):
      92              with self.subTest(line=line):
      93                  code = compile(line, '', 'single')
      94                  self.assertInBytecode(code, cmp_op, invert)
      95                  self.check_lnotab(code)
      96  
      97      def test_global_as_constant(self):
      98          # LOAD_GLOBAL None/True/False  -->  LOAD_CONST None/True/False
      99          def f():
     100              x = None
     101              x = None
     102              return x
     103          def g():
     104              x = True
     105              return x
     106          def h():
     107              x = False
     108              return x
     109  
     110          for func, elem in ((f, None), (g, True), (h, False)):
     111              with self.subTest(func=func):
     112                  self.assertNotInBytecode(func, 'LOAD_GLOBAL')
     113                  self.assertInBytecode(func, 'LOAD_CONST', elem)
     114                  self.check_lnotab(func)
     115  
     116          def f():
     117              'Adding a docstring made this test fail in Py2.5.0'
     118              return None
     119  
     120          self.assertNotInBytecode(f, 'LOAD_GLOBAL')
     121          self.assertInBytecode(f, 'LOAD_CONST', None)
     122          self.check_lnotab(f)
     123  
     124      def test_while_one(self):
     125          # Skip over:  LOAD_CONST trueconst  POP_JUMP_IF_FALSE xx
     126          def f():
     127              while 1:
     128                  pass
     129              return list
     130          for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
     131              self.assertNotInBytecode(f, elem)
     132          for elem in ('JUMP_BACKWARD',):
     133              self.assertInBytecode(f, elem)
     134          self.check_lnotab(f)
     135  
     136      def test_pack_unpack(self):
     137          for line, elem in (
     138              ('a, = a,', 'LOAD_CONST',),
     139              ('a, b = a, b', 'SWAP',),
     140              ('a, b, c = a, b, c', 'SWAP',),
     141              ):
     142              with self.subTest(line=line):
     143                  code = compile(line,'','single')
     144                  self.assertInBytecode(code, elem)
     145                  self.assertNotInBytecode(code, 'BUILD_TUPLE')
     146                  self.assertNotInBytecode(code, 'UNPACK_SEQUENCE')
     147                  self.check_lnotab(code)
     148  
     149      def test_folding_of_tuples_of_constants(self):
     150          for line, elem in (
     151              ('a = 1,2,3', (1, 2, 3)),
     152              ('("a","b","c")', ('a', 'b', 'c')),
     153              ('a,b,c = 1,2,3', (1, 2, 3)),
     154              ('(None, 1, None)', (None, 1, None)),
     155              ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
     156              ):
     157              with self.subTest(line=line):
     158                  code = compile(line,'','single')
     159                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     160                  self.assertNotInBytecode(code, 'BUILD_TUPLE')
     161                  self.check_lnotab(code)
     162  
     163          # Long tuples should be folded too.
     164          code = compile(repr(tuple(range(10000))),'','single')
     165          self.assertNotInBytecode(code, 'BUILD_TUPLE')
     166          # One LOAD_CONST for the tuple, one for the None return value
     167          load_consts = [instr for instr in dis.get_instructions(code)
     168                                if instr.opname == 'LOAD_CONST']
     169          self.assertEqual(len(load_consts), 2)
     170          self.check_lnotab(code)
     171  
     172          # Bug 1053819:  Tuple of constants misidentified when presented with:
     173          # . . . opcode_with_arg 100   unary_opcode   BUILD_TUPLE 1  . . .
     174          # The following would segfault upon compilation
     175          def crater():
     176              (~[
     177                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     178                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     179                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     180                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     181                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     182                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     183                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     184                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     185                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     186                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
     187              ],)
     188          self.check_lnotab(crater)
     189  
     190      def test_folding_of_lists_of_constants(self):
     191          for line, elem in (
     192              # in/not in constants with BUILD_LIST should be folded to a tuple:
     193              ('a in [1,2,3]', (1, 2, 3)),
     194              ('a not in ["a","b","c"]', ('a', 'b', 'c')),
     195              ('a in [None, 1, None]', (None, 1, None)),
     196              ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
     197              ):
     198              with self.subTest(line=line):
     199                  code = compile(line, '', 'single')
     200                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     201                  self.assertNotInBytecode(code, 'BUILD_LIST')
     202                  self.check_lnotab(code)
     203  
     204      def test_folding_of_sets_of_constants(self):
     205          for line, elem in (
     206              # in/not in constants with BUILD_SET should be folded to a frozenset:
     207              ('a in {1,2,3}', frozenset({1, 2, 3})),
     208              ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
     209              ('a in {None, 1, None}', frozenset({1, None})),
     210              ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
     211              ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
     212              ):
     213              with self.subTest(line=line):
     214                  code = compile(line, '', 'single')
     215                  self.assertNotInBytecode(code, 'BUILD_SET')
     216                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     217                  self.check_lnotab(code)
     218  
     219          # Ensure that the resulting code actually works:
     220          def f(a):
     221              return a in {1, 2, 3}
     222  
     223          def g(a):
     224              return a not in {1, 2, 3}
     225  
     226          self.assertTrue(f(3))
     227          self.assertTrue(not f(4))
     228          self.check_lnotab(f)
     229  
     230          self.assertTrue(not g(3))
     231          self.assertTrue(g(4))
     232          self.check_lnotab(g)
     233  
     234  
     235      def test_folding_of_binops_on_constants(self):
     236          for line, elem in (
     237              ('a = 2+3+4', 9),                   # chained fold
     238              ('"@"*4', '@@@@'),                  # check string ops
     239              ('a="abc" + "def"', 'abcdef'),      # check string ops
     240              ('a = 3**4', 81),                   # binary power
     241              ('a = 3*4', 12),                    # binary multiply
     242              ('a = 13//4', 3),                   # binary floor divide
     243              ('a = 14%4', 2),                    # binary modulo
     244              ('a = 2+3', 5),                     # binary add
     245              ('a = 13-4', 9),                    # binary subtract
     246              ('a = (12,13)[1]', 13),             # binary subscr
     247              ('a = 13 << 2', 52),                # binary lshift
     248              ('a = 13 >> 2', 3),                 # binary rshift
     249              ('a = 13 & 7', 5),                  # binary and
     250              ('a = 13 ^ 7', 10),                 # binary xor
     251              ('a = 13 | 7', 15),                 # binary or
     252              ):
     253              with self.subTest(line=line):
     254                  code = compile(line, '', 'single')
     255                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     256                  for instr in dis.get_instructions(code):
     257                      self.assertFalse(instr.opname.startswith('BINARY_'))
     258                  self.check_lnotab(code)
     259  
     260          # Verify that unfoldables are skipped
     261          code = compile('a=2+"b"', '', 'single')
     262          self.assertInBytecode(code, 'LOAD_CONST', 2)
     263          self.assertInBytecode(code, 'LOAD_CONST', 'b')
     264          self.check_lnotab(code)
     265  
     266          # Verify that large sequences do not result from folding
     267          code = compile('a="x"*10000', '', 'single')
     268          self.assertInBytecode(code, 'LOAD_CONST', 10000)
     269          self.assertNotIn("x"*10000, code.co_consts)
     270          self.check_lnotab(code)
     271          code = compile('a=1<<1000', '', 'single')
     272          self.assertInBytecode(code, 'LOAD_CONST', 1000)
     273          self.assertNotIn(1<<1000, code.co_consts)
     274          self.check_lnotab(code)
     275          code = compile('a=2**1000', '', 'single')
     276          self.assertInBytecode(code, 'LOAD_CONST', 1000)
     277          self.assertNotIn(2**1000, code.co_consts)
     278          self.check_lnotab(code)
     279  
     280      def test_binary_subscr_on_unicode(self):
     281          # valid code get optimized
     282          code = compile('"foo"[0]', '', 'single')
     283          self.assertInBytecode(code, 'LOAD_CONST', 'f')
     284          self.assertNotInBytecode(code, 'BINARY_SUBSCR')
     285          self.check_lnotab(code)
     286          code = compile('"\u0061\uffff"[1]', '', 'single')
     287          self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
     288          self.assertNotInBytecode(code,'BINARY_SUBSCR')
     289          self.check_lnotab(code)
     290  
     291          # With PEP 393, non-BMP char get optimized
     292          code = compile('"\U00012345"[0]', '', 'single')
     293          self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
     294          self.assertNotInBytecode(code, 'BINARY_SUBSCR')
     295          self.check_lnotab(code)
     296  
     297          # invalid code doesn't get optimized
     298          # out of range
     299          code = compile('"fuu"[10]', '', 'single')
     300          self.assertInBytecode(code, 'BINARY_SUBSCR')
     301          self.check_lnotab(code)
     302  
     303      def test_folding_of_unaryops_on_constants(self):
     304          for line, elem in (
     305              ('-0.5', -0.5),                     # unary negative
     306              ('-0.0', -0.0),                     # -0.0
     307              ('-(1.0-1.0)', -0.0),               # -0.0 after folding
     308              ('-0', 0),                          # -0
     309              ('~-2', 1),                         # unary invert
     310              ('+1', 1),                          # unary positive
     311          ):
     312              with self.subTest(line=line):
     313                  code = compile(line, '', 'single')
     314                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     315                  for instr in dis.get_instructions(code):
     316                      self.assertFalse(instr.opname.startswith('UNARY_'))
     317                  self.check_lnotab(code)
     318  
     319          # Check that -0.0 works after marshaling
     320          def negzero():
     321              return -(1.0-1.0)
     322  
     323          for instr in dis.get_instructions(negzero):
     324              self.assertFalse(instr.opname.startswith('UNARY_'))
     325          self.check_lnotab(negzero)
     326  
     327          # Verify that unfoldables are skipped
     328          for line, elem, opname in (
     329              ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
     330              ('~"abc"', 'abc', 'UNARY_INVERT'),
     331          ):
     332              with self.subTest(line=line):
     333                  code = compile(line, '', 'single')
     334                  self.assertInBytecode(code, 'LOAD_CONST', elem)
     335                  self.assertInBytecode(code, opname)
     336                  self.check_lnotab(code)
     337  
     338      def test_elim_extra_return(self):
     339          # RETURN LOAD_CONST None RETURN  -->  RETURN
     340          def f(x):
     341              return x
     342          self.assertNotInBytecode(f, 'LOAD_CONST', None)
     343          returns = [instr for instr in dis.get_instructions(f)
     344                            if instr.opname == 'RETURN_VALUE']
     345          self.assertEqual(len(returns), 1)
     346          self.check_lnotab(f)
     347  
     348      @unittest.skip("Following gh-92228 the return has two predecessors "
     349                     "and that prevents jump elimination.")
     350      def test_elim_jump_to_return(self):
     351          # JUMP_FORWARD to RETURN -->  RETURN
     352          def f(cond, true_value, false_value):
     353              # Intentionally use two-line expression to test issue37213.
     354              return (true_value if cond
     355                      else false_value)
     356          self.check_jump_targets(f)
     357          self.assertNotInBytecode(f, 'JUMP_FORWARD')
     358          self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
     359          returns = [instr for instr in dis.get_instructions(f)
     360                            if instr.opname == 'RETURN_VALUE']
     361          self.assertEqual(len(returns), 2)
     362          self.check_lnotab(f)
     363  
     364      def test_elim_jump_to_uncond_jump(self):
     365          # POP_JUMP_IF_FALSE to JUMP_FORWARD --> POP_JUMP_IF_FALSE to non-jump
     366          def f():
     367              if a:
     368                  # Intentionally use two-line expression to test issue37213.
     369                  if (c
     370                      or d):
     371                      foo()
     372              else:
     373                  baz()
     374          self.check_jump_targets(f)
     375          self.check_lnotab(f)
     376  
     377      def test_elim_jump_to_uncond_jump2(self):
     378          # POP_JUMP_IF_FALSE to JUMP_ABSOLUTE --> POP_JUMP_IF_FALSE to non-jump
     379          def f():
     380              while a:
     381                  # Intentionally use two-line expression to test issue37213.
     382                  if (c
     383                      or d):
     384                      a = foo()
     385          self.check_jump_targets(f)
     386          self.check_lnotab(f)
     387  
     388      def test_elim_jump_to_uncond_jump3(self):
     389          # Intentionally use two-line expressions to test issue37213.
     390          # JUMP_IF_FALSE_OR_POP to JUMP_IF_FALSE_OR_POP --> JUMP_IF_FALSE_OR_POP to non-jump
     391          def f(a, b, c):
     392              return ((a and b)
     393                      and c)
     394          self.check_jump_targets(f)
     395          self.check_lnotab(f)
     396          self.assertEqual(count_instr_recursively(f, 'JUMP_IF_FALSE_OR_POP'), 2)
     397          # JUMP_IF_TRUE_OR_POP to JUMP_IF_TRUE_OR_POP --> JUMP_IF_TRUE_OR_POP to non-jump
     398          def f(a, b, c):
     399              return ((a or b)
     400                      or c)
     401          self.check_jump_targets(f)
     402          self.check_lnotab(f)
     403          self.assertEqual(count_instr_recursively(f, 'JUMP_IF_TRUE_OR_POP'), 2)
     404          # JUMP_IF_FALSE_OR_POP to JUMP_IF_TRUE_OR_POP --> POP_JUMP_IF_FALSE to non-jump
     405          def f(a, b, c):
     406              return ((a and b)
     407                      or c)
     408          self.check_jump_targets(f)
     409          self.check_lnotab(f)
     410          self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
     411          self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
     412          self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_FALSE')
     413          # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump
     414          def f(a, b, c):
     415              return ((a or b)
     416                      and c)
     417          self.check_jump_targets(f)
     418          self.check_lnotab(f)
     419          self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
     420          self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
     421          self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_TRUE')
     422  
     423      def test_elim_jump_after_return1(self):
     424          # Eliminate dead code: jumps immediately after returns can't be reached
     425          def f(cond1, cond2):
     426              if cond1: return 1
     427              if cond2: return 2
     428              while 1:
     429                  return 3
     430              while 1:
     431                  if cond1: return 4
     432                  return 5
     433              return 6
     434          self.assertNotInBytecode(f, 'JUMP_FORWARD')
     435          self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
     436          returns = [instr for instr in dis.get_instructions(f)
     437                            if instr.opname == 'RETURN_VALUE']
     438          self.assertLessEqual(len(returns), 6)
     439          self.check_lnotab(f)
     440  
     441      def test_make_function_doesnt_bail(self):
     442          def f():
     443              def g()->1+1:
     444                  pass
     445              return g
     446          self.assertNotInBytecode(f, 'BINARY_OP')
     447          self.check_lnotab(f)
     448  
     449      def test_constant_folding(self):
     450          # Issue #11244: aggressive constant folding.
     451          exprs = [
     452              '3 * -5',
     453              '-3 * 5',
     454              '2 * (3 * 4)',
     455              '(2 * 3) * 4',
     456              '(-1, 2, 3)',
     457              '(1, -2, 3)',
     458              '(1, 2, -3)',
     459              '(1, 2, -3) * 6',
     460              'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
     461          ]
     462          for e in exprs:
     463              with self.subTest(e=e):
     464                  code = compile(e, '', 'single')
     465                  for instr in dis.get_instructions(code):
     466                      self.assertFalse(instr.opname.startswith('UNARY_'))
     467                      self.assertFalse(instr.opname.startswith('BINARY_'))
     468                      self.assertFalse(instr.opname.startswith('BUILD_'))
     469                  self.check_lnotab(code)
     470  
     471      def test_in_literal_list(self):
     472          def containtest():
     473              return x in [a, b]
     474          self.assertEqual(count_instr_recursively(containtest, 'BUILD_LIST'), 0)
     475          self.check_lnotab(containtest)
     476  
     477      def test_iterate_literal_list(self):
     478          def forloop():
     479              for x in [a, b]:
     480                  pass
     481          self.assertEqual(count_instr_recursively(forloop, 'BUILD_LIST'), 0)
     482          self.check_lnotab(forloop)
     483  
     484      def test_condition_with_binop_with_bools(self):
     485          def f():
     486              if True or False:
     487                  return 1
     488              return 0
     489          self.assertEqual(f(), 1)
     490          self.check_lnotab(f)
     491  
     492      def test_if_with_if_expression(self):
     493          # Check bpo-37289
     494          def f(x):
     495              if (True if x else False):
     496                  return True
     497              return False
     498          self.assertTrue(f(True))
     499          self.check_lnotab(f)
     500  
     501      def test_trailing_nops(self):
     502          # Check the lnotab of a function that even after trivial
     503          # optimization has trailing nops, which the lnotab adjustment has to
     504          # handle properly (bpo-38115).
     505          def f(x):
     506              while 1:
     507                  return 3
     508              while 1:
     509                  return 5
     510              return 6
     511          self.check_lnotab(f)
     512  
     513      def test_assignment_idiom_in_comprehensions(self):
     514          def listcomp():
     515              return [y for x in a for y in [f(x)]]
     516          self.assertEqual(count_instr_recursively(listcomp, 'FOR_ITER'), 1)
     517          def setcomp():
     518              return {y for x in a for y in [f(x)]}
     519          self.assertEqual(count_instr_recursively(setcomp, 'FOR_ITER'), 1)
     520          def dictcomp():
     521              return {y: y for x in a for y in [f(x)]}
     522          self.assertEqual(count_instr_recursively(dictcomp, 'FOR_ITER'), 1)
     523          def genexpr():
     524              return (y for x in a for y in [f(x)])
     525          self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1)
     526  
     527      @support.requires_resource('cpu')
     528      def test_format_combinations(self):
     529          flags = '-+ #0'
     530          testcases = [
     531              *product(('', '1234', 'абвг'), 'sra'),
     532              *product((1234, -1234), 'duioxX'),
     533              *product((1234.5678901, -1234.5678901), 'duifegFEG'),
     534              *product((float('inf'), -float('inf')), 'fegFEG'),
     535          ]
     536          width_precs = [
     537              *product(('', '1', '30'), ('', '.', '.0', '.2')),
     538              ('', '.40'),
     539              ('30', '.40'),
     540          ]
     541          for value, suffix in testcases:
     542              for width, prec in width_precs:
     543                  for r in range(len(flags) + 1):
     544                      for spec in combinations(flags, r):
     545                          fmt = '%' + ''.join(spec) + width + prec + suffix
     546                          with self.subTest(fmt=fmt, value=value):
     547                              s1 = fmt % value
     548                              s2 = eval(f'{fmt!r} % (x,)', {'x': value})
     549                              self.assertEqual(s2, s1, f'{fmt = }')
     550  
     551      def test_format_misc(self):
     552          def format(fmt, *values):
     553              vars = [f'x{i+1}' for i in range(len(values))]
     554              if len(vars) == 1:
     555                  args = '(' + vars[0] + ',)'
     556              else:
     557                  args = '(' + ', '.join(vars) + ')'
     558              return eval(f'{fmt!r} % {args}', dict(zip(vars, values)))
     559  
     560          self.assertEqual(format('string'), 'string')
     561          self.assertEqual(format('x = %s!', 1234), 'x = 1234!')
     562          self.assertEqual(format('x = %d!', 1234), 'x = 1234!')
     563          self.assertEqual(format('x = %x!', 1234), 'x = 4d2!')
     564          self.assertEqual(format('x = %f!', 1234), 'x = 1234.000000!')
     565          self.assertEqual(format('x = %s!', 1234.5678901), 'x = 1234.5678901!')
     566          self.assertEqual(format('x = %f!', 1234.5678901), 'x = 1234.567890!')
     567          self.assertEqual(format('x = %d!', 1234.5678901), 'x = 1234!')
     568          self.assertEqual(format('x = %s%% %%%%', 1234), 'x = 1234% %%')
     569          self.assertEqual(format('x = %s!', '%% %s'), 'x = %% %s!')
     570          self.assertEqual(format('x = %s, y = %d', 12, 34), 'x = 12, y = 34')
     571  
     572      def test_format_errors(self):
     573          with self.assertRaisesRegex(TypeError,
     574                      'not enough arguments for format string'):
     575              eval("'%s' % ()")
     576          with self.assertRaisesRegex(TypeError,
     577                      'not all arguments converted during string formatting'):
     578              eval("'%s' % (x, y)", {'x': 1, 'y': 2})
     579          with self.assertRaisesRegex(ValueError, 'incomplete format'):
     580              eval("'%s%' % (x,)", {'x': 1234})
     581          with self.assertRaisesRegex(ValueError, 'incomplete format'):
     582              eval("'%s%%%' % (x,)", {'x': 1234})
     583          with self.assertRaisesRegex(TypeError,
     584                      'not enough arguments for format string'):
     585              eval("'%s%z' % (x,)", {'x': 1234})
     586          with self.assertRaisesRegex(ValueError, 'unsupported format character'):
     587              eval("'%s%z' % (x, 5)", {'x': 1234})
     588          with self.assertRaisesRegex(TypeError, 'a real number is required, not str'):
     589              eval("'%d' % (x,)", {'x': '1234'})
     590          with self.assertRaisesRegex(TypeError, 'an integer is required, not float'):
     591              eval("'%x' % (x,)", {'x': 1234.56})
     592          with self.assertRaisesRegex(TypeError, 'an integer is required, not str'):
     593              eval("'%x' % (x,)", {'x': '1234'})
     594          with self.assertRaisesRegex(TypeError, 'must be real number, not str'):
     595              eval("'%f' % (x,)", {'x': '1234'})
     596          with self.assertRaisesRegex(TypeError,
     597                      'not enough arguments for format string'):
     598              eval("'%s, %s' % (x, *y)", {'x': 1, 'y': []})
     599          with self.assertRaisesRegex(TypeError,
     600                      'not all arguments converted during string formatting'):
     601              eval("'%s, %s' % (x, *y)", {'x': 1, 'y': [2, 3]})
     602  
     603      def test_static_swaps_unpack_two(self):
     604          def f(a, b):
     605              a, b = a, b
     606              b, a = a, b
     607          self.assertNotInBytecode(f, "SWAP")
     608  
     609      def test_static_swaps_unpack_three(self):
     610          def f(a, b, c):
     611              a, b, c = a, b, c
     612              a, c, b = a, b, c
     613              b, a, c = a, b, c
     614              b, c, a = a, b, c
     615              c, a, b = a, b, c
     616              c, b, a = a, b, c
     617          self.assertNotInBytecode(f, "SWAP")
     618  
     619      def test_static_swaps_match_mapping(self):
     620          for a, b, c in product("_a", "_b", "_c"):
     621              pattern = f"{{'a': {a}, 'b': {b}, 'c': {c}}}"
     622              with self.subTest(pattern):
     623                  code = compile_pattern_with_fast_locals(pattern)
     624                  self.assertNotInBytecode(code, "SWAP")
     625  
     626      def test_static_swaps_match_class(self):
     627          forms = [
     628              "C({}, {}, {})",
     629              "C({}, {}, c={})",
     630              "C({}, b={}, c={})",
     631              "C(a={}, b={}, c={})"
     632          ]
     633          for a, b, c in product("_a", "_b", "_c"):
     634              for form in forms:
     635                  pattern = form.format(a, b, c)
     636                  with self.subTest(pattern):
     637                      code = compile_pattern_with_fast_locals(pattern)
     638                      self.assertNotInBytecode(code, "SWAP")
     639  
     640      def test_static_swaps_match_sequence(self):
     641          swaps = {"*_, b, c", "a, *_, c", "a, b, *_"}
     642          forms = ["{}, {}, {}", "{}, {}, *{}", "{}, *{}, {}", "*{}, {}, {}"]
     643          for a, b, c in product("_a", "_b", "_c"):
     644              for form in forms:
     645                  pattern = form.format(a, b, c)
     646                  with self.subTest(pattern):
     647                      code = compile_pattern_with_fast_locals(pattern)
     648                      if pattern in swaps:
     649                          # If this fails... great! Remove this pattern from swaps
     650                          # to prevent regressing on any improvement:
     651                          self.assertInBytecode(code, "SWAP")
     652                      else:
     653                          self.assertNotInBytecode(code, "SWAP")
     654  
     655  
     656  class ESC[4;38;5;81mTestBuglets(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     657  
     658      def test_bug_11510(self):
     659          # folded constant set optimization was commingled with the tuple
     660          # unpacking optimization which would fail if the set had duplicate
     661          # elements so that the set length was unexpected
     662          def f():
     663              x, y = {1, 1}
     664              return x, y
     665          with self.assertRaises(ValueError):
     666              f()
     667  
     668      def test_bpo_42057(self):
     669          for i in range(10):
     670              try:
     671                  raise Exception
     672              except Exception or Exception:
     673                  pass
     674  
     675      def test_bpo_45773_pop_jump_if_true(self):
     676          compile("while True or spam: pass", "<test>", "exec")
     677  
     678      def test_bpo_45773_pop_jump_if_false(self):
     679          compile("while True or not spam: pass", "<test>", "exec")
     680  
     681  
     682  if __name__ == "__main__":
     683      unittest.main()