Skip to content

Commit c15480d

Browse files
authored
Merge pull request #499 from light-curve/pyo3-v0.24
Free-threading Python support
2 parents 341dcf1 + 8cf5e09 commit c15480d

File tree

8 files changed

+77
-40
lines changed

8 files changed

+77
-40
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
strategy:
3434
fail-fast: false
3535
matrix:
36-
python_minor: [ '9', '10', '11', '12', '13' ]
36+
python_minor: [ '9', '10', '11', '12', '13', '13t' ]
3737
os: [ ubuntu-latest ]
3838
# Just a single ARM worker to be sure that it works
3939
include:
@@ -193,22 +193,10 @@ jobs:
193193
uses: actions/setup-python@v5
194194
with:
195195
python-version: '3.9'
196-
- name: Set up Python 3.10
196+
- name: Set up Python 3.13t
197197
uses: actions/setup-python@v5
198198
with:
199-
python-version: '3.10'
200-
- name: Set up Python 3.11
201-
uses: actions/setup-python@v5
202-
with:
203-
python-version: '3.11'
204-
- name: Set up Python 3.12
205-
uses: actions/setup-python@v5
206-
with:
207-
python-version: '3.12'
208-
- name: Set up Python 3.13
209-
uses: actions/setup-python@v5
210-
with:
211-
python-version: '3.13'
199+
python-version: '3.13t'
212200
- name: Get minimum supported Rust version
213201
run: echo "::set-output name=msrv::$(grep '^rust-version = ' Cargo.toml | grep -o '[0-9.]\+')"
214202
id: get_msrv
@@ -228,4 +216,5 @@ jobs:
228216
- name: Build
229217
run: |
230218
rustup default ${{ steps.get_msrv.outputs.msrv }}
231-
maturin build --find-interpreter
219+
maturin build -i python3.9
220+
maturin build -i python3.13t

CHANGELOG.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12-
--
12+
- Mark the module as no-GIL, which enables free-threading Python (can be built from source, not provided so far) https://github.com/light-curve/light-curve-python/pull/499
1313

1414
### Changed
1515

16-
--
16+
- Bump both `PyO3` and `rust-numpy` to v0.24 https://github.com/light-curve/light-curve-python/pull/499
1717

1818
### Deprecated
1919

@@ -44,7 +44,8 @@ The reason is a bug fixed in 0.10.2.
4444

4545
### Changed
4646

47-
- **Experimental Feature Breaking**: change parameter limits for Rainbow https://github.com/light-curve/light-curve-python/pull/494
47+
- **Experimental Feature Breaking**: change parameter limits for
48+
Rainbow https://github.com/light-curve/light-curve-python/pull/494
4849

4950
### Removed
5051

@@ -53,7 +54,8 @@ The reason is a bug fixed in 0.10.2.
5354

5455
### Fixed
5556

56-
- Rainbow multi-band scaler didn't work with list inputs https://github.com/light-curve/light-curve-python/issues/492 https://github.com/light-curve/light-curve-python/pull/493
57+
- Rainbow multi-band scaler didn't work with list
58+
inputs https://github.com/light-curve/light-curve-python/issues/492 https://github.com/light-curve/light-curve-python/pull/493
5759

5860
## [0.10.0] 2025-01-07
5961

light-curve/Cargo.lock

Lines changed: 15 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

light-curve/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ mimalloc = { version = "0.1.42", features = [
4444
"local_dynamic_tls",
4545
], optional = true }
4646
ndarray = { version = "0.16.1", features = ["rayon"] }
47-
numpy = "0.23.0"
47+
numpy = "0.24.0"
4848
num_cpus = "1.13.0"
4949
num-traits = "0.2"
5050
once_cell = "1"
51-
pyo3 = { version = "0.23.5", features = [
51+
pyo3 = { version = "0.24.0", features = [
5252
"extension-module",
5353
"multiple-pymethods",
5454
] }

light-curve/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ We stopped publishing all PyPy wheels (https://github.com/light-curve/light-curv
5353
and the PPC64le CPython glibc wheel (https://github.com/light-curve/light-curve-python/issues/479),
5454
please feel free to open an issue if you need any of them.
5555

56+
[Free-threading Python](https://docs.python.org/3.13/whatsnew/3.13.html#free-threaded-cpython) is supported when built from source.
57+
No pre-built distributions are provided so far, please comment on these issues if you need them: [PyPI binary wheel issue](https://github.com/light-curve/light-curve-python/issues/500), [conda-forge package issue](https://github.com/conda-forge/light-curve-python-feedstock/issues/11).
58+
5659
See [bellow](#build-from-source) for the details on how to build the package from the source code.
5760

5861
## Feature evaluators

light-curve/pyproject.toml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ dev = [
6262
"black",
6363
"ruff",
6464
]
65+
# cesium and iminuit don't support free-threading yet
66+
dev-free-threading = [
67+
"pytest",
68+
"markdown-pytest",
69+
"pytest-benchmark",
70+
"pytest-subtests>=0.10",
71+
"numpy",
72+
"scipy",
73+
"joblib",
74+
"pandas",
75+
"black",
76+
"ruff",
77+
]
6578

6679
[tool.maturin]
6780
# It asks to use Cargo.lock to make the build reproducible
@@ -148,10 +161,10 @@ markers = [
148161
[tool.tox]
149162
legacy_tox_ini = """
150163
[tox]
151-
envlist = py{39,310,311,312,313}-{base,test}
164+
envlist = py{39,310,311,312,313,313t}-{base,test}
152165
isolated_build = True
153166
154-
[testenv:py{39,310,311,312,313}-base]
167+
[testenv:py{39,310,311,312,313,313t}-base]
155168
change_dir = {envtmpdir}
156169
extras =
157170
commands =
@@ -166,6 +179,17 @@ commands =
166179
ruff check .
167180
set_env =
168181
CARGO_TARGET_DIR = {tox_root}/target
182+
183+
[testenv:py313t-test]
184+
extras = dev-free-threading
185+
commands =
186+
pytest README.md tests/ light_curve/ \
187+
--ignore tests/test_w_bench.py \
188+
--ignore=tests/light_curve_py/features/test_rainbow.py \
189+
--deselect=README.md::test_rainbow_fit_example
190+
ruff check .
191+
set_env =
192+
CARGO_TARGET_DIR = {tox_root}/target
169193
"""
170194

171195

light-curve/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static GLOBAL_ALLOCATOR: MiMalloc = MiMalloc;
2626
///
2727
/// dm-lg(dt) maps generator is represented by `DmDt` class, while all other classes are
2828
/// feature extractors
29-
#[pymodule]
29+
#[pymodule(gil_used = false)]
3030
fn light_curve(py: Python, m: Bound<PyModule>) -> PyResult<()> {
3131
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
3232

light-curve/tests/light_curve_ext/test_feature.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import copy
22
import inspect
33
import pickle
4+
from concurrent.futures import ThreadPoolExecutor
45

56
import numpy as np
67
import pytest
@@ -174,7 +175,24 @@ def test_many_vs_call(feature):
174175

175176
call = np.stack([feature(*lc, sorted=True) for lc in lcs])
176177
many = feature.many(lcs, sorted=True, n_jobs=2)
177-
assert_array_equal(many, call)
178+
assert_array_equal(call, many)
179+
180+
# Test with Python threads to ensure we have no problems on the free-threading CPython
181+
with ThreadPoolExecutor(2) as pool:
182+
futures = [pool.submit(feature, *lc, sorted=True) for lc in lcs]
183+
call_threads = np.stack([f.result() for f in futures])
184+
del futures
185+
assert_array_equal(call, call_threads)
186+
187+
n_lcs_per_job = 4
188+
with ThreadPoolExecutor(2) as pool:
189+
futures = [
190+
pool.submit(feature.many, lcs[i : i + n_lcs_per_job], sorted=True, n_jobs=2)
191+
for i in range(0, n_lc, n_lcs_per_job)
192+
]
193+
many_threads = np.concatenate([f.result() for f in futures])
194+
del futures
195+
assert_array_equal(call, many_threads)
178196

179197

180198
def test_fill_value_not_enough_observations():

0 commit comments

Comments
 (0)