Last active
February 3, 2026 15:14
-
-
Save miketheman/0ff15be2efea2573ae46e52bef069c77 to your computer and use it in GitHub Desktop.
Extra debug notes for https://github.com/coveragepy/coveragepy/pull/2123
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import dis | |
| from contextlib import contextmanager | |
| @contextmanager | |
| def dummy_context(name): | |
| yield name | |
| def nested_with(): | |
| result = [] | |
| with dummy_context("outer"): | |
| with dummy_context("middle"): | |
| with dummy_context("inner"): | |
| result.append("inside") | |
| result.append("after") | |
| return result | |
| print('Bytecode with line numbers:') | |
| for inst in dis.get_instructions(nested_with): | |
| print(f'{inst.offset:4} line {inst.line_number or "--":>3} {inst.opname:25} {inst.argrepr}') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Bytecode with line numbers: | |
| 0 line 9 RESUME | |
| 2 line 10 BUILD_LIST | |
| 4 line 10 STORE_FAST result | |
| 6 line 11 LOAD_GLOBAL dummy_context + NULL | |
| 16 line 11 LOAD_CONST 'outer' | |
| 18 line 11 CALL | |
| 26 line 11 COPY | |
| 28 line 11 LOAD_SPECIAL __exit__ | |
| 30 line 11 SWAP | |
| 32 line 11 SWAP | |
| 34 line 11 LOAD_SPECIAL __enter__ | |
| 36 line 11 CALL | |
| 44 line 11 POP_TOP | |
| 46 line 12 LOAD_GLOBAL dummy_context + NULL | |
| 56 line 12 LOAD_CONST 'middle' | |
| 58 line 12 CALL | |
| 66 line 12 COPY | |
| 68 line 12 LOAD_SPECIAL __exit__ | |
| 70 line 12 SWAP | |
| 72 line 12 SWAP | |
| 74 line 12 LOAD_SPECIAL __enter__ | |
| 76 line 12 CALL | |
| 84 line 12 POP_TOP | |
| 86 line 13 LOAD_GLOBAL dummy_context + NULL | |
| 96 line 13 LOAD_CONST 'inner' | |
| 98 line 13 CALL | |
| 106 line 13 COPY | |
| 108 line 13 LOAD_SPECIAL __exit__ | |
| 110 line 13 SWAP | |
| 112 line 13 SWAP | |
| 114 line 13 LOAD_SPECIAL __enter__ | |
| 116 line 13 CALL | |
| 124 line 13 POP_TOP | |
| 126 line 14 LOAD_FAST_BORROW result | |
| 128 line 14 LOAD_ATTR append + NULL|self | |
| 148 line 14 LOAD_CONST 'inside' | |
| 150 line 14 CALL | |
| 158 line 14 POP_TOP | |
| 160 line 13 LOAD_CONST None | |
| 162 line 13 LOAD_CONST None | |
| 164 line 13 LOAD_CONST None | |
| 166 line 13 CALL | |
| 174 line 13 POP_TOP | |
| 176 line 12 LOAD_CONST None | |
| 178 line 12 LOAD_CONST None | |
| 180 line 12 LOAD_CONST None | |
| 182 line 12 CALL | |
| 190 line 12 POP_TOP | |
| 192 line 11 LOAD_CONST None | |
| 194 line 11 LOAD_CONST None | |
| 196 line 11 LOAD_CONST None | |
| 198 line 11 CALL | |
| 206 line 11 POP_TOP | |
| 208 line 15 LOAD_FAST_BORROW result | |
| 210 line 15 LOAD_ATTR append + NULL|self | |
| 230 line 15 LOAD_CONST 'after' | |
| 232 line 15 CALL | |
| 240 line 15 POP_TOP | |
| 242 line 16 LOAD_FAST_BORROW result | |
| 244 line 16 RETURN_VALUE | |
| 246 line 13 PUSH_EXC_INFO | |
| 248 line 13 WITH_EXCEPT_START | |
| 250 line 13 TO_BOOL | |
| 258 line 13 POP_JUMP_IF_TRUE to L4 | |
| 262 line 13 NOT_TAKEN | |
| 264 line 13 RERAISE | |
| 266 line 13 POP_TOP | |
| 268 line 13 POP_EXCEPT | |
| 270 line 13 POP_TOP | |
| 272 line 13 POP_TOP | |
| 274 line 13 POP_TOP | |
| 276 line 13 JUMP_BACKWARD_NO_INTERRUPT to L1 | |
| 278 line -- COPY | |
| 280 line -- POP_EXCEPT | |
| 282 line -- RERAISE | |
| 284 line 12 PUSH_EXC_INFO | |
| 286 line 12 WITH_EXCEPT_START | |
| 288 line 12 TO_BOOL | |
| 296 line 12 POP_JUMP_IF_TRUE to L5 | |
| 300 line 12 NOT_TAKEN | |
| 302 line 12 RERAISE | |
| 304 line 12 POP_TOP | |
| 306 line 12 POP_EXCEPT | |
| 308 line 12 POP_TOP | |
| 310 line 12 POP_TOP | |
| 312 line 12 POP_TOP | |
| 314 line 12 JUMP_BACKWARD_NO_INTERRUPT to L2 | |
| 316 line -- COPY | |
| 318 line -- POP_EXCEPT | |
| 320 line -- RERAISE | |
| 322 line 11 PUSH_EXC_INFO | |
| 324 line 11 WITH_EXCEPT_START | |
| 326 line 11 TO_BOOL | |
| 334 line 11 POP_JUMP_IF_TRUE to L6 | |
| 338 line 11 NOT_TAKEN | |
| 340 line 11 RERAISE | |
| 342 line 11 POP_TOP | |
| 344 line 11 POP_EXCEPT | |
| 346 line 11 POP_TOP | |
| 348 line 11 POP_TOP | |
| 350 line 11 POP_TOP | |
| 352 line 11 JUMP_BACKWARD_NO_INTERRUPT to L3 | |
| 354 line -- COPY | |
| 356 line -- POP_EXCEPT | |
| 358 line -- RERAISE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import dis | |
| from collections import defaultdict | |
| def multi_visit_lines(code): | |
| line_offsets = defaultdict(list) | |
| for inst in dis.get_instructions(code): | |
| if inst.line_number: | |
| line_offsets[inst.line_number].append(inst.offset) | |
| result = set() | |
| for line, offsets in line_offsets.items(): | |
| offsets = sorted(offsets) | |
| # offsets are already in order from walk() | |
| for i in range(1, len(offsets)): | |
| print(f'Line {line} offsets: {offsets}') | |
| # Bytecode instructions are 2 bytes apart; a larger gap means | |
| # the line appears in multiple non-contiguous code sections. | |
| if offsets[i] - offsets[i - 1] > 2: | |
| result.add(line) | |
| break | |
| return result | |
| code = compile("""\ | |
| import dis # unused, to help lines match in both examples | |
| from contextlib import contextmanager | |
| @contextmanager | |
| def dummy_context(name): | |
| yield name | |
| def nested_with(): | |
| result = [] | |
| with dummy_context("outer"): | |
| with dummy_context("middle"): | |
| with dummy_context("inner"): | |
| result.append("inside") | |
| result.append("after") | |
| return result | |
| """, "<test>", "exec") | |
| for const in code.co_consts: | |
| if hasattr(const, 'co_name') and const.co_name == 'nested_with': | |
| func_code = const | |
| break | |
| result = multi_visit_lines(func_code) | |
| print() | |
| print(f'Lines in function: {sorted(set(i.line_number for i in dis.get_instructions(func_code) if i.line_number))}') | |
| print(f'Multi-visit lines: {sorted(result)}') | |
| print() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Line 9 offsets: [2, 4] | |
| Line 10 offsets: [6, 16, 18, 26, 28, 30, 32, 34, 36, 44, 192, 194, 196, 198, 206, 322, 324, 326, 334, 338, 340, 342, 344, 346, 348, 350, 352] | |
| Line 11 offsets: [46, 56, 58, 66, 68, 70, 72, 74, 76, 84, 176, 178, 180, 182, 190, 284, 286, 288, 296, 300, 302, 304, 306, 308, 310, 312, 314] | |
| Line 12 offsets: [86, 96, 98, 106, 108, 110, 112, 114, 116, 124, 160, 162, 164, 166, 174, 246, 248, 250, 258, 262, 264, 266, 268, 270, 272, 274, 276] | |
| Line 13 offsets: [126, 128, 148, 150, 158] | |
| Line 13 offsets: [126, 128, 148, 150, 158] | |
| Line 14 offsets: [208, 210, 230, 232, 240] | |
| Line 14 offsets: [208, 210, 230, 232, 240] | |
| Line 15 offsets: [242, 244] | |
| Lines in function: [8, 9, 10, 11, 12, 13, 14, 15] | |
| Multi-visit lines: [10, 11, 12, 13, 14] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment