Skip to content

Commit 0af394a

Browse files
authored
Merge pull request #157 from 2elli/python-3.13
Python 3.10-3.13 line number and opcode argrepr fixes
2 parents 7f9e8d5 + 6044598 commit 0af394a

File tree

8 files changed

+58
-200
lines changed

8 files changed

+58
-200
lines changed

xdis/codetype/__init__.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from xdis.codetype.code38 import Code38
2929
from xdis.codetype.code310 import Code310
3030
from xdis.codetype.code311 import Code311, Code311FieldNames
31-
from xdis.codetype.code312 import Code312
3231
from xdis.version_info import PYTHON_VERSION_TRIPLE
3332

3433

@@ -101,7 +100,7 @@ def codeType2Portable(code, version_tuple=PYTHON_VERSION_TRIPLE):
101100
co_firstlineno=code.co_firstlineno,
102101
co_linetable=line_table,
103102
)
104-
elif version_tuple[:2] == (3,11):
103+
elif version_tuple[:2] >= (3,11):
105104
return Code311(
106105
co_argcount=code.co_argcount,
107106
co_posonlyargcount=code.co_posonlyargcount,
@@ -122,27 +121,6 @@ def codeType2Portable(code, version_tuple=PYTHON_VERSION_TRIPLE):
122121
co_linetable=line_table,
123122
co_exceptiontable=code.co_exceptiontable,
124123
)
125-
elif version_tuple[:2] >= (3,12):
126-
return Code312(
127-
co_argcount=code.co_argcount,
128-
co_posonlyargcount=code.co_posonlyargcount,
129-
co_kwonlyargcount=code.co_kwonlyargcount,
130-
co_nlocals=code.co_nlocals,
131-
co_stacksize=code.co_stacksize,
132-
co_flags=code.co_flags,
133-
co_consts=code.co_consts,
134-
co_code=code.co_code,
135-
co_names=code.co_names,
136-
co_varnames=code.co_varnames,
137-
co_freevars=code.co_freevars,
138-
co_cellvars=code.co_cellvars,
139-
co_filename=code.co_filename,
140-
co_name=code.co_name,
141-
co_qualname=code.co_qualname,
142-
co_firstlineno=code.co_firstlineno,
143-
co_linetable=line_table,
144-
co_exceptiontable=code.co_exceptiontable,
145-
)
146124
elif version_tuple > (2, 0):
147125
# 2.0 .. 2.7
148126
return Code2(
@@ -209,11 +187,9 @@ def portableCodeType(version_tuple=PYTHON_VERSION_TRIPLE):
209187
elif version_tuple[:2] == (3, 10):
210188
# 3.10
211189
return Code310
212-
elif version_tuple[:2] == (3,11):
190+
elif version_tuple[:2] >= (3,11):
213191
# 3.11 ...
214192
return Code311
215-
elif version_tuple[:2] >= (3,12):
216-
return Code312
217193
elif version_tuple > (2, 0):
218194
# 2.0 .. 2.7
219195
return Code2

xdis/codetype/code310.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import types
1818
from copy import deepcopy
1919

20+
import struct
21+
2022
from xdis.codetype.code38 import Code38
2123
from xdis.cross_types import UnicodeForPython3
2224
from xdis.version_info import PYTHON_VERSION_TRIPLE, version_tuple_to_str
@@ -160,41 +162,25 @@ def co_lines(self):
160162
equal to the size of the bytecode. line will
161163
either be a positive integer, or None
162164
165+
Parsing implementation adapted from: https://github.com/python/cpython/blob/3.10/Objects/lnotab_notes.txt
163166
"""
164-
line_number = self.co_firstlineno
165-
start_offset = 0
166-
byte_increments = [c for c in tuple(self.co_linetable[0::2])]
167-
line_deltas = [c for c in tuple(self.co_linetable[1::2])]
168-
169-
if len(byte_increments) == 0:
170-
yield start_offset, len(self.co_code), line_number
171-
return
172-
173-
byte_incr = byte_increments[0]
174-
line_delta = line_deltas[0]
175-
assert line_delta != -128, "the first line delta can't logically be -128"
176-
assert isinstance(line_delta, int)
177-
if line_delta > 127:
178-
line_delta = 256 - line_delta
179-
else:
180-
line_number += line_delta
181-
182-
for byte_incr, line_delta in zip(byte_increments[1:], line_deltas[1:]):
167+
line = self.co_firstlineno
168+
end_offset = 0
169+
# co_linetable is pairs of (offset_delta: unsigned byte, line_delta: signed byte)
170+
for offset_delta, line_delta in struct.iter_unpack('=Bb', self.co_linetable):
183171
assert isinstance(line_delta, int)
184-
assert isinstance(byte_incr, int)
185-
end_offset = start_offset + byte_incr
186-
if line_delta > 127:
187-
line_delta = 256 - line_delta
188-
189-
if line_delta == -128:
190-
line_delta = 0
191-
yield start_offset, end_offset, line_number
192-
line_number += line_delta
172+
assert isinstance(offset_delta, int)
173+
if line_delta == 0: # No change to line number, just accumulate changes to end
174+
end_offset += offset_delta
175+
continue
193176
start_offset = end_offset
194-
195-
end_offset = len(self.co_code)
196-
yield start_offset, end_offset, line_number
197-
return
177+
end_offset = start_offset + offset_delta
178+
if line_delta == -128: # No valid line number -- skip entry
179+
continue
180+
line += line_delta
181+
if end_offset == start_offset: # Empty range, omit.
182+
continue
183+
yield start_offset, end_offset, line
198184

199185
def encode_lineno_tab(self):
200186
"""

xdis/codetype/code311.py

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,37 @@
2323
from xdis.version_info import PYTHON_VERSION_TRIPLE, version_tuple_to_str
2424

2525

26+
# Note: order is the positional order given in the Python docs for
27+
# 3.11 types.Codetype.
28+
# "posonlyargcount" is not used, but it is in other Python versions, so it
29+
# has to be included since this structure is used as the Union type
30+
# for all code types.
31+
Code311FieldNames = """
32+
co_argcount
33+
co_posonlyargcount
34+
co_kwonlyargcount
35+
co_nlocals
36+
co_stacksize
37+
co_flags
38+
co_consts
39+
co_code
40+
co_names
41+
co_varnames
42+
co_freevars
43+
co_cellvars
44+
co_filename
45+
co_name
46+
co_qualname
47+
co_firstlineno
48+
co_linetable
49+
co_exceptiontable
50+
"""
51+
52+
Code311FieldTypes = deepcopy(Code310FieldTypes)
53+
Code311FieldTypes.update({"co_qualname": str, "co_exceptiontable": bytes})
54+
55+
56+
##### Parse location table #####
2657
def parse_location_entries(location_bytes, first_line):
2758
"""
2859
Parses the locations table described in: https://github.com/python/cpython/blob/3.11/Objects/locations.md
@@ -131,36 +162,6 @@ def decode_signed_varint(s):
131162
return entries
132163

133164

134-
# Note: order is the positional order given in the Python docs for
135-
# 3.11 types.Codetype.
136-
# "posonlyargcount" is not used, but it is in other Python versions, so it
137-
# has to be included since this structure is used as the Union type
138-
# for all code types.
139-
Code311FieldNames = """
140-
co_argcount
141-
co_posonlyargcount
142-
co_kwonlyargcount
143-
co_nlocals
144-
co_stacksize
145-
co_flags
146-
co_consts
147-
co_code
148-
co_names
149-
co_varnames
150-
co_freevars
151-
co_cellvars
152-
co_filename
153-
co_name
154-
co_qualname
155-
co_firstlineno
156-
co_linetable
157-
co_exceptiontable
158-
"""
159-
160-
Code311FieldTypes = deepcopy(Code310FieldTypes)
161-
Code311FieldTypes.update({"co_qualname": str, "co_exceptiontable": bytes})
162-
163-
164165
##### NEW "OPAQUE" LINE TABLE PARSING #####
165166
# See: https://github.com/python/cpython/blob/aaed91cabcedc16c089c4b1c9abb1114659a83d3/Objects/codeobject.c#L1245C1-L1245C17
166167
PY_CODE_LOCATION_INFO_SHORT0 = 0

xdis/codetype/code312.py

Lines changed: 0 additions & 97 deletions
This file was deleted.

xdis/opcodes/opcode_310.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,10 @@
4949
def_op(loc, "RERAISE", 119, 3, 0)
5050
def_op(loc, "GEN_START", 129, 1, 0)
5151
def_op(loc, "MATCH_CLASS", 152, 2, 1)
52-
# fmt: on
53-
5452

53+
# fmt: on
5554
opcode_arg_fmt = opcode_arg_fmt310 = opcode_arg_fmt39.copy()
5655
opcode_extended_fmt = opcode_extended_fmt310 = opcode_extended_fmt39.copy()
5756

58-
# fmt: on
59-
60-
opcode_arg_fmt = opcode_arg_fmt10 = opcode_arg_fmt39.copy()
61-
6257
update_pj3(globals(), loc)
6358
finalize_opcodes(loc)

xdis/opcodes/opcode_311.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,6 @@ def format_BINARY_OP(arg) -> str:
297297
del opcode_extended_fmt311["INPLACE_TRUE_DIVIDE"]
298298
del opcode_extended_fmt311["INPLACE_XOR"]
299299

300-
opcode_extended_fmt = opcode_extended_fmt311
301-
302-
opcode_arg_fmt = opcode_arg_fmt11 = opcode_arg_fmt310.copy()
303-
304300
from xdis.opcodes.opcode_310 import findlinestarts
305301

306302
update_pj3(globals(), loc)

xdis/opcodes/opcode_312.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ def format_CALL_INTRINSIC_1(arg) -> str:
177177
def format_CALL_INTRINSIC_2(arg) -> str:
178178
return _intrinsic_2_descs[arg]
179179

180+
181+
opcode_extended_fmt = opcode_extended_fmt312 = opcode_extended_fmt311.copy()
182+
opcode_arg_fmt = opcode_arg_fmt12 = opcode_arg_fmt311.copy()
183+
180184
### update arg formatting
181185
opcode_arg_fmt312 = {
182186
**opcode_arg_fmt311,
@@ -185,9 +189,6 @@ def format_CALL_INTRINSIC_2(arg) -> str:
185189
"CALL_INTRINSIC_2": format_CALL_INTRINSIC_2,
186190
},
187191
}
188-
opcode_extended_fmt = opcode_extended_fmt312 = opcode_extended_fmt311.copy()
189-
190-
opcode_arg_fmt = opcode_arg_fmt12 = opcode_arg_fmt311.copy()
191192

192193
from xdis.opcodes.opcode_311 import findlinestarts
193194

xdis/opcodes/opcode_313.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,8 @@
450450
opcode_extended_fmt = opcode_312.opcode_extended_fmt312.copy()
451451
for fmt_table in (opcode_arg_fmt, opcode_extended_fmt):
452452
fmt_table.pop("MAKE_FUNCTION") # MAKE_FUNCTION formatting not in 3.13
453-
opcode_arg_fmt13 = opcode_arg_fmt
454-
opcode_extended_fmt13 = opcode_extended_fmt
453+
opcode_arg_fmt313 = opcode_arg_fmt
454+
opcode_extended_fmt313 = opcode_extended_fmt
455455

456456

457457
# update any calls to findlinestarts to include the version tuple

0 commit comments

Comments
 (0)