Skip to content

Commit 12df292

Browse files
Merge pull request #166 from MatthieuDartiailh/3.14-support
Python 3.14 support
2 parents 89f2451 + dc7da4d commit 12df292

19 files changed

Lines changed: 789 additions & 222 deletions

.github/workflows/cis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
name: Lint code
2121
runs-on: ubuntu-latest
2222
steps:
23-
- uses: actions/checkout@v4
23+
- uses: actions/checkout@v5
2424
- name: Set up Python
2525
uses: actions/setup-python@v5
2626
with:
@@ -42,8 +42,6 @@ jobs:
4242
fail-fast: false
4343
matrix:
4444
include:
45-
- python-version: "3.8"
46-
toxenv: py38
4745
- python-version: "3.9"
4846
toxenv: py39
4947
- python-version: "3.10"
@@ -54,8 +52,10 @@ jobs:
5452
toxenv: py312
5553
- python-version: "3.13"
5654
toxenv: py313
55+
- python-version: "3.14-dev"
56+
toxenv: py314
5757
steps:
58-
- uses: actions/checkout@v4
58+
- uses: actions/checkout@v5
5959
- name: Get history and tags for SCM versioning to work
6060
run: |
6161
git fetch --prune --unshallow

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
name: Docs building
2020
runs-on: ubuntu-latest
2121
steps:
22-
- uses: actions/checkout@v4
22+
- uses: actions/checkout@v5
2323
- name: Get history and tags for SCM versioning to work
2424
run: |
2525
git fetch --prune --unshallow

.github/workflows/frameworks.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
strategy:
2222
fail-fast: false
2323
matrix:
24-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
24+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
2525

2626
steps:
27-
- uses: actions/checkout@v4
27+
- uses: actions/checkout@v5
2828
with:
2929
fetch-depth: 0
3030

.github/workflows/release.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- name: Checkout
16-
uses: actions/checkout@v4
16+
uses: actions/checkout@v5
1717
- name: Get history and tags for SCM versioning to work
1818
run: |
1919
git fetch --prune --unshallow
@@ -43,7 +43,7 @@ jobs:
4343
runs-on: ubuntu-latest
4444
steps:
4545
- name: Checkout
46-
uses: actions/checkout@v4
46+
uses: actions/checkout@v5
4747
- name: Get history and tags for SCM versioning to work
4848
run: |
4949
git fetch --prune --unshallow
@@ -72,6 +72,11 @@ jobs:
7272
if: github.event_name == 'push'
7373
needs: [build_wheel, build_sdist]
7474
runs-on: ubuntu-latest
75+
environment:
76+
name: pypi
77+
url: https://pypi.org/p/kiwisolver
78+
permissions:
79+
id-token: write
7580
steps:
7681
- name: Download all the dists
7782
uses: actions/download-artifact@v5.0.0
@@ -81,11 +86,6 @@ jobs:
8186
merge-multiple: true
8287

8388
- uses: pypa/gh-action-pypi-publish@release/v1
84-
with:
85-
user: __token__
86-
password: ${{ secrets.pypi_password }}
87-
# To test:
88-
# repository_url: https://test.pypi.org/legacy/
8989

9090
github-release:
9191
name: >-
@@ -107,9 +107,8 @@ jobs:
107107
path: dist
108108
merge-multiple: true
109109
- name: Sign the dists with Sigstore
110-
uses: sigstore/gh-action-sigstore-python@v2.1.0
110+
uses: sigstore/gh-action-sigstore-python@v3.0.1
111111
with:
112-
password: ${{ secrets.pypi_password }}
113112
inputs: >-
114113
./dist/*.tar.gz
115114
./dist/*.whl

doc/changelog.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
ChangeLog
22
=========
33

4+
unreleased: Version 0.17.0
5+
--------------------------
6+
7+
New features:
8+
9+
- Add support for Python 3.14 PR #166
10+
11+
Support for Python 3.14, comes with a number of changes reflecting changes in
12+
CPython bytecode itself:
13+
14+
- introduced an enum for BINARY_OP argument which now supports subscribe.
15+
When disassembling the enum is always used, when creating bytecode from
16+
scratch integer values are coerced into the right enum member.
17+
- support BUILD_TEMPLATE, BUILD_INTERPOLATION, LOAD_SMALL_INT, LOAD_FAST_BORROW
18+
and LOAD_FAST_BORROW_LOAD_FAST_BORROW
19+
- LOAD_COMMON_CONSTANT, LOAD_SPECIAL whose argument is described using dedicated
20+
enums CommonConstant, SpecialMethod
21+
- CONVERT_VALUE (FORMAT_VALUE in Python < 3.13) now use the FormatValue enum.
22+
When disassembling the enum is always used, when creating bytecode from
23+
scratch integer values are coerced into the right enum member.
24+
25+
426
2025-04-14: Version 0.16.2
527
--------------------------
628

pyproject.toml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "bytecode"
33
description = "Python module to generate and modify bytecode"
44
readme = "README.rst"
5-
requires-python = ">=3.8"
5+
requires-python = ">=3.9"
66
license = { file = "COPYING" }
77
authors = [{ name = "Victor Stinner", email = "victor.stinner@gmail.com" }]
88
maintainers = [{ name = "Matthieu C. Dartiailh", email = "m.dartiailh@gmail.com" }]
@@ -13,12 +13,12 @@
1313
"Natural Language :: English",
1414
"Operating System :: OS Independent",
1515
"Programming Language :: Python :: 3",
16-
"Programming Language :: Python :: 3.8",
1716
"Programming Language :: Python :: 3.9",
1817
"Programming Language :: Python :: 3.10",
1918
"Programming Language :: Python :: 3.11",
2019
"Programming Language :: Python :: 3.12",
2120
"Programming Language :: Python :: 3.13",
21+
"Programming Language :: Python :: 3.14",
2222
"Topic :: Software Development :: Libraries :: Python Modules",
2323
]
2424
dependencies = ["typing_extensions;python_version<'3.10'"]
@@ -36,6 +36,18 @@
3636
requires = ["setuptools>=61.2", "wheel", "setuptools_scm[toml]>=3.4.3"]
3737
build-backend = "setuptools.build_meta"
3838

39+
[dependency-groups]
40+
dev = [
41+
"mypy>=1.16.1",
42+
"pytest>=8",
43+
"pytest-cov>=6",
44+
"ruff>=0.12.0",
45+
]
46+
test = [
47+
"pytest>=8",
48+
"pytest-cov",
49+
]
50+
3951
[tool.setuptools_scm]
4052
write_to = "src/bytecode/version.py"
4153
write_to_template = """
@@ -74,7 +86,7 @@ __version__ = "{version}"
7486
extra-standard-library = ["opcode"]
7587

7688
[tool.ruff.lint.mccabe]
77-
max-complexity = 42
89+
max-complexity = 43
7890

7991
[tool.mypy]
8092
follow_imports = "normal"

src/bytecode/concrete.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,25 @@
2626
from bytecode.flags import CompilerFlags
2727
from bytecode.instr import (
2828
_UNSET,
29+
BINARY_OPS,
2930
BITFLAG2_OPCODES,
3031
BITFLAG_OPCODES,
32+
COMMON_CONSTANT_OPS,
3133
DUAL_ARG_OPCODES,
3234
DUAL_ARG_OPCODES_SINGLE_OPS,
35+
FORMAT_VALUE_OPS,
3336
INTRINSIC,
3437
INTRINSIC_1OP,
3538
INTRINSIC_2OP,
3639
PLACEHOLDER_LABEL,
40+
SPECIAL_OPS,
3741
UNSET,
3842
BaseInstr,
43+
BinaryOp,
3944
CellVar,
45+
CommonConstant,
4046
Compare,
47+
FormatValue,
4148
FreeVar,
4249
Instr,
4350
InstrArg,
@@ -46,6 +53,7 @@
4653
Intrinsic2Op,
4754
Label,
4855
SetLineno,
56+
SpecialMethod,
4957
TryBegin,
5058
TryEnd,
5159
_check_arg_int,
@@ -1056,7 +1064,10 @@ def to_bytecode(
10561064
arg = locals_lookup[c_arg]
10571065
elif opcode in _opcode.hasname:
10581066
if opcode in BITFLAG_OPCODES:
1059-
arg = (bool(c_arg & 1), self.names[c_arg >> 1])
1067+
arg = (
1068+
bool(c_arg & 1),
1069+
self.names[c_arg >> 1],
1070+
)
10601071
elif opcode in BITFLAG2_OPCODES:
10611072
arg = (bool(c_arg & 1), bool(c_arg & 2), self.names[c_arg >> 2])
10621073
else:
@@ -1082,6 +1093,20 @@ def to_bytecode(
10821093
arg = Intrinsic1Op(c_arg)
10831094
elif opcode in INTRINSIC_2OP:
10841095
arg = Intrinsic2Op(c_arg)
1096+
elif opcode in BINARY_OPS:
1097+
arg = BinaryOp(c_arg)
1098+
elif opcode in COMMON_CONSTANT_OPS:
1099+
arg = CommonConstant(c_arg)
1100+
elif opcode in SPECIAL_OPS:
1101+
arg = SpecialMethod(c_arg)
1102+
elif opcode in FORMAT_VALUE_OPS:
1103+
if opcode in BITFLAG_OPCODES:
1104+
arg = (
1105+
bool(c_arg & 1),
1106+
FormatValue(c_arg >> 1),
1107+
)
1108+
else:
1109+
arg = FormatValue(c_arg)
10851110
else:
10861111
arg = c_arg
10871112

@@ -1143,7 +1168,7 @@ def to_bytecode(
11431168

11441169

11451170
class _ConvertBytecodeToConcrete:
1146-
# XXX document attributes
1171+
# FIXME document attributes
11471172

11481173
#: Default number of passes of compute_jumps() before giving up. Refer to
11491174
#: assemble_jump_offsets() in compile.c for background.
@@ -1316,9 +1341,13 @@ def concrete_instructions(self) -> None:
13161341
isinstance(arg, tuple)
13171342
and len(arg) == 2
13181343
and isinstance(arg[0], bool)
1319-
and isinstance(arg[1], str)
13201344
), arg
1321-
index = self.add(self.names, arg[1])
1345+
if isinstance(arg[1], str):
1346+
index = self.add(self.names, arg[1])
1347+
elif isinstance(arg, FormatValue):
1348+
index = int(arg)
1349+
else:
1350+
assert False, arg # noqa
13221351
c_arg = int(arg[0]) + (index << 1)
13231352
elif opcode in BITFLAG2_OPCODES:
13241353
assert (

src/bytecode/flags.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import bytecode as _bytecode
77

88
from .instr import DUAL_ARG_OPCODES, CellVar, FreeVar
9-
from .utils import PY311, PY312, PY313
9+
from .utils import PY311, PY312, PY313, PY314
1010

1111

1212
class CompilerFlags(IntFlag):
@@ -48,7 +48,7 @@ class CompilerFlags(IntFlag):
4848
_opcode.opmap["GET_AWAITABLE"],
4949
_opcode.opmap["GET_AITER"],
5050
_opcode.opmap["GET_ANEXT"],
51-
_opcode.opmap["BEFORE_ASYNC_WITH"],
51+
*((_opcode.opmap["BEFORE_ASYNC_WITH"],) if not PY314 else ()), # Removed in 3.14+
5252
*((_opcode.opmap["SETUP_ASYNC_WITH"],) if not PY311 else ()), # Removed in 3.11+
5353
_opcode.opmap["END_ASYNC_FOR"],
5454
*((_opcode.opmap["ASYNC_GEN_WRAP"],) if PY311 and not PY312 else ()), # New in 3.11

0 commit comments

Comments
 (0)