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()