Skip to content

Commit 24ea43a

Browse files
authored
Merge pull request #298 from lonvia/python-free-threading
Add support for GIL-free Python runtimes
2 parents 0b216de + 152f219 commit 24ea43a

28 files changed

+413
-65
lines changed

.github/workflows/ci.yml

Lines changed: 273 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,68 @@ jobs:
8989
python -m build
9090
shell: bash
9191

92+
- name: Set up Python 3.14
93+
uses: actions/setup-python@v5
94+
with:
95+
python-version: "3.14"
96+
allow-prereleases: true
97+
98+
- name: Build package 3.14
99+
run: |
100+
pip install build wheel
101+
python -m build
102+
shell: bash
103+
92104
- name: Upload Artifact
93105
uses: actions/upload-artifact@v4
94106
with:
95107
name: pyosmium-linux-x64-dist
96108
path: dist
97109

110+
build-free-threaded:
111+
runs-on: ubuntu-22.04
112+
113+
steps:
114+
- uses: actions/checkout@v4
115+
116+
- name: Install packages
117+
run: |
118+
sudo apt-get update -y -qq
119+
sudo apt-get install -y -qq libboost-dev libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev pipx
120+
pipx install mypy
121+
pipx inject mypy types-requests
122+
pipx install flake8
123+
124+
- name: Set up Python 3.13t
125+
uses: actions/setup-python@v5
126+
with:
127+
python-version: "3.13t"
128+
129+
- name: Build package 3.13t
130+
run: |
131+
pip install build wheel
132+
python -m build
133+
shell: bash
134+
135+
- name: Set up Python 3.14t
136+
uses: actions/setup-python@v5
137+
with:
138+
python-version: "3.14t"
139+
allow-prereleases: true
140+
141+
- name: Build package 3.14t
142+
run: |
143+
pip install build wheel
144+
python -m build
145+
shell: bash
146+
147+
- name: Upload Artifact
148+
uses: actions/upload-artifact@v4
149+
with:
150+
name: pyosmium-linux-x64-dist-t
151+
path: dist
152+
153+
98154
test-default:
99155
runs-on: ubuntu-22.04
100156
needs: build-default
@@ -136,6 +192,78 @@ jobs:
136192
./osmium-test/bin/pyosmium-get-changes -h
137193
./osmium-test/bin/pyosmium-up-to-date -h
138194
195+
test-314:
196+
runs-on: ubuntu-22.04
197+
needs: build-default
198+
199+
steps:
200+
- uses: actions/checkout@v4
201+
202+
- name: Set up Python 3.14
203+
uses: actions/setup-python@v5
204+
with:
205+
python-version: 3.14
206+
allow-prereleases: true
207+
208+
- uses: actions/download-artifact@v4
209+
with:
210+
name: pyosmium-linux-x64-dist
211+
212+
- name: Install osmium
213+
run: |
214+
pip install virtualenv
215+
virtualenv osmium-test
216+
WHEEL=`ls osmium*314-*.whl`
217+
./osmium-test/bin/pip install ${WHEEL}
218+
./osmium-test/bin/pip install pytest pytest-httpserver pytest-run-parallel
219+
shell: bash
220+
221+
- name: Run tests
222+
run: ./osmium-test/bin/pytest test
223+
shell: bash
224+
225+
- name: Check tool availability
226+
run: |
227+
./osmium-test/bin/pyosmium-get-changes -h
228+
./osmium-test/bin/pyosmium-up-to-date -h
229+
230+
test-free-threaded:
231+
runs-on: ubuntu-22.04
232+
needs: build-free-threaded
233+
234+
strategy:
235+
fail-fast: false
236+
matrix:
237+
python-version: ["3.13t", "3.14t"]
238+
239+
steps:
240+
- uses: actions/checkout@v4
241+
242+
- name: Set up Python ${{ matrix.python-version }}
243+
uses: actions/setup-python@v5
244+
with:
245+
python-version: ${{ matrix.python-version }}
246+
allow-prereleases: true
247+
248+
- uses: actions/download-artifact@v4
249+
with:
250+
name: pyosmium-linux-x64-dist-t
251+
252+
- name: Install osmium
253+
run: |
254+
pip install virtualenv
255+
virtualenv osmium-test
256+
WHEEL=`ls osmium*${PYVER/./}-*.whl`
257+
./osmium-test/bin/pip install ${WHEEL}
258+
./osmium-test/bin/pip install pytest pytest-httpserver pytest-run-parallel
259+
shell: bash
260+
env:
261+
PYVER: ${{ matrix.python-version }}
262+
263+
- name: Run tests
264+
run: ./osmium-test/bin/pytest test --parallel-threads 10 --iterations 10
265+
shell: bash
266+
139267
build-platform:
140268
runs-on: ${{ matrix.platform }}
141269

@@ -334,20 +462,91 @@ jobs:
334462
env:
335463
CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake
336464

465+
- name: Set up Python 3.14
466+
uses: actions/setup-python@v5
467+
with:
468+
python-version: "3.14"
469+
allow-prereleases: true
470+
471+
- name: Build package 3.14
472+
run: |
473+
pip install build wheel
474+
python -m build
475+
shell: bash
476+
env:
477+
CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake
478+
337479
- name: 'Upload Artifact'
338480
uses: actions/upload-artifact@v4
339481
with:
340482
name: pyosmium-win64-dist
341483
path: dist
342484

485+
build-windows-free-threaded:
486+
runs-on: windows-2022
487+
488+
env:
489+
VCPKG_DEFAULT_BINARY_CACHE: C:/vcpkg_binary_cache
490+
491+
steps:
492+
- uses: actions/checkout@v4
493+
494+
- uses: actions/cache@v4
495+
with:
496+
path: |
497+
C:/vcpkg_binary_cache
498+
key: vcpkg-binary-cache-windows-2022
499+
500+
- name: Prepare cache
501+
run: if [ ! -d C:/vcpkg_binary_cache ]; then mkdir C:/vcpkg_binary_cache; fi
502+
shell: bash
503+
504+
- name: Install packages
505+
run: vcpkg install bzip2:x64-windows expat:x64-windows zlib:x64-windows boost-variant:x64-windows boost-iterator:x64-windows lz4:x86-windows
506+
shell: bash
507+
508+
- name: Set up Python 3.13t
509+
uses: actions/setup-python@v5
510+
with:
511+
python-version: "3.13t"
512+
513+
- name: Build package 3.13t
514+
run: |
515+
pip install build wheel
516+
python -m build
517+
shell: bash
518+
env:
519+
CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake
520+
521+
- name: Set up Python 3.14t
522+
uses: actions/setup-python@v5
523+
with:
524+
python-version: "3.14t"
525+
allow-prereleases: true
526+
527+
- name: Build package 3.14t
528+
run: |
529+
pip install build wheel
530+
python -m build
531+
shell: bash
532+
env:
533+
CMAKE_TOOLCHAIN_FILE: C:/vcpkg/scripts/buildsystems/vcpkg.cmake
534+
535+
- name: 'Upload Artifact'
536+
uses: actions/upload-artifact@v4
537+
with:
538+
name: pyosmium-win64-dist-t
539+
path: dist
540+
541+
343542
test-windows:
344543
runs-on: windows-2022
345544
needs: build-windows
346545

347546
strategy:
348547
fail-fast: false
349548
matrix:
350-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
549+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
351550

352551
env:
353552
PYTEST_ADDOPTS: ${{ matrix.test-args }}
@@ -365,15 +564,28 @@ jobs:
365564
with:
366565
name: pyosmium-win64-dist
367566

368-
- name: Install osmium
567+
- name: Install osmium (with shapely)
369568
run: |
370569
pip install virtualenv
371570
virtualenv osmium-test
372-
WHEEL=`ls osmium*${PYVER/./}*.whl`
571+
WHEEL=`ls osmium*${PYVER/./}-*.whl`
373572
./osmium-test/Scripts/pip install ${WHEEL}[tests]
374573
shell: bash
375574
env:
376575
PYVER: ${{ matrix.python-version }}
576+
if: matrix.python-version != '3.14'
577+
578+
- name: Install osmium (without shapely)
579+
run: |
580+
pip install virtualenv
581+
virtualenv osmium-test
582+
WHEEL=`ls osmium*${PYVER/./}-*.whl`
583+
./osmium-test/Scripts/pip install ${WHEEL}
584+
./osmium-test/Scripts/pip install pytest pytest-httpserver pytest-run-parallel
585+
shell: bash
586+
env:
587+
PYVER: ${{ matrix.python-version }}
588+
if: matrix.python-version == '3.14'
377589

378590
- name: Run tests
379591
run: ./osmium-test/Scripts/pytest test
@@ -384,3 +596,61 @@ jobs:
384596
./osmium-test/Scripts/pyosmium-get-changes -h
385597
./osmium-test/Scripts/pyosmium-up-to-date -h
386598
shell: bash
599+
600+
test-windows-free-threaded:
601+
runs-on: windows-2022
602+
needs: build-windows
603+
604+
strategy:
605+
fail-fast: false
606+
matrix:
607+
python-version: ["3.13t", "3.14t"]
608+
609+
env:
610+
PYTEST_ADDOPTS: ${{ matrix.test-args }}
611+
612+
steps:
613+
- uses: actions/checkout@v4
614+
615+
- name: Set up Python ${{ matrix.python-version }}
616+
uses: actions/setup-python@v5
617+
with:
618+
python-version: ${{ matrix.python-version }}
619+
allow-prereleases: true
620+
621+
- uses: actions/download-artifact@v4
622+
with:
623+
name: pyosmium-win64-dist-t
624+
625+
- name: Install osmium (with shapely)
626+
run: |
627+
pip install virtualenv
628+
virtualenv osmium-test
629+
WHEEL=`ls osmium*${PYVER/./}-*.whl`
630+
./osmium-test/Scripts/pip install ${WHEEL}[tests]
631+
shell: bash
632+
env:
633+
PYVER: ${{ matrix.python-version }}
634+
if: matrix.python-version != '3.14t'
635+
636+
- name: Install osmium (without shapely)
637+
run: |
638+
pip install virtualenv
639+
virtualenv osmium-test
640+
WHEEL=`ls osmium*${PYVER/./}-*.whl`
641+
./osmium-test/Scripts/pip install ${WHEEL}
642+
./osmium-test/Scripts/pip install pytest pytest-httpserver pytest-run-parallel
643+
shell: bash
644+
env:
645+
PYVER: ${{ matrix.python-version }}
646+
if: matrix.python-version == '3.14t'
647+
648+
- name: Run tests
649+
run: ./osmium-test/Scripts/pytest test --parallel-threads 5 --iterations 5
650+
shell: bash
651+
652+
- name: Check tool availability
653+
run: |
654+
./osmium-test/Scripts/pyosmium-get-changes -h
655+
./osmium-test/Scripts/pyosmium-up-to-date -h
656+
shell: bash

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,15 @@ message(STATUS "Building in C++${CMAKE_CXX_STANDARD} mode")
3535

3636
find_package(Python COMPONENTS Interpreter Development)
3737

38+
# Check for abiflags, so we can check for free-threaded later.
39+
execute_process(COMMAND ${Python_EXECUTABLE} -c "import sys; print(sys.abiflags, end='')"
40+
OUTPUT_VARIABLE PYTHON_ABIFLAGS)
41+
3842
if(PYBIND11_PREFIX)
3943
add_subdirectory(${PYBIND11_PREFIX} contrib/pybind11)
44+
elseif(PYTHON_ABIFLAGS STREQUAL "t")
45+
message(STATUS "Free-threading Python found. Enabling support (needs pybind11 2.13+).")
46+
find_package(pybind11 2.13 REQUIRED)
4047
else()
4148
find_package(pybind11 2.9 REQUIRED)
4249
endif()

docs/reference/Thread-Safety.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Thread safety
2+
3+
Object instances of pyosmium are not thread-safe to modify. If you share
4+
objects like an index, you have to protect write accesses to these objects.
5+
Concurrent reads are safe.
6+
7+
The library functions themselves are all reentrant and may be used safely from
8+
different threads.
9+
10+
### Free-threaded Python
11+
12+
Starting with version 4.1, Pyosmium has experimental support for Python
13+
runtimes with GIL disabled. See the
14+
[Python Free-Threading Guide](https://py-free-threading.github.io/)
15+
for more information.
16+
17+
The restrictions mentioned above still apply: write accesses on object need
18+
to be protected by exclusive locks when using them in multi-threaded context.

lib/area.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* This file is part of pyosmium. (https://osmcode.org/pyosmium/)
44
*
5-
* Copyright (C) 2024 Sarah Hoffmann <[email protected]> and others.
5+
* Copyright (C) 2025 Sarah Hoffmann <[email protected]> and others.
66
* For a full list of authors see the git log.
77
*/
88

@@ -127,7 +127,11 @@ class AreaManager : public pyosmium::BaseHandler
127127

128128
} // namespace
129129

130+
#ifdef Py_GIL_DISABLED
131+
PYBIND11_MODULE(area, m, py::mod_gil_not_used())
132+
#else
130133
PYBIND11_MODULE(area, m)
134+
#endif
131135
{
132136
py::class_<AreaManagerSecondPassHandler, pyosmium::BaseHandler>(m,
133137
"AreaManagerSecondPassHandler");

0 commit comments

Comments
 (0)