Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 1 | # Minimal tests for dis module |
| 2 | |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 3 | from test.support import run_unittest, captured_stdout |
Guido van Rossum | d8faa36 | 2007-04-27 19:54:29 +0000 | [diff] [blame] | 4 | import unittest |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 5 | import sys |
| 6 | import dis |
Guido van Rossum | 34d1928 | 2007-08-09 01:03:29 +0000 | [diff] [blame] | 7 | import io |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 8 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 9 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 10 | def _f(a): |
Guido van Rossum | be19ed7 | 2007-02-09 05:37:30 +0000 | [diff] [blame] | 11 | print(a) |
Tim Peters | eabafeb | 2003-03-07 15:55:36 +0000 | [diff] [blame] | 12 | return 1 |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 13 | |
| 14 | dis_f = """\ |
Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 15 | %-4d 0 LOAD_GLOBAL 0 (print) |
| 16 | 3 LOAD_FAST 0 (a) |
| 17 | 6 CALL_FUNCTION 1 |
| 18 | 9 POP_TOP |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 19 | |
Georg Brandl | 88fc664 | 2007-02-09 21:28:07 +0000 | [diff] [blame] | 20 | %-4d 10 LOAD_CONST 1 (1) |
| 21 | 13 RETURN_VALUE |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 22 | """ % (_f.__code__.co_firstlineno + 1, |
| 23 | _f.__code__.co_firstlineno + 2) |
Michael W. Hudson | 26848a3 | 2003-04-29 17:07:36 +0000 | [diff] [blame] | 24 | |
| 25 | |
| 26 | def bug708901(): |
| 27 | for res in range(1, |
| 28 | 10): |
| 29 | pass |
| 30 | |
| 31 | dis_bug708901 = """\ |
| 32 | %-4d 0 SETUP_LOOP 23 (to 26) |
| 33 | 3 LOAD_GLOBAL 0 (range) |
| 34 | 6 LOAD_CONST 1 (1) |
| 35 | |
| 36 | %-4d 9 LOAD_CONST 2 (10) |
| 37 | 12 CALL_FUNCTION 2 |
| 38 | 15 GET_ITER |
| 39 | >> 16 FOR_ITER 6 (to 25) |
| 40 | 19 STORE_FAST 0 (res) |
| 41 | |
| 42 | %-4d 22 JUMP_ABSOLUTE 16 |
| 43 | >> 25 POP_BLOCK |
| 44 | >> 26 LOAD_CONST 0 (None) |
| 45 | 29 RETURN_VALUE |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 46 | """ % (bug708901.__code__.co_firstlineno + 1, |
| 47 | bug708901.__code__.co_firstlineno + 2, |
| 48 | bug708901.__code__.co_firstlineno + 3) |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 49 | |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 50 | |
| 51 | def bug1333982(x=[]): |
| 52 | assert 0, ([s for s in x] + |
| 53 | 1) |
| 54 | pass |
| 55 | |
| 56 | dis_bug1333982 = """\ |
| 57 | %-4d 0 LOAD_CONST 1 (0) |
Antoine Pitrou | f289ae6 | 2008-12-18 11:06:25 +0000 | [diff] [blame] | 58 | 3 JUMP_IF_TRUE 33 (to 39) |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 59 | 6 POP_TOP |
| 60 | 7 LOAD_GLOBAL 0 (AssertionError) |
| 61 | 10 BUILD_LIST 0 |
Antoine Pitrou | f289ae6 | 2008-12-18 11:06:25 +0000 | [diff] [blame] | 62 | 13 LOAD_FAST 0 (x) |
| 63 | 16 GET_ITER |
| 64 | >> 17 FOR_ITER 12 (to 32) |
| 65 | 20 STORE_FAST 1 (s) |
| 66 | 23 LOAD_FAST 1 (s) |
| 67 | 26 LIST_APPEND 2 |
| 68 | 29 JUMP_ABSOLUTE 17 |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 69 | |
Antoine Pitrou | f289ae6 | 2008-12-18 11:06:25 +0000 | [diff] [blame] | 70 | %-4d >> 32 LOAD_CONST 2 (1) |
| 71 | 35 BINARY_ADD |
| 72 | 36 RAISE_VARARGS 2 |
| 73 | >> 39 POP_TOP |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 74 | |
Antoine Pitrou | f289ae6 | 2008-12-18 11:06:25 +0000 | [diff] [blame] | 75 | %-4d 40 LOAD_CONST 0 (None) |
| 76 | 43 RETURN_VALUE |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 77 | """ % (bug1333982.__code__.co_firstlineno + 1, |
| 78 | bug1333982.__code__.co_firstlineno + 2, |
| 79 | bug1333982.__code__.co_firstlineno + 3) |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 80 | |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 81 | _BIG_LINENO_FORMAT = """\ |
| 82 | %3d 0 LOAD_GLOBAL 0 (spam) |
| 83 | 3 POP_TOP |
| 84 | 4 LOAD_CONST 0 (None) |
| 85 | 7 RETURN_VALUE |
| 86 | """ |
| 87 | |
Guido van Rossum | e7ba495 | 2007-06-06 23:52:48 +0000 | [diff] [blame] | 88 | dis_module_expected_results = """\ |
| 89 | Disassembly of f: |
| 90 | 4 0 LOAD_CONST 0 (None) |
| 91 | 3 RETURN_VALUE |
| 92 | |
| 93 | Disassembly of g: |
| 94 | 5 0 LOAD_CONST 0 (None) |
| 95 | 3 RETURN_VALUE |
| 96 | |
| 97 | """ |
| 98 | |
Nick Coghlan | 5c8b54e | 2010-07-03 07:36:51 +0000 | [diff] [blame] | 99 | expr_str = "x + 1" |
| 100 | |
| 101 | dis_expr_str = """\ |
| 102 | 1 0 LOAD_NAME 0 (x) |
| 103 | 3 LOAD_CONST 0 (1) |
| 104 | 6 BINARY_ADD |
| 105 | 7 RETURN_VALUE |
| 106 | """ |
| 107 | |
| 108 | simple_stmt_str = "x = x + 1" |
| 109 | |
| 110 | dis_simple_stmt_str = """\ |
| 111 | 1 0 LOAD_NAME 0 (x) |
| 112 | 3 LOAD_CONST 0 (1) |
| 113 | 6 BINARY_ADD |
| 114 | 7 STORE_NAME 0 (x) |
| 115 | 10 LOAD_CONST 1 (None) |
| 116 | 13 RETURN_VALUE |
| 117 | """ |
| 118 | |
| 119 | compound_stmt_str = """\ |
| 120 | x = 0 |
| 121 | while 1: |
| 122 | x += 1""" |
| 123 | # Trailing newline has been deliberately omitted |
| 124 | |
| 125 | dis_compound_stmt_str = """\ |
| 126 | 1 0 LOAD_CONST 0 (0) |
| 127 | 3 STORE_NAME 0 (x) |
| 128 | |
| 129 | 2 6 SETUP_LOOP 13 (to 22) |
| 130 | |
| 131 | 3 >> 9 LOAD_NAME 0 (x) |
| 132 | 12 LOAD_CONST 1 (1) |
| 133 | 15 INPLACE_ADD |
| 134 | 16 STORE_NAME 0 (x) |
| 135 | 19 JUMP_ABSOLUTE 9 |
| 136 | >> 22 LOAD_CONST 2 (None) |
| 137 | 25 RETURN_VALUE |
| 138 | """ |
Guido van Rossum | e7ba495 | 2007-06-06 23:52:48 +0000 | [diff] [blame] | 139 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 140 | class DisTests(unittest.TestCase): |
Michael W. Hudson | 26848a3 | 2003-04-29 17:07:36 +0000 | [diff] [blame] | 141 | def do_disassembly_test(self, func, expected): |
Guido van Rossum | 34d1928 | 2007-08-09 01:03:29 +0000 | [diff] [blame] | 142 | s = io.StringIO() |
Michael W. Hudson | 26848a3 | 2003-04-29 17:07:36 +0000 | [diff] [blame] | 143 | save_stdout = sys.stdout |
| 144 | sys.stdout = s |
| 145 | dis.dis(func) |
| 146 | sys.stdout = save_stdout |
| 147 | got = s.getvalue() |
| 148 | # Trim trailing blanks (if any). |
| 149 | lines = got.split('\n') |
| 150 | lines = [line.rstrip() for line in lines] |
| 151 | expected = expected.split("\n") |
| 152 | import difflib |
| 153 | if expected != lines: |
| 154 | self.fail( |
| 155 | "events did not match expectation:\n" + |
| 156 | "\n".join(difflib.ndiff(expected, |
| 157 | lines))) |
| 158 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 159 | def test_opmap(self): |
| 160 | self.assertEqual(dis.opmap["STOP_CODE"], 0) |
Ezio Melotti | b58e0bd | 2010-01-23 15:40:09 +0000 | [diff] [blame] | 161 | self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) |
| 162 | self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 163 | |
| 164 | def test_opname(self): |
| 165 | self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") |
| 166 | |
| 167 | def test_boundaries(self): |
| 168 | self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) |
| 169 | self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) |
| 170 | |
| 171 | def test_dis(self): |
Michael W. Hudson | 26848a3 | 2003-04-29 17:07:36 +0000 | [diff] [blame] | 172 | self.do_disassembly_test(_f, dis_f) |
| 173 | |
| 174 | def test_bug_708901(self): |
| 175 | self.do_disassembly_test(bug708901, dis_bug708901) |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 176 | |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 177 | def test_bug_1333982(self): |
Guido van Rossum | e7ba495 | 2007-06-06 23:52:48 +0000 | [diff] [blame] | 178 | # XXX: re-enable this test! |
Tim Peters | 83a8c39 | 2005-12-25 22:52:32 +0000 | [diff] [blame] | 179 | # This one is checking bytecodes generated for an `assert` statement, |
| 180 | # so fails if the tests are run with -O. Skip this test then. |
Nick Coghlan | 650f0d0 | 2007-04-15 12:05:43 +0000 | [diff] [blame] | 181 | pass # Test has been disabled due to change in the way |
| 182 | # list comps are handled. The byte code now includes |
| 183 | # a memory address and a file location, so they change from |
| 184 | # run to run. |
| 185 | # if __debug__: |
| 186 | # self.do_disassembly_test(bug1333982, dis_bug1333982) |
Neal Norwitz | 51abbc7 | 2005-12-18 07:06:23 +0000 | [diff] [blame] | 187 | |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 188 | def test_big_linenos(self): |
| 189 | def func(count): |
| 190 | namespace = {} |
| 191 | func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) |
Georg Brandl | 7cae87c | 2006-09-06 06:51:57 +0000 | [diff] [blame] | 192 | exec(func, namespace) |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 193 | return namespace['foo'] |
| 194 | |
| 195 | # Test all small ranges |
Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 196 | for i in range(1, 300): |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 197 | expected = _BIG_LINENO_FORMAT % (i + 2) |
| 198 | self.do_disassembly_test(func(i), expected) |
| 199 | |
| 200 | # Test some larger ranges too |
Guido van Rossum | 805365e | 2007-05-07 22:24:25 +0000 | [diff] [blame] | 201 | for i in range(300, 5000, 10): |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 202 | expected = _BIG_LINENO_FORMAT % (i + 2) |
| 203 | self.do_disassembly_test(func(i), expected) |
| 204 | |
Guido van Rossum | e7ba495 | 2007-06-06 23:52:48 +0000 | [diff] [blame] | 205 | def test_big_linenos(self): |
| 206 | from test import dis_module |
| 207 | self.do_disassembly_test(dis_module, dis_module_expected_results) |
| 208 | |
Nick Coghlan | 5c8b54e | 2010-07-03 07:36:51 +0000 | [diff] [blame] | 209 | def test_disassemble_str(self): |
| 210 | self.do_disassembly_test(expr_str, dis_expr_str) |
| 211 | self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str) |
| 212 | self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str) |
| 213 | |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 214 | code_info_code_info = """\ |
| 215 | Name: code_info |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 216 | Filename: (.*) |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 217 | Argument count: 1 |
| 218 | Kw-only arguments: 0 |
| 219 | Number of locals: 1 |
| 220 | Stack size: 4 |
| 221 | Flags: OPTIMIZED, NEWLOCALS, NOFREE |
| 222 | Constants: |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 223 | 0: %r |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 224 | 1: '__func__' |
| 225 | 2: '__code__' |
| 226 | 3: '<code_info>' |
| 227 | 4: 'co_code' |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 228 | 5: "don't know how to disassemble %%s objects" |
| 229 | %sNames: |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 230 | 0: hasattr |
| 231 | 1: __func__ |
| 232 | 2: __code__ |
| 233 | 3: isinstance |
| 234 | 4: str |
| 235 | 5: _try_compile |
| 236 | 6: _format_code_info |
| 237 | 7: TypeError |
| 238 | 8: type |
| 239 | 9: __name__ |
| 240 | Variable names: |
Georg Brandl | ebbf63b | 2010-10-14 07:23:01 +0000 | [diff] [blame] | 241 | 0: x""" % (('Formatted details of methods, functions, or code.', ' 6: None\n') |
| 242 | if sys.flags.optimize < 2 else (None, '')) |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 243 | |
| 244 | @staticmethod |
| 245 | def tricky(x, y, z=True, *args, c, d, e=[], **kwds): |
| 246 | def f(c=c): |
| 247 | print(x, y, z, c, d, e, f) |
| 248 | yield x, y, z, c, d, e, f |
| 249 | |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 250 | code_info_tricky = """\ |
| 251 | Name: tricky |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 252 | Filename: (.*) |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 253 | Argument count: 3 |
| 254 | Kw-only arguments: 3 |
| 255 | Number of locals: 8 |
| 256 | Stack size: 7 |
| 257 | Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR |
| 258 | Constants: |
| 259 | 0: None |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 260 | 1: <code object f at (.*), file "(.*)", line (.*)> |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 261 | Variable names: |
| 262 | 0: x |
| 263 | 1: y |
| 264 | 2: z |
| 265 | 3: c |
| 266 | 4: d |
| 267 | 5: e |
| 268 | 6: args |
| 269 | 7: kwds |
| 270 | Cell variables: |
| 271 | 0: e |
| 272 | 1: d |
| 273 | 2: f |
| 274 | 3: y |
| 275 | 4: x |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 276 | 5: z""" |
| 277 | |
| 278 | co_tricky_nested_f = tricky.__func__.__code__.co_consts[1] |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 279 | |
| 280 | code_info_tricky_nested_f = """\ |
| 281 | Name: f |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 282 | Filename: (.*) |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 283 | Argument count: 1 |
| 284 | Kw-only arguments: 0 |
| 285 | Number of locals: 1 |
| 286 | Stack size: 8 |
| 287 | Flags: OPTIMIZED, NEWLOCALS, NESTED |
| 288 | Constants: |
| 289 | 0: None |
| 290 | Names: |
| 291 | 0: print |
| 292 | Variable names: |
| 293 | 0: c |
| 294 | Free variables: |
| 295 | 0: e |
| 296 | 1: d |
| 297 | 2: f |
| 298 | 3: y |
| 299 | 4: x |
Nick Coghlan | 46e6380 | 2010-08-17 11:28:07 +0000 | [diff] [blame] | 300 | 5: z""" |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 301 | |
| 302 | code_info_expr_str = """\ |
| 303 | Name: <module> |
| 304 | Filename: <code_info> |
| 305 | Argument count: 0 |
| 306 | Kw-only arguments: 0 |
| 307 | Number of locals: 0 |
| 308 | Stack size: 2 |
| 309 | Flags: NOFREE |
| 310 | Constants: |
| 311 | 0: 1 |
| 312 | Names: |
| 313 | 0: x""" |
| 314 | |
| 315 | code_info_simple_stmt_str = """\ |
| 316 | Name: <module> |
| 317 | Filename: <code_info> |
| 318 | Argument count: 0 |
| 319 | Kw-only arguments: 0 |
| 320 | Number of locals: 0 |
| 321 | Stack size: 2 |
| 322 | Flags: NOFREE |
| 323 | Constants: |
| 324 | 0: 1 |
| 325 | 1: None |
| 326 | Names: |
| 327 | 0: x""" |
| 328 | |
| 329 | code_info_compound_stmt_str = """\ |
| 330 | Name: <module> |
| 331 | Filename: <code_info> |
| 332 | Argument count: 0 |
| 333 | Kw-only arguments: 0 |
| 334 | Number of locals: 0 |
| 335 | Stack size: 2 |
| 336 | Flags: NOFREE |
| 337 | Constants: |
| 338 | 0: 0 |
| 339 | 1: 1 |
| 340 | 2: None |
| 341 | Names: |
| 342 | 0: x""" |
| 343 | |
| 344 | class CodeInfoTests(unittest.TestCase): |
| 345 | test_pairs = [ |
| 346 | (dis.code_info, code_info_code_info), |
| 347 | (tricky, code_info_tricky), |
| 348 | (co_tricky_nested_f, code_info_tricky_nested_f), |
| 349 | (expr_str, code_info_expr_str), |
| 350 | (simple_stmt_str, code_info_simple_stmt_str), |
| 351 | (compound_stmt_str, code_info_compound_stmt_str), |
| 352 | ] |
| 353 | |
| 354 | def test_code_info(self): |
| 355 | self.maxDiff = 1000 |
| 356 | for x, expected in self.test_pairs: |
Nick Coghlan | 77203ad | 2010-08-17 09:25:57 +0000 | [diff] [blame] | 357 | self.assertRegexpMatches(dis.code_info(x), expected) |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 358 | |
| 359 | def test_show_code(self): |
| 360 | self.maxDiff = 1000 |
| 361 | for x, expected in self.test_pairs: |
| 362 | with captured_stdout() as output: |
| 363 | dis.show_code(x) |
Nick Coghlan | 77203ad | 2010-08-17 09:25:57 +0000 | [diff] [blame] | 364 | self.assertRegexpMatches(output.getvalue(), expected+"\n") |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 365 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 366 | def test_main(): |
Nick Coghlan | eae2da1 | 2010-08-17 08:03:36 +0000 | [diff] [blame] | 367 | run_unittest(DisTests, CodeInfoTests) |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 368 | |
Skip Montanaro | add0ccc | 2003-02-27 21:27:07 +0000 | [diff] [blame] | 369 | if __name__ == "__main__": |
| 370 | test_main() |