1# Minimal tests for dis module
2
3import contextlib
4import dis
5import io
6import re
7import sys
8import types
9import unittest
10from test.support import captured_stdout, requires_debug_ranges, cpython_only
11from test.support.bytecode_helper import BytecodeTestCase
12
13import opcode
14
15
16def 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
29TRACEBACK_CODE = get_tb().tb_frame.f_code
30
31class _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
43dis_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
55dis_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
66dis_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
78dis_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.
90dis_c = """\
91Disassembly of %s:
92%s
93Disassembly of %s:
94%s
95Disassembly 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
101def _f(a):
102    print(a)
103    return 1
104
105dis_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
121dis_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
133def bug708901():
134    for res in range(1,
135                     10):
136        pass
137
138dis_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
164def bug1333982(x=[]):
165    assert 0, ([s for s in x] +
166              1)
167    pass
168
169dis_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
194def bug42562():
195    pass
196
197
198# Set line number for 'pass' to None
199bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8')
200
201
202dis_bug42562 = """\
203       RESUME                   0
204       LOAD_CONST               0 (None)
205       RETURN_VALUE
206"""
207
208# Extended arg followed by NOP
209code_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
217dis_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
226bug46724 = 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
234dis_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
259dis_module_expected_results = """\
260Disassembly of f:
261  4        RESUME                   0
262           LOAD_CONST               0 (None)
263           RETURN_VALUE
264
265Disassembly of g:
266  5        RESUME                   0
267           LOAD_CONST               0 (None)
268           RETURN_VALUE
269
270"""
271
272expr_str = "x + 1"
273
274dis_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
283simple_stmt_str = "x = x + 1"
284
285dis_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
296annot_stmt_str = """\
297
298x: int = 1
299y: fun(1)
300lst[fun(0)]: int = 1
301"""
302# leading newline is for a reason (tests lineno)
303
304dis_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
338compound_stmt_str = """\
339x = 0
340while 1:
341    x += 1"""
342# Trailing newline has been deliberately omitted
343
344dis_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
360dis_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
397ExceptionTable:
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
406def _fstring(a, b, c, d):
407    return f'{a} {b:4} {c!r} {d!r:4}'
408
409dis_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
429def _tryfinally(a, b):
430    try:
431        return a
432    finally:
433        b()
434
435def _tryfinallyconst(b):
436    try:
437        return 1
438    finally:
439        b()
440
441dis_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
464ExceptionTable:
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
471dis_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
495ExceptionTable:
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
502def _g(x):
503    yield x
504
505async def _ag(x):
506    yield x
507
508async def _co(x):
509    async for item in _ag(x):
510        pass
511
512def _h(y):
513    def foo(x):
514        '''funcdoc'''
515        return [x + z for z in y]
516    return foo
517
518dis_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
538dis_nested_1 = """%s
539Disassembly 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
563dis_nested_2 = """%s
564Disassembly 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
584def load_test(x, y=0):
585    a, b = x, y
586    return a, b
587
588dis_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
604def loop_test():
605    for i in [1, 2, 3] * 3:
606        load_test(i)
607
608dis_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
634def extended_arg_quick():
635    *_, _ = ...
636
637dis_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
650QUICKENING_WARMUP_DELAY = 8
651
652class DisTestBase(unittest.TestCase):
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
716class DisTests(DisTestBase):
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
1067class DisWithFileTests(DisTests):
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
1079if dis.code_info.__doc__ is None:
1080    code_info_consts = "0: None"
1081else:
1082    code_info_consts = "0: 'Formatted details of methods, functions, or code.'"
1083
1084code_info_code_info = f"""\
1085Name:              code_info
1086Filename:          (.*)
1087Argument count:    1
1088Positional-only arguments: 0
1089Kw-only arguments: 0
1090Number of locals:  1
1091Stack size:        \\d+
1092Flags:             OPTIMIZED, NEWLOCALS
1093Constants:
1094   {code_info_consts}
1095Names:
1096   0: _format_code_info
1097   1: _get_code_object
1098Variable names:
1099   0: x"""
1100
1101
1102@staticmethod
1103def 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
1108code_info_tricky = """\
1109Name:              tricky
1110Filename:          (.*)
1111Argument count:    5
1112Positional-only arguments: 2
1113Kw-only arguments: 3
1114Number of locals:  10
1115Stack size:        \\d+
1116Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
1117Constants:
1118   0: None
1119   1: <code object f at (.*), file "(.*)", line (.*)>
1120Variable 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
1131Cell 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
1140co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
1141
1142code_info_tricky_nested_f = """\
1143Filename:          (.*)
1144Argument count:    1
1145Positional-only arguments: 0
1146Kw-only arguments: 0
1147Number of locals:  1
1148Stack size:        \\d+
1149Flags:             OPTIMIZED, NEWLOCALS, NESTED
1150Constants:
1151   0: None
1152Names:
1153   0: print
1154Variable names:
1155   0: c
1156Free variables:
1157   0: [abedfxyz]
1158   1: [abedfxyz]
1159   2: [abedfxyz]
1160   3: [abedfxyz]
1161   4: [abedfxyz]
1162   5: [abedfxyz]"""
1163
1164code_info_expr_str = """\
1165Name:              <module>
1166Filename:          <disassembly>
1167Argument count:    0
1168Positional-only arguments: 0
1169Kw-only arguments: 0
1170Number of locals:  0
1171Stack size:        \\d+
1172Flags:             0x0
1173Constants:
1174   0: 1
1175Names:
1176   0: x"""
1177
1178code_info_simple_stmt_str = """\
1179Name:              <module>
1180Filename:          <disassembly>
1181Argument count:    0
1182Positional-only arguments: 0
1183Kw-only arguments: 0
1184Number of locals:  0
1185Stack size:        \\d+
1186Flags:             0x0
1187Constants:
1188   0: 1
1189   1: None
1190Names:
1191   0: x"""
1192
1193code_info_compound_stmt_str = """\
1194Name:              <module>
1195Filename:          <disassembly>
1196Argument count:    0
1197Positional-only arguments: 0
1198Kw-only arguments: 0
1199Number of locals:  0
1200Stack size:        \\d+
1201Flags:             0x0
1202Constants:
1203   0: 0
1204   1: 1
1205Names:
1206   0: x"""
1207
1208
1209async def async_def():
1210    await 1
1211    async for a in b: pass
1212    async with c as d: pass
1213
1214code_info_async_def = """\
1215Name:              async_def
1216Filename:          (.*)
1217Argument count:    0
1218Positional-only arguments: 0
1219Kw-only arguments: 0
1220Number of locals:  2
1221Stack size:        \\d+
1222Flags:             OPTIMIZED, NEWLOCALS, COROUTINE
1223Constants:
1224   0: None
1225   1: 1
1226Names:
1227   0: b
1228   1: c
1229Variable names:
1230   0: a
1231   1: d"""
1232
1233class CodeInfoTests(unittest.TestCase):
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
1268def 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
1277def 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
1307expected_outer_line = 1
1308_line_offset = outer.__code__.co_firstlineno - 1
1309code_object_f = outer.__code__.co_consts[3]
1310expected_f_line = code_object_f.co_firstlineno - _line_offset
1311code_object_inner = code_object_f.co_consts[3]
1312expected_inner_line = code_object_inner.co_firstlineno - _line_offset
1313expected_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
1320def _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
1325def _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
1342Instruction = dis.Instruction
1343expected_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
1369expected_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
1395expected_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
1412expected_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
1539def simple(): pass
1540expected_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
1547class InstructionTestCase(BytecodeTestCase):
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
1554class InstructionTests(InstructionTestCase):
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
1664class BytecodeTests(InstructionTestCase, DisTestBase):
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
1726class TestBytecodeTestCase(BytecodeTestCase):
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
1744class TestFinderMethods(unittest.TestCase):
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
1787class TestDisTraceback(DisTestBase):
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
1820class TestDisTracebackWithFile(TestDisTraceback):
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
1829if __name__ == "__main__":
1830    unittest.main()
1831