python (3.12.0)

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