1# Minimal tests for dis module
2
3from test.support import captured_stdout
4from test.bytecode_helper import BytecodeTestCase
5import difflib
6import unittest
7import sys
8import dis
9import io
10import re
11import types
12import contextlib
13
14def get_tb():
15    def _error():
16        try:
17            1 / 0
18        except Exception as e:
19            tb = e.__traceback__
20        return tb
21
22    tb = _error()
23    while tb.tb_next:
24        tb = tb.tb_next
25    return tb
26
27TRACEBACK_CODE = get_tb().tb_frame.f_code
28
29class _C:
30    def __init__(self, x):
31        self.x = x == 1
32
33    @staticmethod
34    def sm(x):
35        x = x == 1
36
37    @classmethod
38    def cm(cls, x):
39        cls.x = x == 1
40
41dis_c_instance_method = """\
42%3d           0 LOAD_FAST                1 (x)
43              2 LOAD_CONST               1 (1)
44              4 COMPARE_OP               2 (==)
45              6 LOAD_FAST                0 (self)
46              8 STORE_ATTR               0 (x)
47             10 LOAD_CONST               0 (None)
48             12 RETURN_VALUE
49""" % (_C.__init__.__code__.co_firstlineno + 1,)
50
51dis_c_instance_method_bytes = """\
52          0 LOAD_FAST                1 (1)
53          2 LOAD_CONST               1 (1)
54          4 COMPARE_OP               2 (==)
55          6 LOAD_FAST                0 (0)
56          8 STORE_ATTR               0 (0)
57         10 LOAD_CONST               0 (0)
58         12 RETURN_VALUE
59"""
60
61dis_c_class_method = """\
62%3d           0 LOAD_FAST                1 (x)
63              2 LOAD_CONST               1 (1)
64              4 COMPARE_OP               2 (==)
65              6 LOAD_FAST                0 (cls)
66              8 STORE_ATTR               0 (x)
67             10 LOAD_CONST               0 (None)
68             12 RETURN_VALUE
69""" % (_C.cm.__code__.co_firstlineno + 2,)
70
71dis_c_static_method = """\
72%3d           0 LOAD_FAST                0 (x)
73              2 LOAD_CONST               1 (1)
74              4 COMPARE_OP               2 (==)
75              6 STORE_FAST               0 (x)
76              8 LOAD_CONST               0 (None)
77             10 RETURN_VALUE
78""" % (_C.sm.__code__.co_firstlineno + 2,)
79
80# Class disassembling info has an extra newline at end.
81dis_c = """\
82Disassembly of %s:
83%s
84Disassembly of %s:
85%s
86Disassembly of %s:
87%s
88""" % (_C.__init__.__name__, dis_c_instance_method,
89       _C.cm.__name__, dis_c_class_method,
90       _C.sm.__name__, dis_c_static_method)
91
92def _f(a):
93    print(a)
94    return 1
95
96dis_f = """\
97%3d           0 LOAD_GLOBAL              0 (print)
98              2 LOAD_FAST                0 (a)
99              4 CALL_FUNCTION            1
100              6 POP_TOP
101
102%3d           8 LOAD_CONST               1 (1)
103             10 RETURN_VALUE
104""" % (_f.__code__.co_firstlineno + 1,
105       _f.__code__.co_firstlineno + 2)
106
107
108dis_f_co_code = """\
109          0 LOAD_GLOBAL              0 (0)
110          2 LOAD_FAST                0 (0)
111          4 CALL_FUNCTION            1
112          6 POP_TOP
113          8 LOAD_CONST               1 (1)
114         10 RETURN_VALUE
115"""
116
117
118def bug708901():
119    for res in range(1,
120                     10):
121        pass
122
123dis_bug708901 = """\
124%3d           0 SETUP_LOOP              18 (to 20)
125              2 LOAD_GLOBAL              0 (range)
126              4 LOAD_CONST               1 (1)
127
128%3d           6 LOAD_CONST               2 (10)
129              8 CALL_FUNCTION            2
130             10 GET_ITER
131        >>   12 FOR_ITER                 4 (to 18)
132             14 STORE_FAST               0 (res)
133
134%3d          16 JUMP_ABSOLUTE           12
135        >>   18 POP_BLOCK
136        >>   20 LOAD_CONST               0 (None)
137             22 RETURN_VALUE
138""" % (bug708901.__code__.co_firstlineno + 1,
139       bug708901.__code__.co_firstlineno + 2,
140       bug708901.__code__.co_firstlineno + 3)
141
142
143def bug1333982(x=[]):
144    assert 0, ([s for s in x] +
145              1)
146    pass
147
148dis_bug1333982 = """\
149%3d           0 LOAD_CONST               1 (0)
150              2 POP_JUMP_IF_TRUE        26
151              4 LOAD_GLOBAL              0 (AssertionError)
152              6 LOAD_CONST               2 (<code object <listcomp> at 0x..., file "%s", line %d>)
153              8 LOAD_CONST               3 ('bug1333982.<locals>.<listcomp>')
154             10 MAKE_FUNCTION            0
155             12 LOAD_FAST                0 (x)
156             14 GET_ITER
157             16 CALL_FUNCTION            1
158
159%3d          18 LOAD_CONST               4 (1)
160             20 BINARY_ADD
161             22 CALL_FUNCTION            1
162             24 RAISE_VARARGS            1
163
164%3d     >>   26 LOAD_CONST               0 (None)
165             28 RETURN_VALUE
166""" % (bug1333982.__code__.co_firstlineno + 1,
167       __file__,
168       bug1333982.__code__.co_firstlineno + 1,
169       bug1333982.__code__.co_firstlineno + 2,
170       bug1333982.__code__.co_firstlineno + 3)
171
172_BIG_LINENO_FORMAT = """\
173%3d           0 LOAD_GLOBAL              0 (spam)
174              2 POP_TOP
175              4 LOAD_CONST               0 (None)
176              6 RETURN_VALUE
177"""
178
179dis_module_expected_results = """\
180Disassembly of f:
181  4           0 LOAD_CONST               0 (None)
182              2 RETURN_VALUE
183
184Disassembly of g:
185  5           0 LOAD_CONST               0 (None)
186              2 RETURN_VALUE
187
188"""
189
190expr_str = "x + 1"
191
192dis_expr_str = """\
193  1           0 LOAD_NAME                0 (x)
194              2 LOAD_CONST               0 (1)
195              4 BINARY_ADD
196              6 RETURN_VALUE
197"""
198
199simple_stmt_str = "x = x + 1"
200
201dis_simple_stmt_str = """\
202  1           0 LOAD_NAME                0 (x)
203              2 LOAD_CONST               0 (1)
204              4 BINARY_ADD
205              6 STORE_NAME               0 (x)
206              8 LOAD_CONST               1 (None)
207             10 RETURN_VALUE
208"""
209
210annot_stmt_str = """\
211
212x: int = 1
213y: fun(1)
214lst[fun(0)]: int = 1
215"""
216# leading newline is for a reason (tests lineno)
217
218dis_annot_stmt_str = """\
219  2           0 SETUP_ANNOTATIONS
220              2 LOAD_CONST               0 (1)
221              4 STORE_NAME               0 (x)
222              6 LOAD_NAME                1 (int)
223              8 STORE_ANNOTATION         0 (x)
224
225  3          10 LOAD_NAME                2 (fun)
226             12 LOAD_CONST               0 (1)
227             14 CALL_FUNCTION            1
228             16 STORE_ANNOTATION         3 (y)
229
230  4          18 LOAD_CONST               0 (1)
231             20 LOAD_NAME                4 (lst)
232             22 LOAD_NAME                2 (fun)
233             24 LOAD_CONST               1 (0)
234             26 CALL_FUNCTION            1
235             28 STORE_SUBSCR
236             30 LOAD_NAME                1 (int)
237             32 POP_TOP
238             34 LOAD_CONST               2 (None)
239             36 RETURN_VALUE
240"""
241
242compound_stmt_str = """\
243x = 0
244while 1:
245    x += 1"""
246# Trailing newline has been deliberately omitted
247
248dis_compound_stmt_str = """\
249  1           0 LOAD_CONST               0 (0)
250              2 STORE_NAME               0 (x)
251
252  2           4 SETUP_LOOP              12 (to 18)
253
254  3     >>    6 LOAD_NAME                0 (x)
255              8 LOAD_CONST               1 (1)
256             10 INPLACE_ADD
257             12 STORE_NAME               0 (x)
258             14 JUMP_ABSOLUTE            6
259             16 POP_BLOCK
260        >>   18 LOAD_CONST               2 (None)
261             20 RETURN_VALUE
262"""
263
264dis_traceback = """\
265%3d           0 SETUP_EXCEPT            12 (to 14)
266
267%3d           2 LOAD_CONST               1 (1)
268              4 LOAD_CONST               2 (0)
269    -->       6 BINARY_TRUE_DIVIDE
270              8 POP_TOP
271             10 POP_BLOCK
272             12 JUMP_FORWARD            40 (to 54)
273
274%3d     >>   14 DUP_TOP
275             16 LOAD_GLOBAL              0 (Exception)
276             18 COMPARE_OP              10 (exception match)
277             20 POP_JUMP_IF_FALSE       52
278             22 POP_TOP
279             24 STORE_FAST               0 (e)
280             26 POP_TOP
281             28 SETUP_FINALLY           12 (to 42)
282
283%3d          30 LOAD_FAST                0 (e)
284             32 LOAD_ATTR                1 (__traceback__)
285             34 STORE_FAST               1 (tb)
286             36 POP_BLOCK
287             38 POP_EXCEPT
288             40 LOAD_CONST               0 (None)
289        >>   42 LOAD_CONST               0 (None)
290             44 STORE_FAST               0 (e)
291             46 DELETE_FAST              0 (e)
292             48 END_FINALLY
293             50 JUMP_FORWARD             2 (to 54)
294        >>   52 END_FINALLY
295
296%3d     >>   54 LOAD_FAST                1 (tb)
297             56 RETURN_VALUE
298""" % (TRACEBACK_CODE.co_firstlineno + 1,
299       TRACEBACK_CODE.co_firstlineno + 2,
300       TRACEBACK_CODE.co_firstlineno + 3,
301       TRACEBACK_CODE.co_firstlineno + 4,
302       TRACEBACK_CODE.co_firstlineno + 5)
303
304def _fstring(a, b, c, d):
305    return f'{a} {b:4} {c!r} {d!r:4}'
306
307dis_fstring = """\
308%3d           0 LOAD_FAST                0 (a)
309              2 FORMAT_VALUE             0
310              4 LOAD_CONST               1 (' ')
311              6 LOAD_FAST                1 (b)
312              8 LOAD_CONST               2 ('4')
313             10 FORMAT_VALUE             4 (with format)
314             12 LOAD_CONST               1 (' ')
315             14 LOAD_FAST                2 (c)
316             16 FORMAT_VALUE             2 (repr)
317             18 LOAD_CONST               1 (' ')
318             20 LOAD_FAST                3 (d)
319             22 LOAD_CONST               2 ('4')
320             24 FORMAT_VALUE             6 (repr, with format)
321             26 BUILD_STRING             7
322             28 RETURN_VALUE
323""" % (_fstring.__code__.co_firstlineno + 1,)
324
325def _g(x):
326    yield x
327
328class DisTests(unittest.TestCase):
329
330    def get_disassembly(self, func, lasti=-1, wrapper=True):
331        # We want to test the default printing behaviour, not the file arg
332        output = io.StringIO()
333        with contextlib.redirect_stdout(output):
334            if wrapper:
335                dis.dis(func)
336            else:
337                dis.disassemble(func, lasti)
338        return output.getvalue()
339
340    def get_disassemble_as_string(self, func, lasti=-1):
341        return self.get_disassembly(func, lasti, False)
342
343    def strip_addresses(self, text):
344        return re.sub(r'\b0x[0-9A-Fa-f]+\b', '0x...', text)
345
346    def do_disassembly_test(self, func, expected):
347        got = self.get_disassembly(func)
348        if got != expected:
349            got = self.strip_addresses(got)
350        self.assertEqual(got, expected)
351
352    def test_opmap(self):
353        self.assertEqual(dis.opmap["NOP"], 9)
354        self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst)
355        self.assertIn(dis.opmap["STORE_NAME"], dis.hasname)
356
357    def test_opname(self):
358        self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST")
359
360    def test_boundaries(self):
361        self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG)
362        self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT)
363
364    def test_dis(self):
365        self.do_disassembly_test(_f, dis_f)
366
367    def test_bug_708901(self):
368        self.do_disassembly_test(bug708901, dis_bug708901)
369
370    def test_bug_1333982(self):
371        # This one is checking bytecodes generated for an `assert` statement,
372        # so fails if the tests are run with -O.  Skip this test then.
373        if not __debug__:
374            self.skipTest('need asserts, run without -O')
375
376        self.do_disassembly_test(bug1333982, dis_bug1333982)
377
378    def test_big_linenos(self):
379        def func(count):
380            namespace = {}
381            func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"])
382            exec(func, namespace)
383            return namespace['foo']
384
385        # Test all small ranges
386        for i in range(1, 300):
387            expected = _BIG_LINENO_FORMAT % (i + 2)
388            self.do_disassembly_test(func(i), expected)
389
390        # Test some larger ranges too
391        for i in range(300, 5000, 10):
392            expected = _BIG_LINENO_FORMAT % (i + 2)
393            self.do_disassembly_test(func(i), expected)
394
395        from test import dis_module
396        self.do_disassembly_test(dis_module, dis_module_expected_results)
397
398    def test_disassemble_str(self):
399        self.do_disassembly_test(expr_str, dis_expr_str)
400        self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str)
401        self.do_disassembly_test(annot_stmt_str, dis_annot_stmt_str)
402        self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str)
403
404    def test_disassemble_bytes(self):
405        self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
406
407    def test_disassemble_class(self):
408        self.do_disassembly_test(_C, dis_c)
409
410    def test_disassemble_instance_method(self):
411        self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
412
413    def test_disassemble_instance_method_bytes(self):
414        method_bytecode = _C(1).__init__.__code__.co_code
415        self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
416
417    def test_disassemble_static_method(self):
418        self.do_disassembly_test(_C.sm, dis_c_static_method)
419
420    def test_disassemble_class_method(self):
421        self.do_disassembly_test(_C.cm, dis_c_class_method)
422
423    def test_disassemble_generator(self):
424        gen_func_disas = self.get_disassembly(_g)  # Disassemble generator function
425        gen_disas = self.get_disassembly(_g(1))  # Disassemble generator itself
426        self.assertEqual(gen_disas, gen_func_disas)
427
428    def test_disassemble_fstring(self):
429        self.do_disassembly_test(_fstring, dis_fstring)
430
431    def test_dis_none(self):
432        try:
433            del sys.last_traceback
434        except AttributeError:
435            pass
436        self.assertRaises(RuntimeError, dis.dis, None)
437
438    def test_dis_traceback(self):
439        try:
440            del sys.last_traceback
441        except AttributeError:
442            pass
443
444        try:
445            1/0
446        except Exception as e:
447            tb = e.__traceback__
448            sys.last_traceback = tb
449
450        tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti)
451        self.do_disassembly_test(None, tb_dis)
452
453    def test_dis_object(self):
454        self.assertRaises(TypeError, dis.dis, object())
455
456class DisWithFileTests(DisTests):
457
458    # Run the tests again, using the file arg instead of print
459    def get_disassembly(self, func, lasti=-1, wrapper=True):
460        output = io.StringIO()
461        if wrapper:
462            dis.dis(func, file=output)
463        else:
464            dis.disassemble(func, lasti, file=output)
465        return output.getvalue()
466
467
468
469code_info_code_info = """\
470Name:              code_info
471Filename:          (.*)
472Argument count:    1
473Kw-only arguments: 0
474Number of locals:  1
475Stack size:        3
476Flags:             OPTIMIZED, NEWLOCALS, NOFREE
477Constants:
478   0: %r
479Names:
480   0: _format_code_info
481   1: _get_code_object
482Variable names:
483   0: x""" % (('Formatted details of methods, functions, or code.',)
484              if sys.flags.optimize < 2 else (None,))
485
486@staticmethod
487def tricky(x, y, z=True, *args, c, d, e=[], **kwds):
488    def f(c=c):
489        print(x, y, z, c, d, e, f)
490    yield x, y, z, c, d, e, f
491
492code_info_tricky = """\
493Name:              tricky
494Filename:          (.*)
495Argument count:    3
496Kw-only arguments: 3
497Number of locals:  8
498Stack size:        7
499Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
500Constants:
501   0: None
502   1: <code object f at (.*), file "(.*)", line (.*)>
503   2: 'tricky.<locals>.f'
504Variable names:
505   0: x
506   1: y
507   2: z
508   3: c
509   4: d
510   5: e
511   6: args
512   7: kwds
513Cell variables:
514   0: [edfxyz]
515   1: [edfxyz]
516   2: [edfxyz]
517   3: [edfxyz]
518   4: [edfxyz]
519   5: [edfxyz]"""
520# NOTE: the order of the cell variables above depends on dictionary order!
521
522co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
523
524code_info_tricky_nested_f = """\
525Name:              f
526Filename:          (.*)
527Argument count:    1
528Kw-only arguments: 0
529Number of locals:  1
530Stack size:        8
531Flags:             OPTIMIZED, NEWLOCALS, NESTED
532Constants:
533   0: None
534Names:
535   0: print
536Variable names:
537   0: c
538Free variables:
539   0: [edfxyz]
540   1: [edfxyz]
541   2: [edfxyz]
542   3: [edfxyz]
543   4: [edfxyz]
544   5: [edfxyz]"""
545
546code_info_expr_str = """\
547Name:              <module>
548Filename:          <disassembly>
549Argument count:    0
550Kw-only arguments: 0
551Number of locals:  0
552Stack size:        2
553Flags:             NOFREE
554Constants:
555   0: 1
556Names:
557   0: x"""
558
559code_info_simple_stmt_str = """\
560Name:              <module>
561Filename:          <disassembly>
562Argument count:    0
563Kw-only arguments: 0
564Number of locals:  0
565Stack size:        2
566Flags:             NOFREE
567Constants:
568   0: 1
569   1: None
570Names:
571   0: x"""
572
573code_info_compound_stmt_str = """\
574Name:              <module>
575Filename:          <disassembly>
576Argument count:    0
577Kw-only arguments: 0
578Number of locals:  0
579Stack size:        2
580Flags:             NOFREE
581Constants:
582   0: 0
583   1: 1
584   2: None
585Names:
586   0: x"""
587
588
589async def async_def():
590    await 1
591    async for a in b: pass
592    async with c as d: pass
593
594code_info_async_def = """\
595Name:              async_def
596Filename:          (.*)
597Argument count:    0
598Kw-only arguments: 0
599Number of locals:  2
600Stack size:        17
601Flags:             OPTIMIZED, NEWLOCALS, NOFREE, COROUTINE
602Constants:
603   0: None
604   1: 1"""
605
606class CodeInfoTests(unittest.TestCase):
607    test_pairs = [
608      (dis.code_info, code_info_code_info),
609      (tricky, code_info_tricky),
610      (co_tricky_nested_f, code_info_tricky_nested_f),
611      (expr_str, code_info_expr_str),
612      (simple_stmt_str, code_info_simple_stmt_str),
613      (compound_stmt_str, code_info_compound_stmt_str),
614      (async_def, code_info_async_def)
615    ]
616
617    def test_code_info(self):
618        self.maxDiff = 1000
619        for x, expected in self.test_pairs:
620            self.assertRegex(dis.code_info(x), expected)
621
622    def test_show_code(self):
623        self.maxDiff = 1000
624        for x, expected in self.test_pairs:
625            with captured_stdout() as output:
626                dis.show_code(x)
627            self.assertRegex(output.getvalue(), expected+"\n")
628            output = io.StringIO()
629            dis.show_code(x, file=output)
630            self.assertRegex(output.getvalue(), expected)
631
632    def test_code_info_object(self):
633        self.assertRaises(TypeError, dis.code_info, object())
634
635    def test_pretty_flags_no_flags(self):
636        self.assertEqual(dis.pretty_flags(0), '0x0')
637
638
639# Fodder for instruction introspection tests
640#   Editing any of these may require recalculating the expected output
641def outer(a=1, b=2):
642    def f(c=3, d=4):
643        def inner(e=5, f=6):
644            print(a, b, c, d, e, f)
645        print(a, b, c, d)
646        return inner
647    print(a, b, '', 1, [], {}, "Hello world!")
648    return f
649
650def jumpy():
651    # This won't actually run (but that's OK, we only disassemble it)
652    for i in range(10):
653        print(i)
654        if i < 4:
655            continue
656        if i > 6:
657            break
658    else:
659        print("I can haz else clause?")
660    while i:
661        print(i)
662        i -= 1
663        if i > 6:
664            continue
665        if i < 4:
666            break
667    else:
668        print("Who let lolcatz into this test suite?")
669    try:
670        1 / 0
671    except ZeroDivisionError:
672        print("Here we go, here we go, here we go...")
673    else:
674        with i as dodgy:
675            print("Never reach this")
676    finally:
677        print("OK, now we're done")
678
679# End fodder for opinfo generation tests
680expected_outer_line = 1
681_line_offset = outer.__code__.co_firstlineno - 1
682code_object_f = outer.__code__.co_consts[3]
683expected_f_line = code_object_f.co_firstlineno - _line_offset
684code_object_inner = code_object_f.co_consts[3]
685expected_inner_line = code_object_inner.co_firstlineno - _line_offset
686expected_jumpy_line = 1
687
688# The following lines are useful to regenerate the expected results after
689# either the fodder is modified or the bytecode generation changes
690# After regeneration, update the references to code_object_f and
691# code_object_inner before rerunning the tests
692
693#_instructions = dis.get_instructions(outer, first_line=expected_outer_line)
694#print('expected_opinfo_outer = [\n  ',
695      #',\n  '.join(map(str, _instructions)), ',\n]', sep='')
696#_instructions = dis.get_instructions(outer(), first_line=expected_f_line)
697#print('expected_opinfo_f = [\n  ',
698      #',\n  '.join(map(str, _instructions)), ',\n]', sep='')
699#_instructions = dis.get_instructions(outer()(), first_line=expected_inner_line)
700#print('expected_opinfo_inner = [\n  ',
701      #',\n  '.join(map(str, _instructions)), ',\n]', sep='')
702#_instructions = dis.get_instructions(jumpy, first_line=expected_jumpy_line)
703#print('expected_opinfo_jumpy = [\n  ',
704      #',\n  '.join(map(str, _instructions)), ',\n]', sep='')
705
706
707Instruction = dis.Instruction
708expected_opinfo_outer = [
709  Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False),
710  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
711  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
712  Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False),
713  Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False),
714  Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=10, starts_line=None, is_jump_target=False),
715  Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=12, starts_line=None, is_jump_target=False),
716  Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False),
717  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=16, starts_line=7, is_jump_target=False),
718  Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False),
719  Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False),
720  Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False),
721  Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False),
722  Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False),
723  Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False),
724  Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False),
725  Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=32, starts_line=None, is_jump_target=False),
726  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False),
727  Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=36, starts_line=8, is_jump_target=False),
728  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False),
729]
730
731expected_opinfo_f = [
732  Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False),
733  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
734  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
735  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
736  Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
737  Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False),
738  Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False),
739  Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=14, starts_line=None, is_jump_target=False),
740  Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=16, starts_line=None, is_jump_target=False),
741  Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=18, starts_line=None, is_jump_target=False),
742  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=5, is_jump_target=False),
743  Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False),
744  Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
745  Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False),
746  Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False),
747  Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=30, starts_line=None, is_jump_target=False),
748  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False),
749  Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=34, starts_line=6, is_jump_target=False),
750  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False),
751]
752
753expected_opinfo_inner = [
754  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False),
755  Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
756  Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
757  Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
758  Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
759  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False),
760  Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False),
761  Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False),
762  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False),
763  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False),
764  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
765]
766
767expected_opinfo_jumpy = [
768  Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=54, argrepr='to 54', offset=0, starts_line=3, is_jump_target=False),
769  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=2, starts_line=None, is_jump_target=False),
770  Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=4, starts_line=None, is_jump_target=False),
771  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=6, starts_line=None, is_jump_target=False),
772  Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False),
773  Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=44, argrepr='to 44', offset=10, starts_line=None, is_jump_target=True),
774  Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=12, starts_line=None, is_jump_target=False),
775  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=14, starts_line=4, is_jump_target=False),
776  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False),
777  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=18, starts_line=None, is_jump_target=False),
778  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
779  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=5, is_jump_target=False),
780  Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=24, starts_line=None, is_jump_target=False),
781  Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=26, starts_line=None, is_jump_target=False),
782  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=32, argrepr='', offset=28, starts_line=None, is_jump_target=False),
783  Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=30, starts_line=6, is_jump_target=False),
784  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=32, starts_line=7, is_jump_target=True),
785  Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=34, starts_line=None, is_jump_target=False),
786  Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=36, starts_line=None, is_jump_target=False),
787  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=10, argval=10, argrepr='', offset=38, starts_line=None, is_jump_target=False),
788  Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=40, starts_line=8, is_jump_target=False),
789  Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=42, starts_line=None, is_jump_target=False),
790  Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=True),
791  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=46, starts_line=10, is_jump_target=False),
792  Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=48, starts_line=None, is_jump_target=False),
793  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False),
794  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False),
795  Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=108, argrepr='to 108', offset=54, starts_line=11, is_jump_target=True),
796  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=True),
797  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=98, argval=98, argrepr='', offset=58, starts_line=None, is_jump_target=False),
798  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=60, starts_line=12, is_jump_target=False),
799  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=None, is_jump_target=False),
800  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=64, starts_line=None, is_jump_target=False),
801  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False),
802  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=13, is_jump_target=False),
803  Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=70, starts_line=None, is_jump_target=False),
804  Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=72, starts_line=None, is_jump_target=False),
805  Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False),
806  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=76, starts_line=14, is_jump_target=False),
807  Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=78, starts_line=None, is_jump_target=False),
808  Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=80, starts_line=None, is_jump_target=False),
809  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=86, argval=86, argrepr='', offset=82, starts_line=None, is_jump_target=False),
810  Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=84, starts_line=15, is_jump_target=False),
811  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=86, starts_line=16, is_jump_target=True),
812  Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=88, starts_line=None, is_jump_target=False),
813  Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=90, starts_line=None, is_jump_target=False),
814  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=56, argval=56, argrepr='', offset=92, starts_line=None, is_jump_target=False),
815  Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=94, starts_line=17, is_jump_target=False),
816  Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=96, starts_line=None, is_jump_target=False),
817  Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=98, starts_line=None, is_jump_target=True),
818  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=100, starts_line=19, is_jump_target=False),
819  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=102, starts_line=None, is_jump_target=False),
820  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=104, starts_line=None, is_jump_target=False),
821  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, starts_line=None, is_jump_target=False),
822  Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True),
823  Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=124, argrepr='to 124', offset=110, starts_line=None, is_jump_target=False),
824  Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=112, starts_line=21, is_jump_target=False),
825  Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=114, starts_line=None, is_jump_target=False),
826  Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False),
827  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=118, starts_line=None, is_jump_target=False),
828  Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=120, starts_line=None, is_jump_target=False),
829  Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=152, argrepr='to 152', offset=122, starts_line=None, is_jump_target=False),
830  Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=124, starts_line=22, is_jump_target=True),
831  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=126, starts_line=None, is_jump_target=False),
832  Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=128, starts_line=None, is_jump_target=False),
833  Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=150, argval=150, argrepr='', offset=130, starts_line=None, is_jump_target=False),
834  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False),
835  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False),
836  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False),
837  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=138, starts_line=23, is_jump_target=False),
838  Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=140, starts_line=None, is_jump_target=False),
839  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=142, starts_line=None, is_jump_target=False),
840  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False),
841  Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False),
842  Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=176, argrepr='to 176', offset=148, starts_line=None, is_jump_target=False),
843  Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=150, starts_line=None, is_jump_target=True),
844  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=25, is_jump_target=True),
845  Instruction(opname='SETUP_WITH', opcode=143, arg=14, argval=170, argrepr='to 170', offset=154, starts_line=None, is_jump_target=False),
846  Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=156, starts_line=None, is_jump_target=False),
847  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=158, starts_line=26, is_jump_target=False),
848  Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=160, starts_line=None, is_jump_target=False),
849  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=162, starts_line=None, is_jump_target=False),
850  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False),
851  Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
852  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=168, starts_line=None, is_jump_target=False),
853  Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True),
854  Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
855  Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False),
856  Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True),
857  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=178, starts_line=None, is_jump_target=False),
858  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=180, starts_line=28, is_jump_target=True),
859  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=182, starts_line=None, is_jump_target=False),
860  Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=184, starts_line=None, is_jump_target=False),
861  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
862  Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False),
863  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=190, starts_line=None, is_jump_target=False),
864  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False),
865]
866
867# One last piece of inspect fodder to check the default line number handling
868def simple(): pass
869expected_opinfo_simple = [
870  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False),
871  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=2, starts_line=None, is_jump_target=False)
872]
873
874
875class InstructionTests(BytecodeTestCase):
876
877    def test_default_first_line(self):
878        actual = dis.get_instructions(simple)
879        self.assertEqual(list(actual), expected_opinfo_simple)
880
881    def test_first_line_set_to_None(self):
882        actual = dis.get_instructions(simple, first_line=None)
883        self.assertEqual(list(actual), expected_opinfo_simple)
884
885    def test_outer(self):
886        actual = dis.get_instructions(outer, first_line=expected_outer_line)
887        self.assertEqual(list(actual), expected_opinfo_outer)
888
889    def test_nested(self):
890        with captured_stdout():
891            f = outer()
892        actual = dis.get_instructions(f, first_line=expected_f_line)
893        self.assertEqual(list(actual), expected_opinfo_f)
894
895    def test_doubly_nested(self):
896        with captured_stdout():
897            inner = outer()()
898        actual = dis.get_instructions(inner, first_line=expected_inner_line)
899        self.assertEqual(list(actual), expected_opinfo_inner)
900
901    def test_jumpy(self):
902        actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line)
903        self.assertEqual(list(actual), expected_opinfo_jumpy)
904
905# get_instructions has its own tests above, so can rely on it to validate
906# the object oriented API
907class BytecodeTests(unittest.TestCase):
908    def test_instantiation(self):
909        # Test with function, method, code string and code object
910        for obj in [_f, _C(1).__init__, "a=1", _f.__code__]:
911            with self.subTest(obj=obj):
912                b = dis.Bytecode(obj)
913                self.assertIsInstance(b.codeobj, types.CodeType)
914
915        self.assertRaises(TypeError, dis.Bytecode, object())
916
917    def test_iteration(self):
918        for obj in [_f, _C(1).__init__, "a=1", _f.__code__]:
919            with self.subTest(obj=obj):
920                via_object = list(dis.Bytecode(obj))
921                via_generator = list(dis.get_instructions(obj))
922                self.assertEqual(via_object, via_generator)
923
924    def test_explicit_first_line(self):
925        actual = dis.Bytecode(outer, first_line=expected_outer_line)
926        self.assertEqual(list(actual), expected_opinfo_outer)
927
928    def test_source_line_in_disassembly(self):
929        # Use the line in the source code
930        actual = dis.Bytecode(simple).dis()[:3]
931        expected = "{:>3}".format(simple.__code__.co_firstlineno)
932        self.assertEqual(actual, expected)
933        # Use an explicit first line number
934        actual = dis.Bytecode(simple, first_line=350).dis()[:3]
935        self.assertEqual(actual, "350")
936
937    def test_info(self):
938        self.maxDiff = 1000
939        for x, expected in CodeInfoTests.test_pairs:
940            b = dis.Bytecode(x)
941            self.assertRegex(b.info(), expected)
942
943    def test_disassembled(self):
944        actual = dis.Bytecode(_f).dis()
945        self.assertEqual(actual, dis_f)
946
947    def test_from_traceback(self):
948        tb = get_tb()
949        b = dis.Bytecode.from_traceback(tb)
950        while tb.tb_next: tb = tb.tb_next
951
952        self.assertEqual(b.current_offset, tb.tb_lasti)
953
954    def test_from_traceback_dis(self):
955        tb = get_tb()
956        b = dis.Bytecode.from_traceback(tb)
957        self.assertEqual(b.dis(), dis_traceback)
958
959if __name__ == "__main__":
960    unittest.main()
961