Skip to content

Commit 4678989

Browse files
authored
add support for 3.13 and 3.14 (#87)
1 parent c7da009 commit 4678989

4 files changed

Lines changed: 42 additions & 15 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ jobs:
5252
run: zig build fmt
5353

5454
python:
55-
name: Python bindings
55+
name: Python ${{ matrix.python }} bindings
5656
runs-on: ubuntu-latest
57+
strategy:
58+
fail-fast: false
59+
matrix:
60+
python: ['3.10', '3.11', '3.12', '3.13', '3.14']
5761

5862
steps:
5963
- name: Check out repository
@@ -62,7 +66,7 @@ jobs:
6266
- name: Set up Python
6367
uses: actions/setup-python@v5
6468
with:
65-
python-version: '3.12'
69+
python-version: ${{ matrix.python }}
6670

6771
- name: Set up Zig
6872
uses: mlugg/setup-zig@v2
@@ -74,11 +78,12 @@ jobs:
7478
run: |
7579
PYTHON_INCLUDE=$(python -c "import sysconfig; print(sysconfig.get_path('include'))")
7680
PYTHON_LIBDIR=$(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
81+
PYTHON_LIB=$(python -c "import sys; print(f'python{sys.version_info.major}.{sys.version_info.minor}')")
7782
echo "Python include: $PYTHON_INCLUDE"
7883
echo "Python libdir: $PYTHON_LIBDIR"
7984
zig build python-bindings \
8085
-Dpython-include="$PYTHON_INCLUDE" \
81-
-Dpython-lib=python3.12 \
86+
-Dpython-lib="$PYTHON_LIB" \
8287
-Dpython-lib-path="$PYTHON_LIBDIR" \
8388
-Doptimize=ReleaseFast
8489

.github/workflows/python.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ jobs:
1414
matrix:
1515
include:
1616
# Linux x86_64
17+
- os: ubuntu-latest
18+
python: '3.14'
19+
target: linux-x86_64
20+
- os: ubuntu-latest
21+
python: '3.13'
22+
target: linux-x86_64
1723
- os: ubuntu-latest
1824
python: '3.12'
1925
target: linux-x86_64
@@ -24,6 +30,12 @@ jobs:
2430
python: '3.10'
2531
target: linux-x86_64
2632
# macOS ARM64
33+
- os: macos-latest
34+
python: '3.14'
35+
target: macos-arm64
36+
- os: macos-latest
37+
python: '3.13'
38+
target: macos-arm64
2739
- os: macos-latest
2840
python: '3.12'
2941
target: macos-arm64

bindings/python/pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ classifiers = [
1414
"Development Status :: 3 - Alpha",
1515
"Intended Audience :: Science/Research",
1616
"Programming Language :: Python :: 3",
17+
"Programming Language :: Python :: 3.10",
18+
"Programming Language :: Python :: 3.11",
19+
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
21+
"Programming Language :: Python :: 3.14",
1722
"Topic :: Scientific/Engineering :: Astronomy",
1823
]
1924
dependencies = [

bindings/python/src/python.zig

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,29 @@ pub const c = @cImport({
77

88
const std = @import("std");
99

10-
/// Zig's translate-c can't handle CPython 3.12+'s ob_refcnt_split union (ziglang/zig#3949).
11-
/// On 3.10/3.11 ob_refcnt is a plain field; on 3.12+ it's inside unnamed_0.
12-
inline fn refcnt(obj: *c.PyObject) *c.Py_ssize_t {
10+
// Zig's translate-c can't handle CPython's ob_refcnt union (ziglang/zig#3949).
11+
// 3.10-3.11 have ob_refcnt as a plain field, 3.12+ need the stable C API
12+
// because the union layout keeps changing across versions.
13+
pub inline fn incref(obj: *c.PyObject) void {
1314
if (@hasField(c.PyObject, "ob_refcnt")) {
14-
return &obj.ob_refcnt;
15+
obj.ob_refcnt += 1;
1516
} else {
16-
return &obj.unnamed_0.ob_refcnt;
17+
c.Py_SET_REFCNT(obj, c.Py_REFCNT(obj) + 1);
1718
}
1819
}
1920

20-
pub inline fn incref(obj: *c.PyObject) void {
21-
refcnt(obj).* += 1;
22-
}
23-
2421
pub inline fn decref(obj: *c.PyObject) void {
25-
refcnt(obj).* -= 1;
26-
if (refcnt(obj).* == 0) {
27-
obj.ob_type.*.tp_dealloc.?(obj);
22+
if (@hasField(c.PyObject, "ob_refcnt")) {
23+
obj.ob_refcnt -= 1;
24+
if (obj.ob_refcnt == 0) {
25+
obj.ob_type.*.tp_dealloc.?(obj);
26+
}
27+
} else {
28+
const n = c.Py_REFCNT(obj) - 1;
29+
c.Py_SET_REFCNT(obj, n);
30+
if (n == 0) {
31+
obj.ob_type.*.tp_dealloc.?(obj);
32+
}
2833
}
2934
}
3035

0 commit comments

Comments
 (0)