1 # Minimal tests for dis module
2
3 import contextlib
4 import dis
5 import io
6 import re
7 import sys
8 import types
9 import unittest
10 from test.support import captured_stdout, requires_debug_ranges, cpython_only
11 from test.support.bytecode_helper import BytecodeTestCase
12
13 import opcode
14
15
16 def get_tb():
17 def _error():
18 try:
19 1 / 0
20 except Exception as e:
21 tb = e.__traceback__
22 return tb
23
24 tb = _error()
25 while tb.tb_next:
26 tb = tb.tb_next
27 return tb
28
29 TRACEBACK_CODE = get_tb().tb_frame.f_code
30
31 class ESC[4;38;5;81m_C:
32 def __init__(self, x):
33 self.x = x == 1
34
35 @staticmethod
36 def sm(x):
37 x = x == 1
38
39 @classmethod
40 def cm(cls, x):
41 cls.x = x == 1
42
43 dis_c_instance_method = """\
44 %3d RESUME 0
45
46 %3d LOAD_FAST 1 (x)
47 LOAD_CONST 1 (1)
48 COMPARE_OP 2 (==)
49 LOAD_FAST 0 (self)
50 STORE_ATTR 0 (x)
51 LOAD_CONST 0 (None)
52 RETURN_VALUE
53 """ % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,)
54
55 dis_c_instance_method_bytes = """\
56 RESUME 0
57 LOAD_FAST 1
58 LOAD_CONST 1
59 COMPARE_OP 2 (==)
60 LOAD_FAST 0
61 STORE_ATTR 0
62 LOAD_CONST 0
63 RETURN_VALUE
64 """
65
66 dis_c_class_method = """\
67 %3d RESUME 0
68
69 %3d LOAD_FAST 1 (x)
70 LOAD_CONST 1 (1)
71 COMPARE_OP 2 (==)
72 LOAD_FAST 0 (cls)
73 STORE_ATTR 0 (x)
74 LOAD_CONST 0 (None)
75 RETURN_VALUE
76 """ % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,)
77
78 dis_c_static_method = """\
79 %3d RESUME 0
80
81 %3d LOAD_FAST 0 (x)
82 LOAD_CONST 1 (1)
83 COMPARE_OP 2 (==)
84 STORE_FAST 0 (x)
85 LOAD_CONST 0 (None)
86 RETURN_VALUE
87 """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,)
88
89 # Class disassembling info has an extra newline at end.
90 dis_c = """\
91 Disassembly of %s:
92 %s
93 Disassembly of %s:
94 %s
95 Disassembly of %s:
96 %s
97 """ % (_C.__init__.__name__, dis_c_instance_method,
98 _C.cm.__name__, dis_c_class_method,
99 _C.sm.__name__, dis_c_static_method)
100
101 def _f(a):
102 print(a)
103 return 1
104
105 dis_f = """\
106 %3d RESUME 0
107
108 %3d LOAD_GLOBAL 1 (NULL + print)
109 LOAD_FAST 0 (a)
110 PRECALL 1
111 CALL 1
112 POP_TOP
113
114 %3d LOAD_CONST 1 (1)
115 RETURN_VALUE
116 """ % (_f.__code__.co_firstlineno,
117 _f.__code__.co_firstlineno + 1,
118 _f.__code__.co_firstlineno + 2)
119
120
121 dis_f_co_code = """\
122 RESUME 0
123 LOAD_GLOBAL 1
124 LOAD_FAST 0
125 PRECALL 1
126 CALL 1
127 POP_TOP
128 LOAD_CONST 1
129 RETURN_VALUE
130 """
131
132
133 def bug708901():
134 for res in range(1,
135 10):
136 pass
137
138 dis_bug708901 = """\
139 %3d RESUME 0
140
141 %3d LOAD_GLOBAL 1 (NULL + range)
142 LOAD_CONST 1 (1)
143
144 %3d LOAD_CONST 2 (10)
145
146 %3d PRECALL 2
147 CALL 2
148 GET_ITER
149 >> FOR_ITER 2 (to 40)
150 STORE_FAST 0 (res)
151
152 %3d JUMP_BACKWARD 3 (to 34)
153
154 %3d >> LOAD_CONST 0 (None)
155 RETURN_VALUE
156 """ % (bug708901.__code__.co_firstlineno,
157 bug708901.__code__.co_firstlineno + 1,
158 bug708901.__code__.co_firstlineno + 2,
159 bug708901.__code__.co_firstlineno + 1,
160 bug708901.__code__.co_firstlineno + 3,
161 bug708901.__code__.co_firstlineno + 1)
162
163
164 def bug1333982(x=[]):
165 assert 0, ([s for s in x] +
166 1)
167 pass
168
169 dis_bug1333982 = """\
170 %3d RESUME 0
171
172 %3d LOAD_ASSERTION_ERROR
173 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
174 MAKE_FUNCTION 0
175 LOAD_FAST 0 (x)
176 GET_ITER
177 PRECALL 0
178 CALL 0
179
180 %3d LOAD_CONST 3 (1)
181
182 %3d BINARY_OP 0 (+)
183 PRECALL 0
184 CALL 0
185 RAISE_VARARGS 1
186 """ % (bug1333982.__code__.co_firstlineno,
187 bug1333982.__code__.co_firstlineno + 1,
188 __file__,
189 bug1333982.__code__.co_firstlineno + 1,
190 bug1333982.__code__.co_firstlineno + 2,
191 bug1333982.__code__.co_firstlineno + 1)
192
193
194 def bug42562():
195 pass
196
197
198 # Set line number for 'pass' to None
199 bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8')
200
201
202 dis_bug42562 = """\
203 RESUME 0
204 LOAD_CONST 0 (None)
205 RETURN_VALUE
206 """
207
208 # Extended arg followed by NOP
209 code_bug_45757 = bytes([
210 0x90, 0x01, # EXTENDED_ARG 0x01
211 0x09, 0xFF, # NOP 0xFF
212 0x90, 0x01, # EXTENDED_ARG 0x01
213 0x64, 0x29, # LOAD_CONST 0x29
214 0x53, 0x00, # RETURN_VALUE 0x00
215 ])
216
217 dis_bug_45757 = """\
218 EXTENDED_ARG 1
219 NOP
220 EXTENDED_ARG 1
221 LOAD_CONST 297
222 RETURN_VALUE
223 """
224
225 # [255, 255, 255, 252] is -4 in a 4 byte signed integer
226 bug46724 = bytes([
227 opcode.EXTENDED_ARG, 255,
228 opcode.EXTENDED_ARG, 255,
229 opcode.EXTENDED_ARG, 255,
230 opcode.opmap['JUMP_FORWARD'], 252,
231 ])
232
233
234 dis_bug46724 = """\
235 >> EXTENDED_ARG 255
236 EXTENDED_ARG 65535
237 EXTENDED_ARG 16777215
238 JUMP_FORWARD -4 (to 0)
239 """
240
241 _BIG_LINENO_FORMAT = """\
242 1 RESUME 0
243
244 %3d LOAD_GLOBAL 0 (spam)
245 POP_TOP
246 LOAD_CONST 0 (None)
247 RETURN_VALUE
248 """
249
250 _BIG_LINENO_FORMAT2 = """\
251 1 RESUME 0
252
253 %4d LOAD_GLOBAL 0 (spam)
254 POP_TOP
255 LOAD_CONST 0 (None)
256 RETURN_VALUE
257 """
258
259 dis_module_expected_results = """\
260 Disassembly of f:
261 4 RESUME 0
262 LOAD_CONST 0 (None)
263 RETURN_VALUE
264
265 Disassembly of g:
266 5 RESUME 0
267 LOAD_CONST 0 (None)
268 RETURN_VALUE
269
270 """
271
272 expr_str = "x + 1"
273
274 dis_expr_str = """\
275 0 RESUME 0
276
277 1 LOAD_NAME 0 (x)
278 LOAD_CONST 0 (1)
279 BINARY_OP 0 (+)
280 RETURN_VALUE
281 """
282
283 simple_stmt_str = "x = x + 1"
284
285 dis_simple_stmt_str = """\
286 0 RESUME 0
287
288 1 LOAD_NAME 0 (x)
289 LOAD_CONST 0 (1)
290 BINARY_OP 0 (+)
291 STORE_NAME 0 (x)
292 LOAD_CONST 1 (None)
293 RETURN_VALUE
294 """
295
296 annot_stmt_str = """\
297
298 x: int = 1
299 y: fun(1)
300 lst[fun(0)]: int = 1
301 """
302 # leading newline is for a reason (tests lineno)
303
304 dis_annot_stmt_str = """\
305 0 RESUME 0
306
307 2 SETUP_ANNOTATIONS
308 LOAD_CONST 0 (1)
309 STORE_NAME 0 (x)
310 LOAD_NAME 1 (int)
311 LOAD_NAME 2 (__annotations__)
312 LOAD_CONST 1 ('x')
313 STORE_SUBSCR
314
315 3 PUSH_NULL
316 LOAD_NAME 3 (fun)
317 LOAD_CONST 0 (1)
318 PRECALL 1
319 CALL 1
320 LOAD_NAME 2 (__annotations__)
321 LOAD_CONST 2 ('y')
322 STORE_SUBSCR
323
324 4 LOAD_CONST 0 (1)
325 LOAD_NAME 4 (lst)
326 PUSH_NULL
327 LOAD_NAME 3 (fun)
328 LOAD_CONST 3 (0)
329 PRECALL 1
330 CALL 1
331 STORE_SUBSCR
332 LOAD_NAME 1 (int)
333 POP_TOP
334 LOAD_CONST 4 (None)
335 RETURN_VALUE
336 """
337
338 compound_stmt_str = """\
339 x = 0
340 while 1:
341 x += 1"""
342 # Trailing newline has been deliberately omitted
343
344 dis_compound_stmt_str = """\
345 0 RESUME 0
346
347 1 LOAD_CONST 0 (0)
348 STORE_NAME 0 (x)
349
350 2 NOP
351
352 3 >> LOAD_NAME 0 (x)
353 LOAD_CONST 1 (1)
354 BINARY_OP 13 (+=)
355 STORE_NAME 0 (x)
356
357 2 JUMP_BACKWARD 6 (to 8)
358 """
359
360 dis_traceback = """\
361 %3d RESUME 0
362
363 %3d NOP
364
365 %3d LOAD_CONST 1 (1)
366 LOAD_CONST 2 (0)
367 --> BINARY_OP 11 (/)
368 POP_TOP
369 JUMP_FORWARD 30 (to 76)
370 >> PUSH_EXC_INFO
371
372 %3d LOAD_GLOBAL 0 (Exception)
373 CHECK_EXC_MATCH
374 POP_JUMP_FORWARD_IF_FALSE 17 (to 68)
375 STORE_FAST 0 (e)
376
377 %3d LOAD_FAST 0 (e)
378 LOAD_ATTR 1 (__traceback__)
379 STORE_FAST 1 (tb)
380 POP_EXCEPT
381 LOAD_CONST 0 (None)
382 STORE_FAST 0 (e)
383 DELETE_FAST 0 (e)
384 JUMP_FORWARD 8 (to 76)
385 >> LOAD_CONST 0 (None)
386 STORE_FAST 0 (e)
387 DELETE_FAST 0 (e)
388 RERAISE 1
389
390 %3d >> RERAISE 0
391 >> COPY 3
392 POP_EXCEPT
393 RERAISE 1
394
395 %3d >> LOAD_FAST 1 (tb)
396 RETURN_VALUE
397 ExceptionTable:
398 """ % (TRACEBACK_CODE.co_firstlineno,
399 TRACEBACK_CODE.co_firstlineno + 1,
400 TRACEBACK_CODE.co_firstlineno + 2,
401 TRACEBACK_CODE.co_firstlineno + 3,
402 TRACEBACK_CODE.co_firstlineno + 4,
403 TRACEBACK_CODE.co_firstlineno + 3,
404 TRACEBACK_CODE.co_firstlineno + 5)
405
406 def _fstring(a, b, c, d):
407 return f'{a} {b:4} {c!r} {d!r:4}'
408
409 dis_fstring = """\
410 %3d RESUME 0
411
412 %3d LOAD_FAST 0 (a)
413 FORMAT_VALUE 0
414 LOAD_CONST 1 (' ')
415 LOAD_FAST 1 (b)
416 LOAD_CONST 2 ('4')
417 FORMAT_VALUE 4 (with format)
418 LOAD_CONST 1 (' ')
419 LOAD_FAST 2 (c)
420 FORMAT_VALUE 2 (repr)
421 LOAD_CONST 1 (' ')
422 LOAD_FAST 3 (d)
423 LOAD_CONST 2 ('4')
424 FORMAT_VALUE 6 (repr, with format)
425 BUILD_STRING 7
426 RETURN_VALUE
427 """ % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1)
428
429 def _tryfinally(a, b):
430 try:
431 return a
432 finally:
433 b()
434
435 def _tryfinallyconst(b):
436 try:
437 return 1
438 finally:
439 b()
440
441 dis_tryfinally = """\
442 %3d RESUME 0
443
444 %3d NOP
445
446 %3d LOAD_FAST 0 (a)
447
448 %3d PUSH_NULL
449 LOAD_FAST 1 (b)
450 PRECALL 0
451 CALL 0
452 POP_TOP
453 RETURN_VALUE
454 >> PUSH_EXC_INFO
455 PUSH_NULL
456 LOAD_FAST 1 (b)
457 PRECALL 0
458 CALL 0
459 POP_TOP
460 RERAISE 0
461 >> COPY 3
462 POP_EXCEPT
463 RERAISE 1
464 ExceptionTable:
465 """ % (_tryfinally.__code__.co_firstlineno,
466 _tryfinally.__code__.co_firstlineno + 1,
467 _tryfinally.__code__.co_firstlineno + 2,
468 _tryfinally.__code__.co_firstlineno + 4,
469 )
470
471 dis_tryfinallyconst = """\
472 %3d RESUME 0
473
474 %3d NOP
475
476 %3d NOP
477
478 %3d PUSH_NULL
479 LOAD_FAST 0 (b)
480 PRECALL 0
481 CALL 0
482 POP_TOP
483 LOAD_CONST 1 (1)
484 RETURN_VALUE
485 PUSH_EXC_INFO
486 PUSH_NULL
487 LOAD_FAST 0 (b)
488 PRECALL 0
489 CALL 0
490 POP_TOP
491 RERAISE 0
492 >> COPY 3
493 POP_EXCEPT
494 RERAISE 1
495 ExceptionTable:
496 """ % (_tryfinallyconst.__code__.co_firstlineno,
497 _tryfinallyconst.__code__.co_firstlineno + 1,
498 _tryfinallyconst.__code__.co_firstlineno + 2,
499 _tryfinallyconst.__code__.co_firstlineno + 4,
500 )
501
502 def _g(x):
503 yield x
504
505 async def _ag(x):
506 yield x
507
508 async def _co(x):
509 async for item in _ag(x):
510 pass
511
512 def _h(y):
513 def foo(x):
514 '''funcdoc'''
515 return [x + z for z in y]
516 return foo
517
518 dis_nested_0 = """\
519 MAKE_CELL 0 (y)
520
521 %3d RESUME 0
522
523 %3d LOAD_CLOSURE 0 (y)
524 BUILD_TUPLE 1
525 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
526 MAKE_FUNCTION 8 (closure)
527 STORE_FAST 1 (foo)
528
529 %3d LOAD_FAST 1 (foo)
530 RETURN_VALUE
531 """ % (_h.__code__.co_firstlineno,
532 _h.__code__.co_firstlineno + 1,
533 __file__,
534 _h.__code__.co_firstlineno + 1,
535 _h.__code__.co_firstlineno + 4,
536 )
537
538 dis_nested_1 = """%s
539 Disassembly of <code object foo at 0x..., file "%s", line %d>:
540 COPY_FREE_VARS 1
541 MAKE_CELL 0 (x)
542
543 %3d RESUME 0
544
545 %3d LOAD_CLOSURE 0 (x)
546 BUILD_TUPLE 1
547 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
548 MAKE_FUNCTION 8 (closure)
549 LOAD_DEREF 1 (y)
550 GET_ITER
551 PRECALL 0
552 CALL 0
553 RETURN_VALUE
554 """ % (dis_nested_0,
555 __file__,
556 _h.__code__.co_firstlineno + 1,
557 _h.__code__.co_firstlineno + 1,
558 _h.__code__.co_firstlineno + 3,
559 __file__,
560 _h.__code__.co_firstlineno + 3,
561 )
562
563 dis_nested_2 = """%s
564 Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>:
565 COPY_FREE_VARS 1
566
567 %3d RESUME 0
568 BUILD_LIST 0
569 LOAD_FAST 0 (.0)
570 >> FOR_ITER 7 (to 24)
571 STORE_FAST 1 (z)
572 LOAD_DEREF 2 (x)
573 LOAD_FAST 1 (z)
574 BINARY_OP 0 (+)
575 LIST_APPEND 2
576 JUMP_BACKWARD 8 (to 8)
577 >> RETURN_VALUE
578 """ % (dis_nested_1,
579 __file__,
580 _h.__code__.co_firstlineno + 3,
581 _h.__code__.co_firstlineno + 3,
582 )
583
584 def load_test(x, y=0):
585 a, b = x, y
586 return a, b
587
588 dis_load_test_quickened_code = """\
589 %3d 0 RESUME_QUICK 0
590
591 %3d 2 LOAD_FAST__LOAD_FAST 0 (x)
592 4 LOAD_FAST 1 (y)
593 6 STORE_FAST__STORE_FAST 3 (b)
594 8 STORE_FAST__LOAD_FAST 2 (a)
595
596 %3d 10 LOAD_FAST__LOAD_FAST 2 (a)
597 12 LOAD_FAST 3 (b)
598 14 BUILD_TUPLE 2
599 16 RETURN_VALUE
600 """ % (load_test.__code__.co_firstlineno,
601 load_test.__code__.co_firstlineno + 1,
602 load_test.__code__.co_firstlineno + 2)
603
604 def loop_test():
605 for i in [1, 2, 3] * 3:
606 load_test(i)
607
608 dis_loop_test_quickened_code = """\
609 %3d 0 RESUME_QUICK 0
610
611 %3d 2 BUILD_LIST 0
612 4 LOAD_CONST 1 ((1, 2, 3))
613 6 LIST_EXTEND 1
614 8 LOAD_CONST 2 (3)
615 10 BINARY_OP_ADAPTIVE 5 (*)
616 14 GET_ITER
617 16 FOR_ITER 17 (to 52)
618 18 STORE_FAST 0 (i)
619
620 %3d 20 LOAD_GLOBAL_MODULE 1 (NULL + load_test)
621 32 LOAD_FAST 0 (i)
622 34 PRECALL_PYFUNC 1
623 38 CALL_PY_WITH_DEFAULTS 1
624 48 POP_TOP
625 50 JUMP_BACKWARD_QUICK 18 (to 16)
626
627 %3d >> 52 LOAD_CONST 0 (None)
628 54 RETURN_VALUE
629 """ % (loop_test.__code__.co_firstlineno,
630 loop_test.__code__.co_firstlineno + 1,
631 loop_test.__code__.co_firstlineno + 2,
632 loop_test.__code__.co_firstlineno + 1,)
633
634 def extended_arg_quick():
635 *_, _ = ...
636
637 dis_extended_arg_quick_code = """\
638 %3d 0 RESUME 0
639
640 %3d 2 LOAD_CONST 1 (Ellipsis)
641 4 EXTENDED_ARG 1
642 6 UNPACK_EX 256
643 8 STORE_FAST 0 (_)
644 10 STORE_FAST 0 (_)
645 12 LOAD_CONST 0 (None)
646 14 RETURN_VALUE
647 """% (extended_arg_quick.__code__.co_firstlineno,
648 extended_arg_quick.__code__.co_firstlineno + 1,)
649
650 QUICKENING_WARMUP_DELAY = 8
651
652 class ESC[4;38;5;81mDisTestBase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
653 "Common utilities for DisTests and TestDisTraceback"
654
655 def strip_addresses(self, text):
656 return re.sub(r'\b0x[0-9A-Fa-f]+\b', '0x...', text)
657
658 def find_offset_column(self, lines):
659 for line in lines:
660 if line and not line.startswith("Disassembly"):
661 break
662 else:
663 return 0, 0
664 offset = 5
665 while (line[offset] == " "):
666 offset += 1
667 if (line[offset] == ">"):
668 offset += 2
669 while (line[offset] == " "):
670 offset += 1
671 end = offset
672 while line[end] in "0123456789":
673 end += 1
674 return end-5, end
675
676 def assert_offsets_increasing(self, text, delta):
677 expected_offset = 0
678 lines = text.splitlines()
679 start, end = self.find_offset_column(lines)
680 for line in lines:
681 if not line:
682 continue
683 if line.startswith("Disassembly"):
684 expected_offset = 0
685 continue
686 if line.startswith("Exception"):
687 break
688 offset = int(line[start:end])
689 self.assertGreaterEqual(offset, expected_offset, line)
690 expected_offset = offset + delta
691
692 def strip_offsets(self, text):
693 lines = text.splitlines(True)
694 start, end = self.find_offset_column(lines)
695 res = []
696 lines = iter(lines)
697 for line in lines:
698 if line.startswith("Exception"):
699 res.append(line)
700 break
701 if not line or line.startswith("Disassembly"):
702 res.append(line)
703 else:
704 res.append(line[:start] + line[end:])
705 return "".join(res)
706
707 def do_disassembly_compare(self, got, expected, with_offsets=False):
708 if not with_offsets:
709 self.assert_offsets_increasing(got, 2)
710 got = self.strip_offsets(got)
711 if got != expected:
712 got = self.strip_addresses(got)
713 self.assertEqual(got, expected)
714
715
716 class ESC[4;38;5;81mDisTests(ESC[4;38;5;149mDisTestBase):
717
718 maxDiff = None
719
720 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs):
721 # We want to test the default printing behaviour, not the file arg
722 output = io.StringIO()
723 with contextlib.redirect_stdout(output):
724 if wrapper:
725 dis.dis(func, **kwargs)
726 else:
727 dis.disassemble(func, lasti, **kwargs)
728 return output.getvalue()
729
730 def get_disassemble_as_string(self, func, lasti=-1):
731 return self.get_disassembly(func, lasti, False)
732
733 def do_disassembly_test(self, func, expected, with_offsets=False):
734 self.maxDiff = None
735 got = self.get_disassembly(func, depth=0)
736 self.do_disassembly_compare(got, expected, with_offsets)
737
738 def test_opmap(self):
739 self.assertEqual(dis.opmap["NOP"], 9)
740 self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst)
741 self.assertIn(dis.opmap["STORE_NAME"], dis.hasname)
742
743 def test_opname(self):
744 self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST")
745
746 def test_boundaries(self):
747 self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG)
748 self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT)
749
750 def test_widths(self):
751 long_opcodes = set(['POP_JUMP_FORWARD_IF_FALSE',
752 'POP_JUMP_FORWARD_IF_TRUE',
753 'POP_JUMP_FORWARD_IF_NOT_NONE',
754 'POP_JUMP_FORWARD_IF_NONE',
755 'POP_JUMP_BACKWARD_IF_FALSE',
756 'POP_JUMP_BACKWARD_IF_TRUE',
757 'POP_JUMP_BACKWARD_IF_NOT_NONE',
758 'POP_JUMP_BACKWARD_IF_NONE',
759 'JUMP_BACKWARD_NO_INTERRUPT',
760 ])
761 for opcode, opname in enumerate(dis.opname):
762 if opname in long_opcodes:
763 continue
764 with self.subTest(opname=opname):
765 width = dis._OPNAME_WIDTH
766 if opcode < dis.HAVE_ARGUMENT:
767 width += 1 + dis._OPARG_WIDTH
768 self.assertLessEqual(len(opname), width)
769
770 def test_dis(self):
771 self.do_disassembly_test(_f, dis_f)
772
773 def test_bug_708901(self):
774 self.do_disassembly_test(bug708901, dis_bug708901)
775
776 def test_bug_1333982(self):
777 # This one is checking bytecodes generated for an `assert` statement,
778 # so fails if the tests are run with -O. Skip this test then.
779 if not __debug__:
780 self.skipTest('need asserts, run without -O')
781
782 self.do_disassembly_test(bug1333982, dis_bug1333982)
783
784 def test_bug_42562(self):
785 self.do_disassembly_test(bug42562, dis_bug42562)
786
787 def test_bug_45757(self):
788 # Extended arg followed by NOP
789 self.do_disassembly_test(code_bug_45757, dis_bug_45757)
790
791 def test_bug_46724(self):
792 # Test that negative operargs are handled properly
793 self.do_disassembly_test(bug46724, dis_bug46724)
794
795 def test_big_linenos(self):
796 def func(count):
797 namespace = {}
798 func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"])
799 exec(func, namespace)
800 return namespace['foo']
801
802 # Test all small ranges
803 for i in range(1, 300):
804 expected = _BIG_LINENO_FORMAT % (i + 2)
805 self.do_disassembly_test(func(i), expected)
806
807 # Test some larger ranges too
808 for i in range(300, 1000, 10):
809 expected = _BIG_LINENO_FORMAT % (i + 2)
810 self.do_disassembly_test(func(i), expected)
811
812 for i in range(1000, 5000, 10):
813 expected = _BIG_LINENO_FORMAT2 % (i + 2)
814 self.do_disassembly_test(func(i), expected)
815
816 from test import dis_module
817 self.do_disassembly_test(dis_module, dis_module_expected_results)
818
819 def test_big_offsets(self):
820 self.maxDiff = None
821 def func(count):
822 namespace = {}
823 func = "def foo(x):\n " + ";".join(["x = x + 1"] * count) + "\n return x"
824 exec(func, namespace)
825 return namespace['foo']
826
827 def expected(count, w):
828 s = ['''\
829 1 %*d RESUME 0
830
831 ''' % (w, 0)]
832 s += ['''\
833 %*d LOAD_FAST 0 (x)
834 %*d LOAD_CONST 1 (1)
835 %*d BINARY_OP 0 (+)
836 %*d STORE_FAST 0 (x)
837 ''' % (w, 10*i + 2, w, 10*i + 4, w, 10*i + 6, w, 10*i + 10)
838 for i in range(count)]
839 s += ['''\
840
841 3 %*d LOAD_FAST 0 (x)
842 %*d RETURN_VALUE
843 ''' % (w, 10*count + 2, w, 10*count + 4)]
844 s[1] = ' 2' + s[1][3:]
845 return ''.join(s)
846
847 for i in range(1, 5):
848 self.do_disassembly_test(func(i), expected(i, 4), True)
849 self.do_disassembly_test(func(999), expected(999, 4), True)
850 self.do_disassembly_test(func(1000), expected(1000, 5), True)
851
852 def test_disassemble_str(self):
853 self.do_disassembly_test(expr_str, dis_expr_str)
854 self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str)
855 self.do_disassembly_test(annot_stmt_str, dis_annot_stmt_str)
856 self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str)
857
858 def test_disassemble_bytes(self):
859 self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
860
861 def test_disassemble_class(self):
862 self.do_disassembly_test(_C, dis_c)
863
864 def test_disassemble_instance_method(self):
865 self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
866
867 def test_disassemble_instance_method_bytes(self):
868 method_bytecode = _C(1).__init__.__code__.co_code
869 self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
870
871 def test_disassemble_static_method(self):
872 self.do_disassembly_test(_C.sm, dis_c_static_method)
873
874 def test_disassemble_class_method(self):
875 self.do_disassembly_test(_C.cm, dis_c_class_method)
876
877 def test_disassemble_generator(self):
878 gen_func_disas = self.get_disassembly(_g) # Generator function
879 gen_disas = self.get_disassembly(_g(1)) # Generator iterator
880 self.assertEqual(gen_disas, gen_func_disas)
881
882 def test_disassemble_async_generator(self):
883 agen_func_disas = self.get_disassembly(_ag) # Async generator function
884 agen_disas = self.get_disassembly(_ag(1)) # Async generator iterator
885 self.assertEqual(agen_disas, agen_func_disas)
886
887 def test_disassemble_coroutine(self):
888 coro_func_disas = self.get_disassembly(_co) # Coroutine function
889 coro = _co(1) # Coroutine object
890 coro.close() # Avoid a RuntimeWarning (never awaited)
891 coro_disas = self.get_disassembly(coro)
892 self.assertEqual(coro_disas, coro_func_disas)
893
894 def test_disassemble_fstring(self):
895 self.do_disassembly_test(_fstring, dis_fstring)
896
897 def test_disassemble_try_finally(self):
898 self.do_disassembly_test(_tryfinally, dis_tryfinally)
899 self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst)
900
901 def test_dis_none(self):
902 try:
903 del sys.last_traceback
904 except AttributeError:
905 pass
906 self.assertRaises(RuntimeError, dis.dis, None)
907
908 def test_dis_traceback(self):
909 self.maxDiff = None
910 try:
911 del sys.last_traceback
912 except AttributeError:
913 pass
914
915 try:
916 1/0
917 except Exception as e:
918 tb = e.__traceback__
919 sys.last_traceback = tb
920
921 tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti)
922 self.do_disassembly_test(None, tb_dis, True)
923
924 def test_dis_object(self):
925 self.assertRaises(TypeError, dis.dis, object())
926
927 def test_disassemble_recursive(self):
928 def check(expected, **kwargs):
929 dis = self.get_disassembly(_h, **kwargs)
930 dis = self.strip_addresses(dis)
931 dis = self.strip_offsets(dis)
932 self.assertEqual(dis, expected)
933
934 check(dis_nested_0, depth=0)
935 check(dis_nested_1, depth=1)
936 check(dis_nested_2, depth=2)
937 check(dis_nested_2, depth=3)
938 check(dis_nested_2, depth=None)
939 check(dis_nested_2)
940
941 @staticmethod
942 def code_quicken(f, times=QUICKENING_WARMUP_DELAY):
943 for _ in range(times):
944 f()
945
946 @cpython_only
947 def test_super_instructions(self):
948 self.code_quicken(lambda: load_test(0, 0))
949 got = self.get_disassembly(load_test, adaptive=True)
950 self.do_disassembly_compare(got, dis_load_test_quickened_code, True)
951
952 @cpython_only
953 def test_binary_specialize(self):
954 binary_op_quicken = """\
955 0 0 RESUME_QUICK 0
956
957 1 2 LOAD_NAME 0 (a)
958 4 LOAD_NAME 1 (b)
959 6 %s
960 10 RETURN_VALUE
961 """
962 co_int = compile('a + b', "<int>", "eval")
963 self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2}))
964 got = self.get_disassembly(co_int, adaptive=True)
965 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_INT 0 (+)", True)
966
967 co_unicode = compile('a + b', "<unicode>", "eval")
968 self.code_quicken(lambda: exec(co_unicode, {}, {'a': 'a', 'b': 'b'}))
969 got = self.get_disassembly(co_unicode, adaptive=True)
970 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)", True)
971
972 binary_subscr_quicken = """\
973 0 0 RESUME_QUICK 0
974
975 1 2 LOAD_NAME 0 (a)
976 4 LOAD_CONST 0 (0)
977 6 %s
978 16 RETURN_VALUE
979 """
980 co_list = compile('a[0]', "<list>", "eval")
981 self.code_quicken(lambda: exec(co_list, {}, {'a': [0]}))
982 got = self.get_disassembly(co_list, adaptive=True)
983 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_LIST_INT", True)
984
985 co_dict = compile('a[0]', "<dict>", "eval")
986 self.code_quicken(lambda: exec(co_dict, {}, {'a': {0: '1'}}))
987 got = self.get_disassembly(co_dict, adaptive=True)
988 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT", True)
989
990 @cpython_only
991 def test_load_attr_specialize(self):
992 load_attr_quicken = """\
993 0 0 RESUME_QUICK 0
994
995 1 2 LOAD_CONST 0 ('a')
996 4 LOAD_ATTR_SLOT 0 (__class__)
997 14 RETURN_VALUE
998 """
999 co = compile("'a'.__class__", "", "eval")
1000 self.code_quicken(lambda: exec(co, {}, {}))
1001 got = self.get_disassembly(co, adaptive=True)
1002 self.do_disassembly_compare(got, load_attr_quicken, True)
1003
1004 @cpython_only
1005 def test_call_specialize(self):
1006 call_quicken = """\
1007 0 0 RESUME_QUICK 0
1008
1009 1 2 PUSH_NULL
1010 4 LOAD_NAME 0 (str)
1011 6 LOAD_CONST 0 (1)
1012 8 PRECALL_NO_KW_STR_1 1
1013 12 CALL_ADAPTIVE 1
1014 22 RETURN_VALUE
1015 """
1016 co = compile("str(1)", "", "eval")
1017 self.code_quicken(lambda: exec(co, {}, {}))
1018 got = self.get_disassembly(co, adaptive=True)
1019 self.do_disassembly_compare(got, call_quicken, True)
1020
1021 @cpython_only
1022 def test_loop_quicken(self):
1023 # Loop can trigger a quicken where the loop is located
1024 self.code_quicken(loop_test, 1)
1025 got = self.get_disassembly(loop_test, adaptive=True)
1026 self.do_disassembly_compare(got, dis_loop_test_quickened_code, True)
1027
1028 @cpython_only
1029 def test_extended_arg_quick(self):
1030 got = self.get_disassembly(extended_arg_quick)
1031 self.do_disassembly_compare(got, dis_extended_arg_quick_code, True)
1032
1033 def get_cached_values(self, quickened, adaptive):
1034 def f():
1035 l = []
1036 for i in range(42):
1037 l.append(i)
1038 if quickened:
1039 self.code_quicken(f)
1040 else:
1041 # "copy" the code to un-quicken it:
1042 f.__code__ = f.__code__.replace()
1043 for instruction in dis.get_instructions(
1044 f, show_caches=True, adaptive=adaptive
1045 ):
1046 if instruction.opname == "CACHE":
1047 yield instruction.argrepr
1048
1049 @cpython_only
1050 def test_show_caches(self):
1051 for quickened in (False, True):
1052 for adaptive in (False, True):
1053 with self.subTest(f"{quickened=}, {adaptive=}"):
1054 if quickened and adaptive:
1055 pattern = r"^(\w+: \d+)?$"
1056 else:
1057 pattern = r"^(\w+: 0)?$"
1058 caches = list(self.get_cached_values(quickened, adaptive))
1059 for cache in caches:
1060 self.assertRegex(cache, pattern)
1061 total_caches = 25
1062 empty_caches = 8 if adaptive and quickened else total_caches
1063 self.assertEqual(caches.count(""), empty_caches)
1064 self.assertEqual(len(caches), total_caches)
1065
1066
1067 class ESC[4;38;5;81mDisWithFileTests(ESC[4;38;5;149mDisTests):
1068
1069 # Run the tests again, using the file arg instead of print
1070 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs):
1071 output = io.StringIO()
1072 if wrapper:
1073 dis.dis(func, file=output, **kwargs)
1074 else:
1075 dis.disassemble(func, lasti, file=output, **kwargs)
1076 return output.getvalue()
1077
1078
1079 if dis.code_info.__doc__ is None:
1080 code_info_consts = "0: None"
1081 else:
1082 code_info_consts = "0: 'Formatted details of methods, functions, or code.'"
1083
1084 code_info_code_info = f"""\
1085 Name: code_info
1086 Filename: (.*)
1087 Argument count: 1
1088 Positional-only arguments: 0
1089 Kw-only arguments: 0
1090 Number of locals: 1
1091 Stack size: \\d+
1092 Flags: OPTIMIZED, NEWLOCALS
1093 Constants:
1094 {code_info_consts}
1095 Names:
1096 0: _format_code_info
1097 1: _get_code_object
1098 Variable names:
1099 0: x"""
1100
1101
1102 @staticmethod
1103 def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
1104 def f(c=c):
1105 print(a, b, x, y, z, c, d, e, f)
1106 yield a, b, x, y, z, c, d, e, f
1107
1108 code_info_tricky = """\
1109 Name: tricky
1110 Filename: (.*)
1111 Argument count: 5
1112 Positional-only arguments: 2
1113 Kw-only arguments: 3
1114 Number of locals: 10
1115 Stack size: \\d+
1116 Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
1117 Constants:
1118 0: None
1119 1: <code object f at (.*), file "(.*)", line (.*)>
1120 Variable names:
1121 0: a
1122 1: b
1123 2: x
1124 3: y
1125 4: z
1126 5: c
1127 6: d
1128 7: e
1129 8: args
1130 9: kwds
1131 Cell variables:
1132 0: [abedfxyz]
1133 1: [abedfxyz]
1134 2: [abedfxyz]
1135 3: [abedfxyz]
1136 4: [abedfxyz]
1137 5: [abedfxyz]"""
1138 # NOTE: the order of the cell variables above depends on dictionary order!
1139
1140 co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
1141
1142 code_info_tricky_nested_f = """\
1143 Filename: (.*)
1144 Argument count: 1
1145 Positional-only arguments: 0
1146 Kw-only arguments: 0
1147 Number of locals: 1
1148 Stack size: \\d+
1149 Flags: OPTIMIZED, NEWLOCALS, NESTED
1150 Constants:
1151 0: None
1152 Names:
1153 0: print
1154 Variable names:
1155 0: c
1156 Free variables:
1157 0: [abedfxyz]
1158 1: [abedfxyz]
1159 2: [abedfxyz]
1160 3: [abedfxyz]
1161 4: [abedfxyz]
1162 5: [abedfxyz]"""
1163
1164 code_info_expr_str = """\
1165 Name: <module>
1166 Filename: <disassembly>
1167 Argument count: 0
1168 Positional-only arguments: 0
1169 Kw-only arguments: 0
1170 Number of locals: 0
1171 Stack size: \\d+
1172 Flags: 0x0
1173 Constants:
1174 0: 1
1175 Names:
1176 0: x"""
1177
1178 code_info_simple_stmt_str = """\
1179 Name: <module>
1180 Filename: <disassembly>
1181 Argument count: 0
1182 Positional-only arguments: 0
1183 Kw-only arguments: 0
1184 Number of locals: 0
1185 Stack size: \\d+
1186 Flags: 0x0
1187 Constants:
1188 0: 1
1189 1: None
1190 Names:
1191 0: x"""
1192
1193 code_info_compound_stmt_str = """\
1194 Name: <module>
1195 Filename: <disassembly>
1196 Argument count: 0
1197 Positional-only arguments: 0
1198 Kw-only arguments: 0
1199 Number of locals: 0
1200 Stack size: \\d+
1201 Flags: 0x0
1202 Constants:
1203 0: 0
1204 1: 1
1205 Names:
1206 0: x"""
1207
1208
1209 async def async_def():
1210 await 1
1211 async for a in b: pass
1212 async with c as d: pass
1213
1214 code_info_async_def = """\
1215 Name: async_def
1216 Filename: (.*)
1217 Argument count: 0
1218 Positional-only arguments: 0
1219 Kw-only arguments: 0
1220 Number of locals: 2
1221 Stack size: \\d+
1222 Flags: OPTIMIZED, NEWLOCALS, COROUTINE
1223 Constants:
1224 0: None
1225 1: 1
1226 Names:
1227 0: b
1228 1: c
1229 Variable names:
1230 0: a
1231 1: d"""
1232
1233 class ESC[4;38;5;81mCodeInfoTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1234 test_pairs = [
1235 (dis.code_info, code_info_code_info),
1236 (tricky, code_info_tricky),
1237 (co_tricky_nested_f, code_info_tricky_nested_f),
1238 (expr_str, code_info_expr_str),
1239 (simple_stmt_str, code_info_simple_stmt_str),
1240 (compound_stmt_str, code_info_compound_stmt_str),
1241 (async_def, code_info_async_def)
1242 ]
1243
1244 def test_code_info(self):
1245 self.maxDiff = 1000
1246 for x, expected in self.test_pairs:
1247 self.assertRegex(dis.code_info(x), expected)
1248
1249 def test_show_code(self):
1250 self.maxDiff = 1000
1251 for x, expected in self.test_pairs:
1252 with captured_stdout() as output:
1253 dis.show_code(x)
1254 self.assertRegex(output.getvalue(), expected+"\n")
1255 output = io.StringIO()
1256 dis.show_code(x, file=output)
1257 self.assertRegex(output.getvalue(), expected)
1258
1259 def test_code_info_object(self):
1260 self.assertRaises(TypeError, dis.code_info, object())
1261
1262 def test_pretty_flags_no_flags(self):
1263 self.assertEqual(dis.pretty_flags(0), '0x0')
1264
1265
1266 # Fodder for instruction introspection tests
1267 # Editing any of these may require recalculating the expected output
1268 def outer(a=1, b=2):
1269 def f(c=3, d=4):
1270 def inner(e=5, f=6):
1271 print(a, b, c, d, e, f)
1272 print(a, b, c, d)
1273 return inner
1274 print(a, b, '', 1, [], {}, "Hello world!")
1275 return f
1276
1277 def jumpy():
1278 # This won't actually run (but that's OK, we only disassemble it)
1279 for i in range(10):
1280 print(i)
1281 if i < 4:
1282 continue
1283 if i > 6:
1284 break
1285 else:
1286 print("I can haz else clause?")
1287 while i:
1288 print(i)
1289 i -= 1
1290 if i > 6:
1291 continue
1292 if i < 4:
1293 break
1294 else:
1295 print("Who let lolcatz into this test suite?")
1296 try:
1297 1 / 0
1298 except ZeroDivisionError:
1299 print("Here we go, here we go, here we go...")
1300 else:
1301 with i as dodgy:
1302 print("Never reach this")
1303 finally:
1304 print("OK, now we're done")
1305
1306 # End fodder for opinfo generation tests
1307 expected_outer_line = 1
1308 _line_offset = outer.__code__.co_firstlineno - 1
1309 code_object_f = outer.__code__.co_consts[3]
1310 expected_f_line = code_object_f.co_firstlineno - _line_offset
1311 code_object_inner = code_object_f.co_consts[3]
1312 expected_inner_line = code_object_inner.co_firstlineno - _line_offset
1313 expected_jumpy_line = 1
1314
1315 # The following lines are useful to regenerate the expected results after
1316 # either the fodder is modified or the bytecode generation changes
1317 # After regeneration, update the references to code_object_f and
1318 # code_object_inner before rerunning the tests
1319
1320 def _stringify_instruction(instr):
1321 # Since line numbers and other offsets change a lot for these
1322 # test cases, ignore them.
1323 return str(instr._replace(positions=None))
1324
1325 def _prepare_test_cases():
1326 _instructions = dis.get_instructions(outer, first_line=expected_outer_line)
1327 print('expected_opinfo_outer = [\n ',
1328 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='')
1329 _instructions = dis.get_instructions(outer(), first_line=expected_f_line)
1330 print('expected_opinfo_f = [\n ',
1331 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='')
1332 _instructions = dis.get_instructions(outer()(), first_line=expected_inner_line)
1333 print('expected_opinfo_inner = [\n ',
1334 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='')
1335 _instructions = dis.get_instructions(jumpy, first_line=expected_jumpy_line)
1336 print('expected_opinfo_jumpy = [\n ',
1337 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='')
1338 dis.dis(outer)
1339
1340 #_prepare_test_cases()
1341
1342 Instruction = dis.Instruction
1343 expected_opinfo_outer = [
1344 Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False, positions=None),
1345 Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False, positions=None),
1346 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=4, starts_line=1, is_jump_target=False, positions=None),
1347 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=(3, 4), argrepr='(3, 4)', offset=6, starts_line=2, is_jump_target=False, positions=None),
1348 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=8, starts_line=None, is_jump_target=False, positions=None),
1349 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=10, starts_line=None, is_jump_target=False, positions=None),
1350 Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False, positions=None),
1351 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=14, starts_line=None, is_jump_target=False, positions=None),
1352 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False, positions=None),
1353 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None),
1354 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=20, starts_line=7, is_jump_target=False, positions=None),
1355 Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=32, starts_line=None, is_jump_target=False, positions=None),
1356 Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=34, starts_line=None, is_jump_target=False, positions=None),
1357 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False, positions=None),
1358 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=38, starts_line=None, is_jump_target=False, positions=None),
1359 Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
1360 Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
1361 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=44, starts_line=None, is_jump_target=False, positions=None),
1362 Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
1363 Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None),
1364 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None),
1365 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=62, starts_line=8, is_jump_target=False, positions=None),
1366 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
1367 ]
1368
1369 expected_opinfo_f = [
1370 Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
1371 Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=2, starts_line=None, is_jump_target=False, positions=None),
1372 Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, starts_line=None, is_jump_target=False, positions=None),
1373 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=6, starts_line=2, is_jump_target=False, positions=None),
1374 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=(5, 6), argrepr='(5, 6)', offset=8, starts_line=3, is_jump_target=False, positions=None),
1375 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=10, starts_line=None, is_jump_target=False, positions=None),
1376 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=12, starts_line=None, is_jump_target=False, positions=None),
1377 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=14, starts_line=None, is_jump_target=False, positions=None),
1378 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=16, starts_line=None, is_jump_target=False, positions=None),
1379 Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
1380 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, starts_line=None, is_jump_target=False, positions=None),
1381 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=22, starts_line=None, is_jump_target=False, positions=None),
1382 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=24, starts_line=None, is_jump_target=False, positions=None),
1383 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=26, starts_line=5, is_jump_target=False, positions=None),
1384 Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=38, starts_line=None, is_jump_target=False, positions=None),
1385 Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=40, starts_line=None, is_jump_target=False, positions=None),
1386 Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False, positions=None),
1387 Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=44, starts_line=None, is_jump_target=False, positions=None),
1388 Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
1389 Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None),
1390 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None),
1391 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=62, starts_line=6, is_jump_target=False, positions=None),
1392 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
1393 ]
1394
1395 expected_opinfo_inner = [
1396 Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
1397 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=2, starts_line=3, is_jump_target=False, positions=None),
1398 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=4, starts_line=4, is_jump_target=False, positions=None),
1399 Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=16, starts_line=None, is_jump_target=False, positions=None),
1400 Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=18, starts_line=None, is_jump_target=False, positions=None),
1401 Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=20, starts_line=None, is_jump_target=False, positions=None),
1402 Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=22, starts_line=None, is_jump_target=False, positions=None),
1403 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=24, starts_line=None, is_jump_target=False, positions=None),
1404 Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=26, starts_line=None, is_jump_target=False, positions=None),
1405 Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
1406 Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
1407 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
1408 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=44, starts_line=None, is_jump_target=False, positions=None),
1409 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
1410 ]
1411
1412 expected_opinfo_jumpy = [
1413 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None),
1414 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, starts_line=3, is_jump_target=False, positions=None),
1415 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=14, starts_line=None, is_jump_target=False, positions=None),
1416 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
1417 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None),
1418 Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None),
1419 Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=98, argrepr='to 98', offset=32, starts_line=None, is_jump_target=True, positions=None),
1420 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=False, positions=None),
1421 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=36, starts_line=4, is_jump_target=False, positions=None),
1422 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=48, starts_line=None, is_jump_target=False, positions=None),
1423 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None),
1424 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None),
1425 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
1426 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=5, is_jump_target=False, positions=None),
1427 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None),
1428 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None),
1429 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None),
1430 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
1431 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None),
1432 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None),
1433 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None),
1434 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None),
1435 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None),
1436 Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None),
1437 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
1438 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None),
1439 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None),
1440 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
1441 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None),
1442 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None),
1443 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=128, starts_line=11, is_jump_target=True, positions=None),
1444 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=36, argval=204, argrepr='to 204', offset=130, starts_line=None, is_jump_target=False, positions=None),
1445 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=132, starts_line=12, is_jump_target=True, positions=None),
1446 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=None, is_jump_target=False, positions=None),
1447 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None),
1448 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
1449 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
1450 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=162, starts_line=13, is_jump_target=False, positions=None),
1451 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=164, starts_line=None, is_jump_target=False, positions=None),
1452 Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=166, starts_line=None, is_jump_target=False, positions=None),
1453 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=170, starts_line=None, is_jump_target=False, positions=None),
1454 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=14, is_jump_target=False, positions=None),
1455 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None),
1456 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None),
1457 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None),
1458 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
1459 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None),
1460 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None),
1461 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None),
1462 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=200, argrepr='to 200', offset=196, starts_line=None, is_jump_target=False, positions=None),
1463 Instruction(opname='JUMP_FORWARD', opcode=110, arg=17, argval=234, argrepr='to 234', offset=198, starts_line=17, is_jump_target=False, positions=None),
1464 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=200, starts_line=11, is_jump_target=True, positions=None),
1465 Instruction(opname='POP_JUMP_BACKWARD_IF_TRUE', opcode=176, arg=36, argval=132, argrepr='to 132', offset=202, starts_line=None, is_jump_target=False, positions=None),
1466 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=204, starts_line=19, is_jump_target=True, positions=None),
1467 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=216, starts_line=None, is_jump_target=False, positions=None),
1468 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
1469 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None),
1470 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None),
1471 Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=234, starts_line=20, is_jump_target=True, positions=None),
1472 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=236, starts_line=21, is_jump_target=False, positions=None),
1473 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=238, starts_line=None, is_jump_target=False, positions=None),
1474 Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=240, starts_line=None, is_jump_target=False, positions=None),
1475 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=244, starts_line=None, is_jump_target=False, positions=None),
1476 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=246, starts_line=25, is_jump_target=False, positions=None),
1477 Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=248, starts_line=None, is_jump_target=False, positions=None),
1478 Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=250, starts_line=None, is_jump_target=False, positions=None),
1479 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=252, starts_line=26, is_jump_target=False, positions=None),
1480 Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=264, starts_line=None, is_jump_target=False, positions=None),
1481 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None),
1482 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None),
1483 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=280, starts_line=None, is_jump_target=False, positions=None),
1484 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=282, starts_line=25, is_jump_target=False, positions=None),
1485 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=284, starts_line=None, is_jump_target=False, positions=None),
1486 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=286, starts_line=None, is_jump_target=False, positions=None),
1487 Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None),
1488 Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None),
1489 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None),
1490 Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=328, argrepr='to 328', offset=304, starts_line=None, is_jump_target=False, positions=None),
1491 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None),
1492 Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None),
1493 Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=320, argrepr='to 320', offset=310, starts_line=None, is_jump_target=False, positions=None),
1494 Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None),
1495 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None),
1496 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None),
1497 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None),
1498 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=True, positions=None),
1499 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None),
1500 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None),
1501 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None),
1502 Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=392, argrepr='to 392', offset=328, starts_line=None, is_jump_target=True, positions=None),
1503 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None),
1504 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None),
1505 Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None),
1506 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None),
1507 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None),
1508 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None),
1509 Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None),
1510 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None),
1511 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None),
1512 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None),
1513 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None),
1514 Instruction(opname='JUMP_FORWARD', opcode=110, arg=4, argval=392, argrepr='to 392', offset=382, starts_line=None, is_jump_target=False, positions=None),
1515 Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None),
1516 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None),
1517 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None),
1518 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None),
1519 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=392, starts_line=28, is_jump_target=True, positions=None),
1520 Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=404, starts_line=None, is_jump_target=False, positions=None),
1521 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=406, starts_line=None, is_jump_target=False, positions=None),
1522 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None),
1523 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None),
1524 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=422, starts_line=None, is_jump_target=False, positions=None),
1525 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None),
1526 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None),
1527 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=428, starts_line=None, is_jump_target=False, positions=None),
1528 Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=440, starts_line=None, is_jump_target=False, positions=None),
1529 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=442, starts_line=None, is_jump_target=False, positions=None),
1530 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=446, starts_line=None, is_jump_target=False, positions=None),
1531 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=456, starts_line=None, is_jump_target=False, positions=None),
1532 Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None),
1533 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None),
1534 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None),
1535 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=464, starts_line=None, is_jump_target=False, positions=None),
1536 ]
1537
1538 # One last piece of inspect fodder to check the default line number handling
1539 def simple(): pass
1540 expected_opinfo_simple = [
1541 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False, positions=None),
1542 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=2, starts_line=None, is_jump_target=False),
1543 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=4, starts_line=None, is_jump_target=False)
1544 ]
1545
1546
1547 class ESC[4;38;5;81mInstructionTestCase(ESC[4;38;5;149mBytecodeTestCase):
1548
1549 def assertInstructionsEqual(self, instrs_1, instrs_2, /):
1550 instrs_1 = [instr_1._replace(positions=None) for instr_1 in instrs_1]
1551 instrs_2 = [instr_2._replace(positions=None) for instr_2 in instrs_2]
1552 self.assertEqual(instrs_1, instrs_2)
1553
1554 class ESC[4;38;5;81mInstructionTests(ESC[4;38;5;149mInstructionTestCase):
1555
1556 def __init__(self, *args):
1557 super().__init__(*args)
1558 self.maxDiff = None
1559
1560 def test_default_first_line(self):
1561 actual = dis.get_instructions(simple)
1562 self.assertInstructionsEqual(list(actual), expected_opinfo_simple)
1563
1564 def test_first_line_set_to_None(self):
1565 actual = dis.get_instructions(simple, first_line=None)
1566 self.assertInstructionsEqual(list(actual), expected_opinfo_simple)
1567
1568 def test_outer(self):
1569 actual = dis.get_instructions(outer, first_line=expected_outer_line)
1570 self.assertInstructionsEqual(list(actual), expected_opinfo_outer)
1571
1572 def test_nested(self):
1573 with captured_stdout():
1574 f = outer()
1575 actual = dis.get_instructions(f, first_line=expected_f_line)
1576 self.assertInstructionsEqual(list(actual), expected_opinfo_f)
1577
1578 def test_doubly_nested(self):
1579 with captured_stdout():
1580 inner = outer()()
1581 actual = dis.get_instructions(inner, first_line=expected_inner_line)
1582 self.assertInstructionsEqual(list(actual), expected_opinfo_inner)
1583
1584 def test_jumpy(self):
1585 actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line)
1586 self.assertInstructionsEqual(list(actual), expected_opinfo_jumpy)
1587
1588 @requires_debug_ranges()
1589 def test_co_positions(self):
1590 code = compile('f(\n x, y, z\n)', '<test>', 'exec')
1591 positions = [
1592 instr.positions
1593 for instr in dis.get_instructions(code)
1594 ]
1595 expected = [
1596 (0, 1, 0, 0),
1597 (1, 1, 0, 1),
1598 (1, 1, 0, 1),
1599 (2, 2, 2, 3),
1600 (2, 2, 5, 6),
1601 (2, 2, 8, 9),
1602 (1, 3, 0, 1),
1603 (1, 3, 0, 1),
1604 (1, 3, 0, 1),
1605 (1, 3, 0, 1),
1606 (1, 3, 0, 1)
1607 ]
1608 self.assertEqual(positions, expected)
1609
1610 named_positions = [
1611 (pos.lineno, pos.end_lineno, pos.col_offset, pos.end_col_offset)
1612 for pos in positions
1613 ]
1614 self.assertEqual(named_positions, expected)
1615
1616 @requires_debug_ranges()
1617 def test_co_positions_missing_info(self):
1618 code = compile('x, y, z', '<test>', 'exec')
1619 code_without_location_table = code.replace(co_linetable=b'')
1620 actual = dis.get_instructions(code_without_location_table)
1621 for instruction in actual:
1622 with self.subTest(instruction=instruction):
1623 positions = instruction.positions
1624 self.assertEqual(len(positions), 4)
1625 if instruction.opname == "RESUME":
1626 continue
1627 self.assertIsNone(positions.lineno)
1628 self.assertIsNone(positions.end_lineno)
1629 self.assertIsNone(positions.col_offset)
1630 self.assertIsNone(positions.end_col_offset)
1631
1632 @requires_debug_ranges()
1633 def test_co_positions_with_lots_of_caches(self):
1634 def roots(a, b, c):
1635 d = b**2 - 4 * a * c
1636 yield (-b - cmath.sqrt(d)) / (2 * a)
1637 if d:
1638 yield (-b + cmath.sqrt(d)) / (2 * a)
1639 code = roots.__code__
1640 ops = code.co_code[::2]
1641 cache_opcode = opcode.opmap["CACHE"]
1642 caches = sum(op == cache_opcode for op in ops)
1643 non_caches = len(ops) - caches
1644 # Make sure we have "lots of caches". If not, roots should be changed:
1645 assert 1 / 3 <= caches / non_caches, "this test needs more caches!"
1646 for show_caches in (False, True):
1647 for adaptive in (False, True):
1648 with self.subTest(f"{adaptive=}, {show_caches=}"):
1649 co_positions = [
1650 positions
1651 for op, positions in zip(ops, code.co_positions(), strict=True)
1652 if show_caches or op != cache_opcode
1653 ]
1654 dis_positions = [
1655 instruction.positions
1656 for instruction in dis.get_instructions(
1657 code, adaptive=adaptive, show_caches=show_caches
1658 )
1659 ]
1660 self.assertEqual(co_positions, dis_positions)
1661
1662 # get_instructions has its own tests above, so can rely on it to validate
1663 # the object oriented API
1664 class ESC[4;38;5;81mBytecodeTests(ESC[4;38;5;149mInstructionTestCase, ESC[4;38;5;149mDisTestBase):
1665
1666 def test_instantiation(self):
1667 # Test with function, method, code string and code object
1668 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]:
1669 with self.subTest(obj=obj):
1670 b = dis.Bytecode(obj)
1671 self.assertIsInstance(b.codeobj, types.CodeType)
1672
1673 self.assertRaises(TypeError, dis.Bytecode, object())
1674
1675 def test_iteration(self):
1676 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]:
1677 with self.subTest(obj=obj):
1678 via_object = list(dis.Bytecode(obj))
1679 via_generator = list(dis.get_instructions(obj))
1680 self.assertInstructionsEqual(via_object, via_generator)
1681
1682 def test_explicit_first_line(self):
1683 actual = dis.Bytecode(outer, first_line=expected_outer_line)
1684 self.assertInstructionsEqual(list(actual), expected_opinfo_outer)
1685
1686 def test_source_line_in_disassembly(self):
1687 # Use the line in the source code
1688 actual = dis.Bytecode(simple).dis()
1689 actual = actual.strip().partition(" ")[0] # extract the line no
1690 expected = str(simple.__code__.co_firstlineno)
1691 self.assertEqual(actual, expected)
1692 # Use an explicit first line number
1693 actual = dis.Bytecode(simple, first_line=350).dis()
1694 actual = actual.strip().partition(" ")[0] # extract the line no
1695 self.assertEqual(actual, "350")
1696
1697 def test_info(self):
1698 self.maxDiff = 1000
1699 for x, expected in CodeInfoTests.test_pairs:
1700 b = dis.Bytecode(x)
1701 self.assertRegex(b.info(), expected)
1702
1703 def test_disassembled(self):
1704 actual = dis.Bytecode(_f).dis()
1705 self.do_disassembly_compare(actual, dis_f)
1706
1707 def test_from_traceback(self):
1708 tb = get_tb()
1709 b = dis.Bytecode.from_traceback(tb)
1710 while tb.tb_next: tb = tb.tb_next
1711
1712 self.assertEqual(b.current_offset, tb.tb_lasti)
1713
1714 def test_from_traceback_dis(self):
1715 self.maxDiff = None
1716 tb = get_tb()
1717 b = dis.Bytecode.from_traceback(tb)
1718 self.assertEqual(self.strip_offsets(b.dis()), dis_traceback)
1719
1720 @requires_debug_ranges()
1721 def test_bytecode_co_positions(self):
1722 bytecode = dis.Bytecode("a=1")
1723 for instr, positions in zip(bytecode, bytecode.codeobj.co_positions()):
1724 assert instr.positions == positions
1725
1726 class ESC[4;38;5;81mTestBytecodeTestCase(ESC[4;38;5;149mBytecodeTestCase):
1727 def test_assert_not_in_with_op_not_in_bytecode(self):
1728 code = compile("a = 1", "<string>", "exec")
1729 self.assertInBytecode(code, "LOAD_CONST", 1)
1730 self.assertNotInBytecode(code, "LOAD_NAME")
1731 self.assertNotInBytecode(code, "LOAD_NAME", "a")
1732
1733 def test_assert_not_in_with_arg_not_in_bytecode(self):
1734 code = compile("a = 1", "<string>", "exec")
1735 self.assertInBytecode(code, "LOAD_CONST")
1736 self.assertInBytecode(code, "LOAD_CONST", 1)
1737 self.assertNotInBytecode(code, "LOAD_CONST", 2)
1738
1739 def test_assert_not_in_with_arg_in_bytecode(self):
1740 code = compile("a = 1", "<string>", "exec")
1741 with self.assertRaises(AssertionError):
1742 self.assertNotInBytecode(code, "LOAD_CONST", 1)
1743
1744 class ESC[4;38;5;81mTestFinderMethods(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
1745 def test__find_imports(self):
1746 cases = [
1747 ("import a.b.c", ('a.b.c', 0, None)),
1748 ("from a.b import c", ('a.b', 0, ('c',))),
1749 ("from a.b import c as d", ('a.b', 0, ('c',))),
1750 ("from a.b import *", ('a.b', 0, ('*',))),
1751 ("from ...a.b import c as d", ('a.b', 3, ('c',))),
1752 ("from ..a.b import c as d, e as f", ('a.b', 2, ('c', 'e'))),
1753 ("from ..a.b import *", ('a.b', 2, ('*',))),
1754 ]
1755 for src, expected in cases:
1756 with self.subTest(src=src):
1757 code = compile(src, "<string>", "exec")
1758 res = tuple(dis._find_imports(code))
1759 self.assertEqual(len(res), 1)
1760 self.assertEqual(res[0], expected)
1761
1762 def test__find_store_names(self):
1763 cases = [
1764 ("x+y", ()),
1765 ("x=y=1", ('x', 'y')),
1766 ("x+=y", ('x',)),
1767 ("global x\nx=y=1", ('x', 'y')),
1768 ("global x\nz=x", ('z',)),
1769 ]
1770 for src, expected in cases:
1771 with self.subTest(src=src):
1772 code = compile(src, "<string>", "exec")
1773 res = tuple(dis._find_store_names(code))
1774 self.assertEqual(res, expected)
1775
1776 def test_findlabels(self):
1777 labels = dis.findlabels(jumpy.__code__.co_code)
1778 jumps = [
1779 instr.offset
1780 for instr in expected_opinfo_jumpy
1781 if instr.is_jump_target
1782 ]
1783
1784 self.assertEqual(sorted(labels), sorted(jumps))
1785
1786
1787 class ESC[4;38;5;81mTestDisTraceback(ESC[4;38;5;149mDisTestBase):
1788 def setUp(self) -> None:
1789 try: # We need to clean up existing tracebacks
1790 del sys.last_traceback
1791 except AttributeError:
1792 pass
1793 return super().setUp()
1794
1795 def get_disassembly(self, tb):
1796 output = io.StringIO()
1797 with contextlib.redirect_stdout(output):
1798 dis.distb(tb)
1799 return output.getvalue()
1800
1801 def test_distb_empty(self):
1802 with self.assertRaises(RuntimeError):
1803 dis.distb()
1804
1805 def test_distb_last_traceback(self):
1806 self.maxDiff = None
1807 # We need to have an existing last traceback in `sys`:
1808 tb = get_tb()
1809 sys.last_traceback = tb
1810
1811 self.do_disassembly_compare(self.get_disassembly(None), dis_traceback)
1812
1813 def test_distb_explicit_arg(self):
1814 self.maxDiff = None
1815 tb = get_tb()
1816
1817 self.do_disassembly_compare(self.get_disassembly(tb), dis_traceback)
1818
1819
1820 class ESC[4;38;5;81mTestDisTracebackWithFile(ESC[4;38;5;149mTestDisTraceback):
1821 # Run the `distb` tests again, using the file arg instead of print
1822 def get_disassembly(self, tb):
1823 output = io.StringIO()
1824 with contextlib.redirect_stdout(output):
1825 dis.distb(tb, file=output)
1826 return output.getvalue()
1827
1828
1829 if __name__ == "__main__":
1830 unittest.main()