mirror of https://github.com/python/cpython.git
bpo-46422: use `dis.Positions` in `dis.Instruction` (GH-30716)
Co-authored-by: Batuhan Taskaya <isidentical@gmail.com>
This commit is contained in:
parent
0367a36fdc
commit
58f3d98098
|
@ -316,8 +316,30 @@ details of bytecode instructions as :class:`Instruction` instances:
|
|||
|
||||
``True`` if other code jumps to here, otherwise ``False``
|
||||
|
||||
|
||||
.. data:: positions
|
||||
|
||||
:class:`dis.Positions` object holding the
|
||||
start and end locations that are covered by this instruction.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
|
||||
Field ``positions`` is added.
|
||||
|
||||
|
||||
.. class:: Positions
|
||||
|
||||
In case the information is not available, some fields might be `None`.
|
||||
|
||||
.. data:: lineno
|
||||
.. data:: end_lineno
|
||||
.. data:: col_offset
|
||||
.. data:: end_col_offset
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
The Python compiler currently generates the following bytecode instructions.
|
||||
|
||||
|
|
|
@ -413,10 +413,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
|
|||
is_jump_target = offset in labels
|
||||
argval = None
|
||||
argrepr = ''
|
||||
try:
|
||||
positions = next(co_positions)
|
||||
except StopIteration:
|
||||
positions = None
|
||||
positions = Positions(*next(co_positions, ()))
|
||||
if arg is not None:
|
||||
# Set argval to the dereferenced value of the argument when
|
||||
# available, and argrepr to the string representation of argval.
|
||||
|
|
|
@ -1313,6 +1313,12 @@ def test_co_positions(self):
|
|||
]
|
||||
self.assertEqual(positions, expected)
|
||||
|
||||
named_positions = [
|
||||
(pos.lineno, pos.end_lineno, pos.col_offset, pos.end_col_offset)
|
||||
for pos in positions
|
||||
]
|
||||
self.assertEqual(named_positions, expected)
|
||||
|
||||
@requires_debug_ranges()
|
||||
def test_co_positions_missing_info(self):
|
||||
code = compile('x, y, z', '<test>', 'exec')
|
||||
|
@ -1320,25 +1326,27 @@ def test_co_positions_missing_info(self):
|
|||
actual = dis.get_instructions(code_without_column_table)
|
||||
for instruction in actual:
|
||||
with self.subTest(instruction=instruction):
|
||||
start_line, end_line, start_offset, end_offset = instruction.positions
|
||||
positions = instruction.positions
|
||||
self.assertEqual(len(positions), 4)
|
||||
if instruction.opname == "RESUME":
|
||||
continue
|
||||
assert start_line == 1
|
||||
assert end_line == 1
|
||||
assert start_offset is None
|
||||
assert end_offset is None
|
||||
self.assertEqual(positions.lineno, 1)
|
||||
self.assertEqual(positions.end_lineno, 1)
|
||||
self.assertIsNone(positions.col_offset)
|
||||
self.assertIsNone(positions.end_col_offset)
|
||||
|
||||
code_without_endline_table = code.replace(co_endlinetable=b'')
|
||||
actual = dis.get_instructions(code_without_endline_table)
|
||||
for instruction in actual:
|
||||
with self.subTest(instruction=instruction):
|
||||
start_line, end_line, start_offset, end_offset = instruction.positions
|
||||
positions = instruction.positions
|
||||
self.assertEqual(len(positions), 4)
|
||||
if instruction.opname == "RESUME":
|
||||
continue
|
||||
assert start_line == 1
|
||||
assert end_line is None
|
||||
assert start_offset is not None
|
||||
assert end_offset is not None
|
||||
self.assertEqual(positions.lineno, 1)
|
||||
self.assertIsNone(positions.end_lineno)
|
||||
self.assertIsNotNone(positions.col_offset)
|
||||
self.assertIsNotNone(positions.end_col_offset)
|
||||
|
||||
# get_instructions has its own tests above, so can rely on it to validate
|
||||
# the object oriented API
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Use ``dis.Positions`` in ``dis.Instruction`` instead of a regular ``tuple``.
|
Loading…
Reference in New Issue