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