Skip to content

Commit

Permalink
3.13t free-threading compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
ijl committed Oct 29, 2024
1 parent 7aea7da commit 5b69b62
Show file tree
Hide file tree
Showing 29 changed files with 523 additions and 280 deletions.
47 changes: 26 additions & 21 deletions .github/workflows/artifact.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ jobs:

- run: python3 -m pip install --user -r test/requirements.txt -r integration/requirements.txt mypy

- run: pytest -s -rxX -v -n 4 test
- run: pytest -v test
env:
PYTHONMALLOC: "debug"

- run: ./integration/run thread
- run: ./integration/run concurrent
- run: ./integration/run http
- run: ./integration/run init
- run: ./integration/run typestubs
Expand All @@ -64,6 +64,14 @@ jobs:
strategy:
fail-fast: false
matrix:
python: [
{ interpreter: 'python3.13t', package: 'python3.13-freethreading', compatibility: "manylinux_2_34" },
{ interpreter: 'python3.13', package: 'python3.13', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.12', package: 'python3.12', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.11', package: 'python3.11', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.10', package: 'python3.10', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.9', package: 'python3.9', compatibility: "manylinux_2_17" },
]
arch: [
{
cc: "clang",
Expand All @@ -75,13 +83,6 @@ jobs:
target: "x86_64-unknown-linux-gnu",
},
]
python: [
{ interpreter: 'python3.13', package: 'python3.13', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.12', package: 'python3.12', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.11', package: 'python3.11', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.10', package: 'python3.10', compatibility: "manylinux_2_17" },
{ interpreter: 'python3.9', package: 'python3.9', compatibility: "manylinux_2_17" },
]
env:
PYTHON: "${{ matrix.python.interpreter }}"
PYTHON_PACKAGE: "${{ matrix.python.package }}"
Expand Down Expand Up @@ -126,6 +127,8 @@ jobs:
./script/install-fedora
source "${VENV}/bin/activate"
export ORJSON_ENABLE_FREETHREADING="$(script/is_freethreading)"
if [[ $ORJSON_ENABLE_FREETHREADING -eq 1 ]]; then export PYTHON_GIL=0; fi
maturin build --release --strip \
--features="${FEATURES}" \
Expand All @@ -135,8 +138,8 @@ jobs:
uv pip install ${CARGO_TARGET_DIR}/wheels/orjson*.whl
pytest -s -rxX -v -n 4 test
./integration/run thread
pytest -v test
./integration/run concurrent
./integration/run http
./integration/run init
Expand All @@ -158,6 +161,10 @@ jobs:
strategy:
fail-fast: false
matrix:
python: [
{ interpreter: 'python3.13t', package: 'python3.13-freethreading', compatibility: "manylinux_2_34" },
{ interpreter: 'python3.13', package: 'python3.13', compatibility: "manylinux_2_17" },
]
arch: [
{
cc: "clang",
Expand All @@ -169,9 +176,6 @@ jobs:
target: "aarch64-unknown-linux-gnu",
},
]
python: [
{ interpreter: 'python3.13', package: 'python3.13', compatibility: "manylinux_2_17" },
]
env:
PYTHON: "${{ matrix.python.interpreter }}"
PYTHON_PACKAGE: "${{ matrix.python.package }}"
Expand Down Expand Up @@ -214,8 +218,9 @@ jobs:
./script/install-fedora
source "${HOME}/.cargo/env"
source "${VENV}/bin/activate"
export ORJSON_ENABLE_FREETHREADING="$(script/is_freethreading)"
if [[ $ORJSON_ENABLE_FREETHREADING -eq 1 ]]; then export PYTHON_GIL=0; fi
maturin build --release --strip \
--features="${FEATURES}" \
Expand All @@ -225,7 +230,7 @@ jobs:
uv pip install ${CARGO_TARGET_DIR}/wheels/orjson*.whl
pytest -s -rxX -v -n 2 test
pytest -v test
cp ${CARGO_TARGET_DIR}/wheels/orjson*.whl dist
Expand Down Expand Up @@ -302,7 +307,7 @@ jobs:
venv/bin/pip install -U pip wheel
venv/bin/pip install -r test/requirements.txt
venv/bin/pip install orjson --no-index --find-links dist/ --force-reinstall
venv/bin/python -m pytest -s -rxX -v -n 2 test
venv/bin/python -m pytest -v test
- name: Store wheels
if: "startsWith(github.ref, 'refs/tags/')"
Expand Down Expand Up @@ -441,11 +446,11 @@ jobs:
--target=universal2-apple-darwin
uv pip install target/wheels/orjson*.whl
- run: pytest -s -rxX -v -n 3 test
- run: pytest -v test
env:
PYTHONMALLOC: "debug"

- run: source .venv/bin/activate && ./integration/run thread
- run: source .venv/bin/activate && ./integration/run concurrent
- run: source .venv/bin/activate && ./integration/run http
- run: source .venv/bin/activate && ./integration/run init

Expand Down Expand Up @@ -510,11 +515,11 @@ jobs:
--target=universal2-apple-darwin
uv pip install target/wheels/orjson*.whl
- run: pytest -s -rxX -v -n 3 test
- run: pytest -v test
env:
PYTHONMALLOC: "debug"

- run: source .venv/bin/activate && ./integration/run thread
- run: source .venv/bin/activate && ./integration/run concurrent
- run: source .venv/bin/activate && ./integration/run http
- run: source .venv/bin/activate && ./integration/run init

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/debug.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
env:
PYTHONMALLOC: "debug"

- run: ./integration/run thread
- run: ./integration/run concurrent
timeout-minutes: 2

- run: ./integration/run http
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ unwind = ["unwinding"]
yyjson = []

# Features detected by build.rs. Do not specify.
freethreading = []
inline_int = []
intrinsics = []
optimize = []
Expand Down
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ and i686/x86 wheels for Windows.
orjson does not and will not support PyPy, embedded Python builds for
Android/iOS, or PEP 554 subinterpreters.

orjson has experimental support for PEP 703 free-threading CPython.

Releases follow semantic versioning and serializing a new object type
without an opt-in flag is considered a breaking change.

Expand Down Expand Up @@ -74,9 +76,10 @@ available in the repository.
1. [Latency](https://github.com/ijl/orjson?tab=readme-ov-file#latency)
2. [Memory](https://github.com/ijl/orjson?tab=readme-ov-file#memory)
3. [Reproducing](https://github.com/ijl/orjson?tab=readme-ov-file#reproducing)
5. [Questions](https://github.com/ijl/orjson?tab=readme-ov-file#questions)
6. [Packaging](https://github.com/ijl/orjson?tab=readme-ov-file#packaging)
7. [License](https://github.com/ijl/orjson?tab=readme-ov-file#license)
6. [Free-threading](https://github.com/ijl/orjson?tab=readme-ov-file#free-threading)
7. [Questions](https://github.com/ijl/orjson?tab=readme-ov-file#questions)
8. [Packaging](https://github.com/ijl/orjson?tab=readme-ov-file#packaging)
9. [License](https://github.com/ijl/orjson?tab=readme-ov-file#license)

## Usage

Expand Down Expand Up @@ -161,7 +164,8 @@ serializing subclasses, specify the option `orjson.OPT_PASSTHROUGH_SUBCLASS`.

The output is a `bytes` object containing UTF-8.

The global interpreter lock (GIL) is held for the duration of the call.
In non-free-threading Python, the global interpreter lock (GIL) is held for
the duration of the call.

It raises `JSONEncodeError` on an unsupported type. This exception message
describes the invalid object with the error message
Expand Down Expand Up @@ -630,7 +634,8 @@ orjson maintains a cache of map keys for the duration of the process. This
causes a net reduction in memory usage by avoiding duplicate strings. The
keys must be at most 64 bytes to be cached and 2048 entries are stored.

The global interpreter lock (GIL) is held for the duration of the call.
In non-free-threading Python, the global interpreter lock (GIL) is held for
the duration of the call.

It raises `JSONDecodeError` if given an invalid type or invalid
JSON. This includes if the input contains `NaN`, `Infinity`, or `-Infinity`,
Expand Down Expand Up @@ -1179,6 +1184,22 @@ orjson 3.10.6, ujson 5.10.0, python-rapidson 1.18, and simplejson 3.19.2.
The latency results can be reproduced using the `pybench` and `graph`
scripts. The memory results can be reproduced using the `pymem` script.

## Free-threading

orjson 3.11.0 introduces experimental support for PEP 703 free-threading CPython.

orjson supports an arbitrary number of Python threads concurrently calling the
library. There are no threads or queues internal to the library. There are
no Python critical sections.

PyPI wheels are provided for manylinux amd64 and aarch64.

To build a wheel with free-threading support, see
[packaging](https://github.com/ijl/orjson?tab=readme-ov-file#packaging).

The free-threading implementation does not respect semantic versioning and may
be removed entirely in the future.

## Questions

### Why can't I install it from PyPI?
Expand Down Expand Up @@ -1220,6 +1241,10 @@ The project's own CI tests against `nightly-2024-10-29` and stable 1.72. It
is prudent to pin the nightly version because that channel can introduce
breaking changes.

Building a wheel with freethreading support requires the environmental
variable `ORJSON_ENABLE_FREETHREADING` set during build or the
`--features=freethreading` argument passed to maturin.

orjson is tested for amd64 on Linux and cross-compiles for aarch64, arm7,
ppc64le, and s390x. It is tested for either aarch64 or amd64 on macOS and
cross-compiles for the other, depending on version. For Windows it is
Expand Down
2 changes: 1 addition & 1 deletion bench/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
memory-profiler
memory-profiler; python_version<"3.13"
pandas; python_version<"3.13"
pytest-benchmark
pytest-random-order
Expand Down
8 changes: 8 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ fn main() {
println!("cargo:rerun-if-env-changed=ORJSON_DISABLE_AVX512");
println!("cargo:rerun-if-env-changed=ORJSON_DISABLE_SIMD");
println!("cargo:rerun-if-env-changed=ORJSON_DISABLE_YYJSON");
println!("cargo:rerun-if-env-changed=ORJSON_ENABLE_FREETHREADING");
println!("cargo:rerun-if-env-changed=RUSTFLAGS");
println!("cargo:rustc-check-cfg=cfg(intrinsics)");
println!("cargo:rustc-check-cfg=cfg(optimize)");
Expand All @@ -31,6 +32,13 @@ fn main() {
println!("cargo:rustc-cfg=feature=\"setitem_knownhash\"");
}

let freethreading_env = env::var("ORJSON_ENABLE_FREETHREADING");
if (freethreading_env.is_ok() && freethreading_env.unwrap() == "1")
|| env::var("CARGO_FEATURE_FREETHREADING").is_ok()
{
println!("cargo:rustc-cfg=feature=\"freethreading\"");
}

if let Some(true) = version_check::supports_feature("core_intrinsics") {
println!("cargo:rustc-cfg=feature=\"intrinsics\"");
}
Expand Down
6 changes: 3 additions & 3 deletions ci/azure-win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ steps:
UNSAFE_PYO3_SKIP_VERSION_CHECK: "1"
- script: python.exe -m pip install orjson --no-index --find-links=D:\a\1\s\target\wheels
displayName: install
- script: python.exe -m pytest -s -rxX -v test
- script: python.exe -m pytest -v test
env:
PYTHONMALLOC: "debug"
displayName: pytest
- script: python.exe integration\thread
displayName: thread
- script: python.exe integration\concurrent
displayName: concurrent
- script: python.exe integration\init
displayName: init
- bash: ./ci/deploy /d/a/1/s/target/wheels/*.whl
Expand Down
Loading

0 comments on commit 5b69b62

Please sign in to comment.