Skip to content

Commit b6eaeb5

Browse files
author
rocky
committed
Limited 3.14 support.
Add 3.14 magic numbers.
1 parent 32b3e51 commit b6eaeb5

File tree

6 files changed

+148
-38
lines changed

6 files changed

+148
-38
lines changed

pytest/test_cross_dis.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
import pytest
44
from xdis.cross_dis import findlabels
55
from xdis.op_imports import get_opcode_module
6-
from xdis.version_info import IS_GRAAL
6+
from xdis.version_info import IS_GRAAL, PYTHON_VERSION_TRIPLE
77

88

99
@pytest.mark.skipif(IS_GRAAL, reason="Graal label finding is wonky")
10+
@pytest.mark.skipif(
11+
PYTHON_VERSION_TRIPLE >= (3, 14),
12+
reason="Python >= 3.14 is not complete.",
13+
)
1014
def test_findlabels():
1115
code = findlabels.__code__.co_code
1216
opc = get_opcode_module()

pytest/test_magic.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
"""
22
Unit test for xdis.magics
33
"""
4+
import pytest
45
from xdis.magics import MAGIC, sysinfo2magic
6+
from xdis.version_info import PYTHON_VERSION_TRIPLE
57

68

9+
@pytest.mark.skipif(
10+
PYTHON_VERSION_TRIPLE >= (3, 14),
11+
reason="Python >= 3.14 is not complete.",
12+
)
713
def test_magic():
814
assert sysinfo2magic() == MAGIC, (sysinfo2magic(), MAGIC)

pytest/test_opcode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import dis
22

3+
import pytest
34
from xdis import IS_PYPY, PYTHON_VERSION_TRIPLE, get_opcode
45

56

7+
@pytest.mark.skipif(
8+
PYTHON_VERSION_TRIPLE >= (3, 14),
9+
reason="Python >= 3.14 is not complete.",
10+
)
611
def test_opcode() -> None:
712
opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY)
813
opmap = dict([(k.replace("+", "_"), v) for (k, v) in dis.opmap.items()])

pytest/test_stack_effect.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ def test_stack_effect_fixed() -> None:
8989
xdis.PYTHON_VERSION_TRIPLE < (3, 4) or xdis.IS_PYPY or xdis.IS_GRAAL,
9090
reason="Python version is before 3.4. Can't test",
9191
)
92+
@pytest.mark.skipif(
93+
xdis.PYTHON_VERSION_TRIPLE >= (3, 14),
94+
reason="Python >= 3.14 is not complete.",
95+
)
9296
def test_stack_effect_vs_dis() -> None:
9397
import dis
9498

xdis/magics.py

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,7 @@ def __by_version(magic_versions: Dict[bytes, str]) -> dict:
9898
magicint2version: Dict[int, str] = {}
9999
versions: Dict[bytes, str] = {}
100100

101-
try:
102-
from importlib.util import MAGIC_NUMBER as MAGIC
103-
except ImportError:
104-
import imp
105-
106-
MAGIC = imp.get_magic()
101+
from importlib.util import MAGIC_NUMBER as MAGIC
107102

108103
PYTHON_MAGIC_INT = magic2int(MAGIC)
109104

@@ -424,12 +419,25 @@ def __by_version(magic_versions: Dict[bytes, str]) -> dict:
424419
add_magic_from_int(3531, "3.12.0rc2")
425420

426421
# 3.13
422+
# Plugin optimizer support
427423
add_magic_from_int(3550, "3.13a1a")
424+
425+
# Compact superinstructions
428426
add_magic_from_int(3551, "3.13a1b")
427+
428+
# Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST
429429
add_magic_from_int(3552, "3.13a1c")
430+
431+
# Add SET_FUNCTION_ATTRIBUTE
430432
add_magic_from_int(3553, "3.13a1d")
433+
434+
# more efficient bytecodes for f-strings
431435
add_magic_from_int(3554, "3.13a1e")
436+
437+
# generate specialized opcodes metadata from bytecodes.c
432438
add_magic_from_int(3555, "3.13a1f")
439+
440+
# Convert LOAD_CLOSURE to a pseudo-op
433441
add_magic_from_int(3556, "3.13a1g")
434442
add_magic_from_int(3557, "3.13a1h")
435443
add_magic_from_int(3558, "3.13a1i")
@@ -447,6 +455,81 @@ def __by_version(magic_versions: Dict[bytes, str]) -> dict:
447455
add_magic_from_int(3570, "3.13a6")
448456
add_magic_from_int(3571, "3.13.0rc3")
449457

458+
# Add LOAD_COMMON_CONSTANT
459+
add_magic_from_int(3600, "3.14a1a")
460+
461+
# Fix miscompilation of private names in generic classes
462+
add_magic_from_int(3601, "3.14a1b")
463+
464+
# Add LOAD_SPECIAL. Remove BEFORE_WITH and BEFORE_ASYNC_WITH
465+
add_magic_from_int(3602, "3.14a1c")
466+
467+
# Remove BUILD_CONST_KEY_MAP
468+
add_magic_from_int(3603, "3.14a1d")
469+
470+
# Do not duplicate test at end of while statements
471+
add_magic_from_int(3604, "3.14a1e")
472+
473+
# Move ENTER_EXECUTOR to opcode 255
474+
add_magic_from_int(3605, "3.14a1f")
475+
476+
# Specialize CALL_KW
477+
add_magic_from_int(3606, "3.14a1g")
478+
479+
# Add pseudo instructions JUMP_IF_TRUE/FALSE
480+
add_magic_from_int(3607, "3.14a1h")
481+
482+
# Add support for slices
483+
add_magic_from_int(3608, "3.14a1i")
484+
485+
# Add LOAD_SMALL_INT and LOAD_CONST_IMMORTAL instructions, remove RETURN_CONST
486+
add_magic_from_int(3608, "3.14a2")
487+
488+
# Add VALUE_WITH_FAKE_GLOBALS format to annotationlib
489+
add_magic_from_int(3610, "3.14a4a")
490+
491+
# Add NOT_TAKEN instruction
492+
add_magic_from_int(3611, "3.14a4b")
493+
494+
#Add LOAD_CONST_MORTAL instruction
495+
add_magic_from_int(3613, "3.14a4c")
496+
497+
#Add BINARY_OP_EXTEND
498+
add_magic_from_int(3614, "3.14a4d")
499+
500+
#Add BINARY_OP_EXTEND
501+
add_magic_from_int(3615, "3.14a5a")
502+
503+
#Add BINARY_OP_EXTEND
504+
add_magic_from_int(3616, "3.14a5a")
505+
506+
#Branch monitoring for async for loops
507+
add_magic_from_int(3617, "3.14a6a")
508+
509+
#Add oparg to END_ASYNC_FOR
510+
add_magic_from_int(3618, "3.14a6b")
511+
512+
#Renumber RESUME opcode from 149 to 128
513+
add_magic_from_int(3619, "3.14a6c")
514+
515+
#Optimize bytecode for all/any/tuple called on a genexp
516+
add_magic_from_int(3620, "3.14a7a")
517+
518+
#Optimize LOAD_FAST opcodes into LOAD_FAST_BORROW
519+
add_magic_from_int(3621, "3.14a7b")
520+
521+
#Store annotations in different class dict keys
522+
add_magic_from_int(3622, "3.14a7c")
523+
524+
#Add BUILD_INTERPOLATION & BUILD_TEMPLATE opcodes
525+
add_magic_from_int(3623, "3.14a7d")
526+
527+
#Don't optimize LOAD_FAST when local is killed by DELETE_FAST
528+
add_magic_from_int(3624, "3.14b1")
529+
530+
# Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST
531+
add_magic_from_int(3625, "3.14b3")
532+
450533
# Weird ones
451534
# WTF? Python 3.2.5 and PyPy have weird magic numbers
452535

@@ -595,6 +678,11 @@ def add_canonic_versions(release_versions: str, canonic: str) -> None:
595678
"3.13.0rc3",
596679
)
597680

681+
add_canonic_versions(
682+
"3.14 3.14-dev",
683+
"3.14b3",
684+
)
685+
598686
# The canonic version for a canonic version is itself
599687
for v in versions.values():
600688
canonic_python_version[v] = v
@@ -646,8 +734,8 @@ def py_str2tuple(orig_version: str) -> tuple[int, int] | tuple[int, int, int]:
646734

647735
def sysinfo2magic(version_info=sys.version_info) -> bytes:
648736
"""Convert a list sys.versions_info compatible list into a 'canonic'
649-
floating-point number which that can then be used to look up a
650-
magic number. Note that this can raise an exception.
737+
The magic bytes value found at the beginning of a bytecode file.
738+
b'?!\r\n' is returned if we can't find a version.
651739
"""
652740

653741
vers_str = version_tuple_to_str(version_info)
@@ -671,7 +759,7 @@ def sysinfo2magic(version_info=sys.version_info) -> bytes:
671759
# just not have platform
672760
pass
673761

674-
return magics[vers_str]
762+
return magics.get(vers_str, b"?!\r\n")
675763

676764

677765
def test() -> None:

xdis/op_imports.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# (C) Copyright 2018-2019, 2021-2023 by Rocky Bernstein
1+
# (C) Copyright 2018-2019, 2021-2023, 2025 by Rocky Bernstein
22
#
33
# This program is free software; you can redistribute it and/or
44
# modify it under the terms of the GNU General Public License
@@ -14,8 +14,6 @@
1414
# along with this program; if not, write to the Free Software
1515
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1616

17-
from ast import Module
18-
1917
"""Facilitates for importing Python opcode maps for a given Python version"""
2018
import copy
2119
import sys
@@ -62,6 +60,7 @@
6260
opcode_311pypy,
6361
opcode_312,
6462
opcode_313,
63+
opcode_314,
6564
)
6665
from xdis.version_info import IS_PYPY, version_tuple_to_str
6766

@@ -95,10 +94,13 @@
9594
2.5: opcode_25,
9695
"2.5.0dropbox": opcode_25,
9796
"2.6a1": opcode_26,
97+
"2.6pypy": opcode_26pypy,
9898
2.6: opcode_26,
9999
"2.7": opcode_27,
100100
2.7: opcode_27,
101101
"2.7.18candidate1": opcode_27,
102+
"2.7pypy": opcode_27pypy,
103+
"2.7.12pypy": opcode_27pypy,
102104
"3.0": opcode_30,
103105
3.0: opcode_30,
104106
"3.0a5": opcode_30,
@@ -108,22 +110,28 @@
108110
"3.2": opcode_32,
109111
"3.2a2": opcode_32,
110112
3.2: opcode_32,
113+
"3.2pypy": opcode_32pypy,
111114
"3.3a4": opcode_33,
112115
3.3: opcode_33,
116+
"3.3pypy": opcode_33pypy,
113117
"3.4": opcode_34,
114118
"3.4rc2": opcode_34,
115119
3.4: opcode_34,
116120
"3.5": opcode_35,
121+
"3.5pypy": opcode_35pypy,
117122
"3.5.1": opcode_35,
118123
"3.5.2": opcode_35,
119124
"3.5.3": opcode_35,
120125
"3.5.4": opcode_35,
121126
3.5: opcode_35,
122127
"3.6rc1": opcode_36,
123128
3.6: opcode_36,
129+
"3.6pypy": opcode_36pypy,
130+
"3.6.1pypy": opcode_36pypy,
124131
"3.7.0beta3": opcode_37,
125132
"3.7.0.beta3": opcode_37,
126133
"3.7.0": opcode_37,
134+
"3.7pypy": opcode_37pypy,
127135
3.7: opcode_37,
128136
"3.8.0alpha0": opcode_38,
129137
"3.8.0a0": opcode_38,
@@ -133,13 +141,27 @@
133141
"3.8.0rc1+": opcode_38,
134142
"3.8.0candidate1": opcode_38,
135143
"3.8": opcode_38,
144+
"3.8.0pypy": opcode_38pypy,
145+
"3.8.12pypy": opcode_38pypy,
146+
"3.8.13pypy": opcode_38pypy,
147+
"3.8.14pypy": opcode_38pypy,
148+
"3.8.15pypy": opcode_38pypy,
149+
"3.8.16pypy": opcode_38pypy,
150+
"3.8.17pypy": opcode_38pypy,
136151
"3.9.0alpha1": opcode_39,
137152
"3.9.0alpha2": opcode_39,
138153
"3.9.0beta5": opcode_39,
139154
"3.9": opcode_39,
155+
"3.9pypy": opcode_39pypy,
156+
"3.9.15pypy": opcode_39pypy,
157+
"3.9.16pypy": opcode_39pypy,
158+
"3.9.17pypy": opcode_39pypy,
159+
"3.9.18pypy": opcode_39pypy,
140160
3.9: opcode_39,
141161
"3.10.0rc2": opcode_310,
142162
"3.10": opcode_310,
163+
"3.10pypy": opcode_310pypy,
164+
"3.10.12pypy": opcode_310pypy,
143165
"3.11": opcode_311,
144166
"3.11.0": opcode_311,
145167
"3.11.1": opcode_311,
@@ -148,34 +170,15 @@
148170
"3.11.4": opcode_311,
149171
"3.11.5": opcode_311,
150172
"3.11a7e": opcode_311,
173+
"3.11.13pypy": opcode_311pypy,
174+
3.11: opcode_311,
151175
"3.12.0rc2": opcode_312,
152176
"3.12.0": opcode_312,
153177
"3.13.0rc3": opcode_313,
154-
"2.6pypy": opcode_26pypy,
155-
"2.7pypy": opcode_27pypy,
156-
"2.7.12pypy": opcode_27pypy,
157-
"3.2pypy": opcode_32pypy,
158-
"3.3pypy": opcode_33pypy,
159-
"3.5pypy": opcode_35pypy,
160-
"3.6pypy": opcode_36pypy,
161-
"3.6.1pypy": opcode_36pypy,
162-
"3.7pypy": opcode_37pypy,
163-
"3.8.0pypy": opcode_38pypy,
164-
"3.8pypy": opcode_38pypy,
165-
"3.8.12pypy": opcode_38pypy,
166-
"3.8.13pypy": opcode_38pypy,
167-
"3.8.14pypy": opcode_38pypy,
168-
"3.8.15pypy": opcode_38pypy,
169-
"3.8.16pypy": opcode_38pypy,
170-
"3.8.17pypy": opcode_38pypy,
171-
"3.9pypy": opcode_39pypy,
172-
"3.9.15pypy": opcode_39pypy,
173-
"3.9.16pypy": opcode_39pypy,
174-
"3.9.17pypy": opcode_39pypy,
175-
"3.9.18pypy": opcode_39pypy,
176-
"3.10pypy": opcode_310pypy,
177-
"3.10.12pypy": opcode_310pypy,
178-
"3.11.13pypy": opcode_311pypy,
178+
"3.14b3": opcode_314,
179+
"3.14.0": opcode_314,
180+
"3.14": opcode_314,
181+
3.14: opcode_314,
179182
}
180183

181184
for k, v in canonic_python_version.items():

0 commit comments

Comments
 (0)