test_dis.py 77 KB

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