Skip to content

Commit 3eb1127

Browse files
committed
feat(python): Support PyPy
Signed-off-by: Dmitry Dygalo <[email protected]>
1 parent c452113 commit 3eb1127

File tree

6 files changed

+122
-5
lines changed

6 files changed

+122
-5
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ jobs:
224224
fail-fast: false
225225
matrix:
226226
os: [ubuntu-22.04, macos-15, windows-2022]
227-
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
227+
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', 'pypy3.11']
228228

229229
name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
230230
runs-on: ${{ matrix.os }}

.github/workflows/python-release-verify.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ defaults:
1313
env:
1414
PACKAGE_NAME: jsonschema_rs
1515
PYTHON_VERSION: "3.10"
16+
PYPY_VERSION: "pypy3.11"
1617

1718
jobs:
1819
wheel-smoke-test:
@@ -52,3 +53,49 @@ jobs:
5253
5354
print('Basic validation tests passed!')
5455
"
56+
57+
wheel-smoke-test-pypy:
58+
runs-on: ubuntu-22.04
59+
steps:
60+
- uses: actions/checkout@v5
61+
- name: Install uv and cache PyPy
62+
uses: astral-sh/setup-uv@v7
63+
with:
64+
python-version: ${{ env.PYPY_VERSION }}
65+
enable-cache: true
66+
cache-python: true
67+
cache-suffix: smoke-pypy
68+
69+
- name: Setup PyPy interpreter
70+
run: |
71+
uv python install ${{ env.PYPY_VERSION }}
72+
interp=$(uv python find ${{ env.PYPY_VERSION }})
73+
echo "PYPY_INTERPRETER=$interp" >> "$GITHUB_ENV"
74+
"$interp" --version
75+
76+
- uses: dtolnay/rust-toolchain@stable
77+
78+
- uses: Swatinem/rust-cache@v2
79+
80+
- name: Install maturin
81+
run: uv pip install --python "$PYPY_INTERPRETER" 'maturin>=1,<2'
82+
83+
- name: Build wheel
84+
run: |
85+
"$PYPY_INTERPRETER" -m maturin build --release -m crates/jsonschema-py/Cargo.toml --out dist --interpreter "$PYPY_INTERPRETER"
86+
87+
- name: Install built wheel
88+
run: uv pip install --python "$PYPY_INTERPRETER" dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
89+
90+
- name: Test wheel with basic validation
91+
run: |
92+
"$PYPY_INTERPRETER" - <<'PY'
93+
import jsonschema_rs
94+
95+
schema = {'type': 'object', 'properties': {'name': {'type': 'string'}}}
96+
97+
assert jsonschema_rs.is_valid(schema, {'name': 'test'}), 'Valid instance failed'
98+
assert not jsonschema_rs.is_valid(schema, {'name': 123}), 'Invalid instance passed'
99+
100+
print('PyPy validation tests passed!')
101+
PY

.github/workflows/python-release.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ concurrency:
1717
env:
1818
PACKAGE_NAME: jsonschema_rs
1919
PYTHON_ABI_VERSION: "3.10"
20+
PYPY_VERSION: "pypy3.11"
2021

2122
jobs:
2223
sdist:
@@ -169,6 +170,67 @@ jobs:
169170
name: wheel-linux-${{ matrix.target }}
170171
path: dist
171172

173+
pypy:
174+
runs-on: ${{ matrix.os }}
175+
strategy:
176+
matrix:
177+
include:
178+
- os: macos-13
179+
target: x86_64
180+
artifact: wheel-macos-pypy
181+
manylinux: ''
182+
- os: windows-2022
183+
target: x64
184+
artifact: wheel-windows-pypy
185+
manylinux: ''
186+
- os: ubuntu-22.04
187+
target: x86_64
188+
artifact: wheel-linux-pypy
189+
manylinux: auto
190+
- os: ubuntu-22.04
191+
target: aarch64
192+
artifact: wheel-linux-pypy-aarch64
193+
manylinux: 2_24
194+
195+
steps:
196+
- uses: actions/checkout@v5
197+
- name: Install uv and cache PyPy
198+
uses: astral-sh/setup-uv@v7
199+
with:
200+
python-version: ${{ env.PYPY_VERSION }}
201+
enable-cache: true
202+
cache-python: true
203+
cache-suffix: pypy-${{ matrix.os }}-${{ matrix.target }}
204+
- name: Ensure PyPy interpreter
205+
run: |
206+
uv python install ${{ env.PYPY_VERSION }}
207+
interp=$(uv python find ${{ env.PYPY_VERSION }})
208+
echo "PYPY_INTERPRETER=$interp" >> "$GITHUB_ENV"
209+
"$interp" --version
210+
- uses: dtolnay/rust-toolchain@stable
211+
- name: Build wheels - PyPy (manylinux)
212+
if: ${{ matrix.manylinux != '' }}
213+
uses: messense/maturin-action@v1
214+
with:
215+
target: ${{ matrix.target }}
216+
manylinux: ${{ matrix.manylinux }}
217+
args: --release -m crates/jsonschema-py/Cargo.toml --out dist --interpreter ${{ env.PYPY_INTERPRETER }}
218+
- name: Build wheels - PyPy
219+
if: ${{ matrix.manylinux == '' }}
220+
uses: messense/maturin-action@v1
221+
with:
222+
target: ${{ matrix.target }}
223+
args: --release -m crates/jsonschema-py/Cargo.toml --out dist --interpreter ${{ env.PYPY_INTERPRETER }}
224+
- name: Install built wheel - PyPy
225+
if: ${{ matrix.target != 'aarch64' }}
226+
run: |
227+
uv pip install --python "${{ env.PYPY_INTERPRETER }}" dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
228+
- name: Upload wheels
229+
uses: actions/upload-artifact@v5
230+
with:
231+
name: ${{ matrix.artifact }}
232+
path: dist
233+
172234
release:
173235
name: Release
174236
runs-on: ubuntu-22.04
@@ -178,6 +240,7 @@ jobs:
178240
- macos-universal
179241
- windows
180242
- linux
243+
- pypy
181244
if: "startsWith(github.ref, 'refs/tags/')"
182245
steps:
183246
- uses: actions/download-artifact@v6

crates/jsonschema-py/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- PyPy 3.11 support. [#309](https://github.com/Stranger6667/jsonschema/issues/309)
8+
59
### Changed
610

711
- Migrated to abi3 so a single wheel per platform works on all supported 3.10+ interpreters.

crates/jsonschema-py/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ classifiers = [
2828
"Programming Language :: Python :: 3.13",
2929
"Programming Language :: Python :: 3.14",
3030
"Programming Language :: Python :: Implementation :: CPython",
31+
"Programming Language :: Python :: Implementation :: PyPy",
3132
"Programming Language :: Rust",
3233
"Topic :: File Formats :: JSON :: JSON Schema",
3334
]

crates/jsonschema-py/src/ser.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ use std::borrow::Cow;
1717

1818
#[cfg(not(Py_LIMITED_API))]
1919
use pyo3::ffi::{
20-
PyDictObject, PyFloat_AS_DOUBLE, PyList_GET_ITEM, PyList_GET_SIZE, PyTuple_GET_ITEM,
21-
PyTuple_GET_SIZE,
20+
PyFloat_AS_DOUBLE, PyList_GET_ITEM, PyList_GET_SIZE, PyTuple_GET_ITEM, PyTuple_GET_SIZE,
2221
};
2322

23+
#[cfg(all(not(Py_LIMITED_API), not(PyPy)))]
24+
use pyo3::ffi::PyDictObject;
25+
2426
pub const RECURSION_LIMIT: u8 = 255;
2527

2628
#[derive(Clone, Copy)]
@@ -135,11 +137,11 @@ unsafe fn pytuple_get_item(
135137

136138
#[inline]
137139
unsafe fn dict_len(object: *mut pyo3::ffi::PyObject) -> usize {
138-
#[cfg(Py_LIMITED_API)]
140+
#[cfg(any(Py_LIMITED_API, PyPy))]
139141
{
140142
pyo3::ffi::PyDict_Size(object) as usize
141143
}
142-
#[cfg(not(Py_LIMITED_API))]
144+
#[cfg(all(not(Py_LIMITED_API), not(PyPy)))]
143145
{
144146
(*object.cast::<PyDictObject>()).ma_used as usize
145147
}

0 commit comments

Comments
 (0)