Skip to content

release: 0.25.1 #5191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ jobs:
python-version: ${{ inputs.python-version }}
architecture: ${{ inputs.python-architecture }}
# PyPy can have FFI changes within Python versions, which creates pain in CI
# 3.13.2 also had an ABI break so temporarily add this for 3.13 to ensure that we're using 3.13.3
check-latest: ${{ startsWith(inputs.python-version, 'pypy') || startsWith(inputs.python-version, '3.13') }}
check-latest: ${{ startsWith(inputs.python-version, 'pypy') }}

- name: Install nox
run: python -m pip install --upgrade pip && pip install nox
Expand All @@ -69,6 +68,14 @@ jobs:
run: |
echo "CARGO_BUILD_TARGET=i686-pc-windows-msvc" >> $GITHUB_ENV

# windows on arm image contains x86-64 libclang
- name: Install LLVM and Clang
if: inputs.os == 'windows-11-arm'
uses: KyleMayes/install-llvm-action@v2
with:
# to match windows-2022 images
version: "18"

- name: Install zoneinfo backport for Python 3.7 / 3.8
if: contains(fromJSON('["3.7", "3.8"]'), inputs.python-version)
run: python -m pip install backports.zoneinfo
Expand Down Expand Up @@ -103,6 +110,9 @@ jobs:
- '.github/workflows/build.yml'

- name: Run pyo3-ffi-check
# Python 3.13.4 has an issue on Windows where the headers are configured to always be free-threaded
# https://discuss.python.org/t/heads-up-3-13-5-release-coming-soon/94535
continue-on-error: ${{ inputs.python-version == '3.13' && (inputs.os == 'windows-latest' || inputs.os == 'windows-11-arm') }}
# pypy 3.9 on windows is not PEP 3123 compliant, nor is graalpy
if: ${{ endsWith(inputs.python-version, '-dev') || (steps.ffi-changes.outputs.changed == 'true' && inputs.rust == 'stable' && !startsWith(inputs.python-version, 'graalpy') && !(inputs.python-version == 'pypy3.9' && contains(inputs.os, 'windows'))) }}
run: nox -s ffi-check
Expand Down Expand Up @@ -132,6 +142,8 @@ jobs:

- if: ${{ github.event_name != 'merge_group' }}
name: Generate coverage report
# needs investigation why llvm-cov fails on windows-11-arm
continue-on-error: ${{ inputs.os == 'windows-11-arm' }}
run: cargo llvm-cov
--package=pyo3
--package=pyo3-build-config
Expand All @@ -143,6 +155,8 @@ jobs:
- if: ${{ github.event_name != 'merge_group' }}
name: Upload coverage report
uses: codecov/codecov-action@v5
# needs investigation why llvm-cov fails on windows-11-arm
continue-on-error: ${{ inputs.os == 'windows-11-arm' }}
with:
files: coverage.json
name: ${{ inputs.os }}/${{ inputs.python-version }}/${{ inputs.rust }}
Expand Down
25 changes: 23 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ jobs:
python-architecture: "x86",
rust-target: "i686-pc-windows-msvc",
},
{
os: "windows-11-arm",
python-architecture: "arm64",
rust-target: "aarch64-pc-windows-msvc",
},
]
include:
# Run beta clippy as a way to detect any incoming lints which may affect downstream users
Expand All @@ -154,11 +159,20 @@ jobs:
components: clippy,rust-src
- uses: actions/setup-python@v5
with:
python-version: "3.13"
# FIXME: 3.13.4 has an issue on windows so pinned to 3.13.3
# once 3.13.5 is out, unpin the patch version
python-version: "3.13.3"
architecture: ${{ matrix.platform.python-architecture }}
- uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'CI-save-pr-cache') }}
# windows on arm image contains x86-64 libclang
- name: Install LLVM and Clang
if: matrix.platform.os == 'windows-11-arm'
uses: KyleMayes/install-llvm-action@v2
with:
# to match windows-2022 images
version: "18"
- run: python -m pip install --upgrade pip && pip install nox
- run: nox -s clippy-all
env:
Expand Down Expand Up @@ -385,7 +399,14 @@ jobs:
python-architecture: "arm64",
rust-target: "aarch64-unknown-linux-gnu",
}

- rust: stable
python-version: "3.13"
platform:
{
os: "windows-11-arm",
python-architecture: "arm64",
rust-target: "aarch64-pc-windows-msvc",
}
exclude:
# ubuntu-latest (24.04) no longer supports 3.7
- python-version: "3.7"
Expand Down
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ To see unreleased changes, please see the [CHANGELOG on the main branch guide](h

<!-- towncrier release notes start -->

## [0.25.1] - 2025-06-12
### Packaging

- Add support for Windows on ARM64. [#5145](https://github.com/PyO3/pyo3/pull/5145)
- Add `chrono-local` feature for optional conversions for chrono's `Local` timezone & `DateTime<Local>` instances. [#5174](https://github.com/PyO3/pyo3/pull/5174)

### Added

- Add FFI definition `PyBytes_AS_STRING`. [#5121](https://github.com/PyO3/pyo3/pull/5121)
- Add support for module associated consts introspection. [#5150](https://github.com/PyO3/pyo3/pull/5150)

### Changed

- Enable "vectorcall" FFI definitions on GraalPy. [#5121](https://github.com/PyO3/pyo3/pull/5121)
- Use `Py_Is` function on GraalPy [#5121](https://github.com/PyO3/pyo3/pull/5121)

### Fixed

- Report a better compile error for `async` declarations when not using `experimental-async` feature. [#5156](https://github.com/PyO3/pyo3/pull/5156)
- Fix implementation of `FromPyObject` for `uuid::Uuid` on big-endian architectures. [#5161](https://github.com/PyO3/pyo3/pull/5161)
- Fix segmentation faults on 32-bit x86 with Python 3.14. [#5180](https://github.com/PyO3/pyo3/pull/5180)

## [0.25.0] - 2025-05-14

### Packaging
Expand Down Expand Up @@ -2198,7 +2220,8 @@ Yanked

- Initial release

[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.25.0...HEAD
[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.25.1...HEAD
[0.25.0]: https://github.com/pyo3/pyo3/compare/v0.25.0...v0.25.1
[0.25.0]: https://github.com/pyo3/pyo3/compare/v0.24.2...v0.25.0
[0.24.2]: https://github.com/pyo3/pyo3/compare/v0.24.1...v0.24.2
[0.24.1]: https://github.com/pyo3/pyo3/compare/v0.24.0...v0.24.1
Expand Down
14 changes: 9 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3"
version = "0.25.0"
version = "0.25.1"
description = "Bindings to Python interpreter"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
readme = "README.md"
Expand All @@ -20,10 +20,10 @@ memoffset = "0.9"
once_cell = "1.13"

# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
pyo3-ffi = { path = "pyo3-ffi", version = "=0.25.0" }
pyo3-ffi = { path = "pyo3-ffi", version = "=0.25.1" }

# support crates for macros feature
pyo3-macros = { path = "pyo3-macros", version = "=0.25.0", optional = true }
pyo3-macros = { path = "pyo3-macros", version = "=0.25.1", optional = true }
indoc = { version = "2.0.1", optional = true }
unindent = { version = "0.2.1", optional = true }

Expand All @@ -50,7 +50,8 @@ serde = { version = "1.0", optional = true }
smallvec = { version = "1.0", optional = true }
uuid = { version = "1.11.0", optional = true }
lock_api = { version = "0.4", optional = true }
parking_lot = { version = "0.12", optional = true}
parking_lot = { version = "0.12", optional = true }
iana-time-zone = { version = "0.1", optional = true, features = ["fallback"]}

[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
portable-atomic = "1.0"
Expand All @@ -73,7 +74,7 @@ uuid = { version = "1.10.0", features = ["v4"] }
parking_lot = { version = "0.12.3", features = ["arc_lock"]}

[build-dependencies]
pyo3-build-config = { path = "pyo3-build-config", version = "=0.25.0", features = ["resolve-config"] }
pyo3-build-config = { path = "pyo3-build-config", version = "=0.25.1", features = ["resolve-config"] }

[features]
default = ["macros"]
Expand Down Expand Up @@ -121,6 +122,8 @@ py-clone = []
parking_lot = ["dep:parking_lot", "lock_api"]
arc_lock = ["lock_api", "lock_api/arc_lock", "parking_lot?/arc_lock"]

chrono-local = ["chrono/clock", "dep:iana-time-zone"]

# Optimizes PyObject to Vec conversion and so on.
nightly = []

Expand All @@ -133,6 +136,7 @@ full = [
"arc_lock",
"bigdecimal",
"chrono",
"chrono-local",
"chrono-tz",
"either",
"experimental-async",
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ name = "string_sum"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.25.0", features = ["extension-module"] }
pyo3 = { version = "0.25.1", features = ["extension-module"] }
```

**`src/lib.rs`**
Expand Down Expand Up @@ -140,7 +140,7 @@ Start a new project with `cargo new` and add `pyo3` to the `Cargo.toml` like th

```toml
[dependencies.pyo3]
version = "0.25.0"
version = "0.25.1"
features = ["auto-initialize"]
```

Expand Down Expand Up @@ -182,9 +182,14 @@ about this topic.
- [rustimport](https://github.com/mityax/rustimport) _Directly import Rust files or crates from Python, without manual compilation step. Provides pyo3 integration by default and generates pyo3 binding code automatically._
- [pyo3-arrow](https://crates.io/crates/pyo3-arrow) _Lightweight [Apache Arrow](https://arrow.apache.org/) integration for pyo3._
- [pyo3-bytes](https://crates.io/crates/pyo3-bytes) _Integration between [`bytes`](https://crates.io/crates/bytes) and pyo3._
- [pyo3-object_store](https://github.com/developmentseed/obstore/tree/main/pyo3-object_store) _Integration between [`object_store`](https://docs.rs/object_store) and [`pyo3`](https://github.com/PyO3/pyo3)._

## Examples

- [arro3](https://github.com/kylebarron/arro3) _A minimal Python library for Apache Arrow, connecting to the Rust arrow crate._
- [arro3-compute](https://github.com/kylebarron/arro3/tree/main/arro3-compute) _`arro3-compute`_
- [arro3-core](https://github.com/kylebarron/arro3/tree/main/arro3-core) _`arro3-core`_
- [arro3-io](https://github.com/kylebarron/arro3/tree/main/arro3-io) _`arro3-io`_
- [bed-reader](https://github.com/fastlmm/bed-reader) _Read and write the PLINK BED format, simply and efficiently._
- Shows Rayon/ndarray::parallel (including capturing errors, controlling thread num), Python types to Rust generics, Github Actions
- [blake3-py](https://github.com/oconnor663/blake3-py) _Python bindings for the [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) cryptographic hash function._
Expand All @@ -199,6 +204,7 @@ about this topic.
- [fastuuid](https://github.com/thedrow/fastuuid/) _Python bindings to Rust's UUID library._
- [feos](https://github.com/feos-org/feos) _Lightning fast thermodynamic modeling in Rust with fully developed Python interface._
- [forust](https://github.com/jinlow/forust) _A lightweight gradient boosted decision tree library written in Rust._
- [geo-index](https://github.com/kylebarron/geo-index) _A Rust crate and [Python library](https://github.com/kylebarron/geo-index/tree/main/python) for packed, immutable, zero-copy spatial indexes._
- [granian](https://github.com/emmett-framework/granian) _A Rust HTTP server for Python applications._
- [haem](https://github.com/BooleanCat/haem) _A Python library for working on Bioinformatics problems._
- [html2text-rs](https://github.com/deedy5/html2text_rs) _Python library for converting HTML to markup or plain text._
Expand All @@ -207,6 +213,7 @@ about this topic.
- [johnnycanencrypt](https://github.com/kushaldas/johnnycanencrypt) OpenPGP library with Yubikey support.
- [jsonschema](https://github.com/Stranger6667/jsonschema/tree/master/crates/jsonschema-py) _A high-performance JSON Schema validator for Python._
- [mocpy](https://github.com/cds-astro/mocpy) _Astronomical Python library offering data structures for describing any arbitrary coverage regions on the unit sphere._
- [obstore](https://github.com/developmentseed/obstore) _The simplest, highest-throughput Python interface to Amazon S3, Google Cloud Storage, Azure Storage, & other S3-compliant APIs, powered by Rust._
- [opendal](https://github.com/apache/opendal/tree/main/bindings/python) _A data access layer that allows users to easily and efficiently retrieve data from various storage services in a unified way._
- [orjson](https://github.com/ijl/orjson) _Fast Python JSON library._
- [ormsgpack](https://github.com/aviramha/ormsgpack) _Fast Python msgpack library._
Expand Down
2 changes: 1 addition & 1 deletion examples/decorator/.template/pre-script.rhai
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
variable::set("PYO3_VERSION", "0.25.0");
variable::set("PYO3_VERSION", "0.25.1");
file::rename(".template/Cargo.toml", "Cargo.toml");
file::rename(".template/pyproject.toml", "pyproject.toml");
file::delete(".template");
2 changes: 1 addition & 1 deletion examples/maturin-starter/.template/pre-script.rhai
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
variable::set("PYO3_VERSION", "0.25.0");
variable::set("PYO3_VERSION", "0.25.1");
file::rename(".template/Cargo.toml", "Cargo.toml");
file::rename(".template/pyproject.toml", "pyproject.toml");
file::delete(".template");
2 changes: 1 addition & 1 deletion examples/plugin/.template/pre-script.rhai
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
variable::set("PYO3_VERSION", "0.25.0");
variable::set("PYO3_VERSION", "0.25.1");
file::rename(".template/Cargo.toml", "Cargo.toml");
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
file::delete(".template");
2 changes: 1 addition & 1 deletion examples/setuptools-rust-starter/.template/pre-script.rhai
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
variable::set("PYO3_VERSION", "0.25.0");
variable::set("PYO3_VERSION", "0.25.1");
file::rename(".template/Cargo.toml", "Cargo.toml");
file::rename(".template/setup.cfg", "setup.cfg");
file::delete(".template");
2 changes: 1 addition & 1 deletion examples/word-count/.template/pre-script.rhai
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
variable::set("PYO3_VERSION", "0.25.0");
variable::set("PYO3_VERSION", "0.25.1");
file::rename(".template/Cargo.toml", "Cargo.toml");
file::rename(".template/pyproject.toml", "pyproject.toml");
file::delete(".template");
6 changes: 3 additions & 3 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ enum HttpResponse {
}

// PyO3 also supports enums with Struct and Tuple variants
// These complex enums have sligtly different behavior from the simple enums above
// These complex enums have slightly different behavior from the simple enums above
// They are meant to work with instance checks and match statement patterns
// The variants can be mixed and matched
// Struct variants have named fields while tuple enums generate generic names for fields in order _0, _1, _2, ...
Expand Down Expand Up @@ -825,7 +825,7 @@ impl MyClass {

## Classes as function arguments

Free functions defined using `#[pyfunction]` interact with classes through the same mechanisms as the self parameters of instance methods, i.e. they can take GIL-bound references, GIL-bound reference wrappers or GIL-indepedent references:
Free functions defined using `#[pyfunction]` interact with classes through the same mechanisms as the self parameters of instance methods, i.e. they can take GIL-bound references, GIL-bound reference wrappers or GIL-independent references:

```rust,no_run
# #![allow(dead_code)]
Expand Down Expand Up @@ -857,7 +857,7 @@ fn increment_then_print_field(my_class: &Bound<'_, MyClass>) {
println!("{}", my_class.borrow().my_field);
}

// Take a GIL-indepedent reference when you want to store the reference elsewhere.
// Take a GIL-independent reference when you want to store the reference elsewhere.
#[pyfunction]
fn print_refcnt(my_class: Py<MyClass>, py: Python<'_>) {
println!("{}", my_class.get_refcnt(py));
Expand Down
8 changes: 4 additions & 4 deletions guide/src/class/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ To automatically generate the `__str__` implementation using a `Display` trait i
# use pyo3::prelude::*;
#
# #[allow(dead_code)]
# #[pyclass(str)]
# struct Coordinate {
#[pyclass(str)]
struct Coordinate {
x: i32,
y: i32,
z: i32,
Expand All @@ -104,8 +104,8 @@ For convenience, a shorthand format string can be passed to `str` as `str="<form
# use pyo3::prelude::*;
#
# #[allow(dead_code)]
# #[pyclass(str="({x}, {y}, {z})")]
# struct Coordinate {
#[pyclass(str="({x}, {y}, {z})")]
struct Coordinate {
x: i32,
y: i32,
z: i32,
Expand Down
4 changes: 2 additions & 2 deletions guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ Additionally `IntoPyObject` can be derived for a reference to a struct or enum u
##### `#[derive(IntoPyObject)]`/`#[derive(IntoPyObjectRef)]` Field Attributes
- `pyo3(into_py_with = ...)`
- apply a custom function to convert the field from Rust into Python.
- the argument must be the function indentifier
- the argument must be the function identifier
- the function signature must be `fn(Cow<'_, T>, Python<'py>) -> PyResult<Bound<'py, PyAny>>` where `T` is the Rust type of the argument.
- `#[derive(IntoPyObject)]` will invoke the function with `Cow::Owned`
- `#[derive(IntoPyObjectRef)]` will invoke the function with `Cow::Borrowed`
Expand Down Expand Up @@ -650,7 +650,7 @@ struct MyPyObjectWrapper(PyObject);
impl<'py> IntoPyObject<'py> for MyPyObjectWrapper {
type Target = PyAny; // the Python type
type Output = Bound<'py, Self::Target>; // in most cases this will be `Bound`
type Error = std::convert::Infallible; // the conversion error type, has to be convertable to `PyErr`
type Error = std::convert::Infallible; // the conversion error type, has to be convertible to `PyErr`

fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
Ok(self.0.into_bound(py))
Expand Down
2 changes: 1 addition & 1 deletion guide/src/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ For more information about how to use both `lldb` and `gdb` you can read the [gd

### Debugger specific setup

Depeding on your OS and your preferences you can use two different debuggers, `rust-gdb` or `rust-lldb`.
Depending on your OS and your preferences you can use two different debuggers, `rust-gdb` or `rust-lldb`.

{{#tabs }}
{{#tab name="Using rust-gdb" }}
Expand Down
6 changes: 5 additions & 1 deletion guide/src/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ This feature was introduced to ease migration. It was found that delayed referen

### `pyo3_disable_reference_pool`

This is a performance-oriented conditional compilation flag, e.g. [set via `$RUSTFLAGS`][set-configuration-options], which disabled the global reference pool and the assocaited overhead for the crossing the Python-Rust boundary. However, if enabled, `Drop`ping an instance of `Py<T>` without the GIL being held will abort the process.
This is a performance-oriented conditional compilation flag, e.g. [set via `$RUSTFLAGS`][set-configuration-options], which disabled the global reference pool and the associated overhead for the crossing the Python-Rust boundary. However, if enabled, `Drop`ping an instance of `Py<T>` without the GIL being held will abort the process.

### `macros`

Expand Down Expand Up @@ -138,6 +138,10 @@ Adds a dependency on [chrono](https://docs.rs/chrono). Enables a conversion from
- [NaiveTime](https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html) -> [`PyTime`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyTime.html)
- [DateTime](https://docs.rs/chrono/latest/chrono/struct.DateTime.html) -> [`PyDateTime`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyDateTime.html)

### `chrono-local`

Enables conversion from and to [Local](https://docs.rs/chrono/latest/chrono/struct.Local.html) timezones.

### `chrono-tz`

Adds a dependency on [chrono-tz](https://docs.rs/chrono-tz).
Expand Down
4 changes: 2 additions & 2 deletions guide/src/free-threading.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ GIL-enabled build instead ask the interpreter to attach the thread to the Python
runtime, and there can be many threads simultaneously attached. See [PEP
703](https://peps.python.org/pep-0703/#thread-states) for more background about
how threads can be attached and detached from the interpreter runtime, in a
manner analagous to releasing and acquiring the GIL in the GIL-enabled build.
manner analogous to releasing and acquiring the GIL in the GIL-enabled build.

In the GIL-enabled build, PyO3 uses the [`Python<'py>`] type and the `'py`
lifetime to signify that the global interpreter lock is held. In the
Expand Down Expand Up @@ -289,7 +289,7 @@ GIL-enabled build.

If, for example, the function executed by [`GILOnceCell`] releases the GIL or
calls code that releases the GIL, then it is possible for multiple threads to
race to initialize the cell. While the cell will only ever be intialized
race to initialize the cell. While the cell will only ever be initialized
once, it can be problematic in some contexts that [`GILOnceCell`] does not block
like the standard library [`OnceLock`].

Expand Down
Loading
Loading