]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46422: use `dis.Positions` in `dis.Instruction` (GH-30716)
authorNikita Sobolev <mail@sobolevn.me>
Mon, 24 Jan 2022 11:09:20 +0000 (14:09 +0300)
committerGitHub <noreply@github.com>
Mon, 24 Jan 2022 11:09:20 +0000 (14:09 +0300)
Co-authored-by: Batuhan Taskaya <isidentical@gmail.com>
Doc/library/dis.rst
Lib/dis.py
Lib/test/test_dis.py
Misc/NEWS.d/next/Library/2022-01-20-10-35-50.bpo-46422.1UAEHL.rst [new file with mode: 0644]

index ddba668088e4a24115c6bda3647c73b7e59b6b56..793152d9d812c8413cb3f5a459cd6ac30ca9cdbd 100644 (file)
@@ -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.
 
index ac0c6e7f04c45705392c2ca9e4dc66afee6b95bb..2462a8434e89502938a0d1446649e1be8cc67e91 100644 (file)
@@ -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.
index 19a4be2c4132b1882b48d7f400b70126f3fab6ab..ee9729ebabf4acab0a2caae09a0399edbf94d024 100644 (file)
@@ -1313,6 +1313,12 @@ class InstructionTests(InstructionTestCase):
         ]
         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 @@ class InstructionTests(InstructionTestCase):
         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
diff --git a/Misc/NEWS.d/next/Library/2022-01-20-10-35-50.bpo-46422.1UAEHL.rst b/Misc/NEWS.d/next/Library/2022-01-20-10-35-50.bpo-46422.1UAEHL.rst
new file mode 100644 (file)
index 0000000..831f526
--- /dev/null
@@ -0,0 +1 @@
+Use ``dis.Positions`` in ``dis.Instruction`` instead of a regular ``tuple``.