From 99509494f350477f9e99daadc59a7aa5e0f8505c Mon Sep 17 00:00:00 2001 From: uncorrelated1 <148440002+uncorrelated1@users.noreply.github.com> Date: Mon, 20 Jul 2026 07:06:21 +1000 Subject: [PATCH] Bump pyo3 to 0.26 to fix segfaults on CPython 3.14 The published cp314 wheels crash with SIGSEGV on any call into the extension (e.g. convert_image_to_svg_py with any input image), because pyo3 0.19 predates CPython 3.14 support and the 3.14 wheels can only have been produced through pyo3's version-forward-compatibility mode, which is not ABI-safe on 3.14. - bump pyo3 0.19 -> 0.26 (supports CPython 3.7+, so no change to the supported-version floor; MSRV 1.74) - add the #[pyo3(signature = ...)] attributes now required for trailing Option arguments, preserving the existing keyword-optional Python API exactly - port the #[pymodule] entry to the Bound API Verified by building cp312 and cp314 wheels from this branch: the 3.14 wheel no longer segfaults, and both produce byte-identical SVG output for the same 1 MP input image. --- cmdapp/Cargo.toml | 2 +- cmdapp/src/python.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmdapp/Cargo.toml b/cmdapp/Cargo.toml index 0ad3636..630ca33 100644 --- a/cmdapp/Cargo.toml +++ b/cmdapp/Cargo.toml @@ -15,7 +15,7 @@ clap = "2.33.3" image = "0.23.10" visioncortex = { version = "0.8.8" } fastrand = { version = "2.3" } -pyo3 = { version = "0.19.0", optional = true } +pyo3 = { version = "0.26", optional = true } [features] python-binding = ["pyo3"] diff --git a/cmdapp/src/python.rs b/cmdapp/src/python.rs index cb83b97..3167e9a 100644 --- a/cmdapp/src/python.rs +++ b/cmdapp/src/python.rs @@ -7,6 +7,7 @@ use visioncortex::PathSimplifyMode; /// Python binding #[pyfunction] +#[pyo3(signature = (image_path, out_path, colormode=None, hierarchical=None, mode=None, filter_speckle=None, color_precision=None, layer_difference=None, corner_threshold=None, length_threshold=None, max_iterations=None, splice_threshold=None, path_precision=None))] fn convert_image_to_svg_py( image_path: &str, out_path: &str, @@ -44,6 +45,7 @@ fn convert_image_to_svg_py( } #[pyfunction] +#[pyo3(signature = (img_bytes, img_format=None, colormode=None, hierarchical=None, mode=None, filter_speckle=None, color_precision=None, layer_difference=None, corner_threshold=None, length_threshold=None, max_iterations=None, splice_threshold=None, path_precision=None))] fn convert_raw_image_to_svg( img_bytes: Vec, img_format: Option<&str>, // Format of the image (e.g. 'jpg', 'png'... A full list of supported formats can be found [here](https://docs.rs/image/latest/image/enum.ImageFormat.html)). If not provided, the image format will be guessed based on its contents. @@ -100,6 +102,7 @@ fn convert_raw_image_to_svg( } #[pyfunction] +#[pyo3(signature = (rgba_pixels, size, colormode=None, hierarchical=None, mode=None, filter_speckle=None, color_precision=None, layer_difference=None, corner_threshold=None, length_threshold=None, max_iterations=None, splice_threshold=None, path_precision=None))] fn convert_pixels_to_svg( rgba_pixels: Vec<(u8, u8, u8, u8)>, size: (usize, usize), @@ -214,7 +217,7 @@ fn construct_config( /// A Python module implemented in Rust. #[pymodule] -fn vtracer(_py: Python, m: &PyModule) -> PyResult<()> { +fn vtracer(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(convert_image_to_svg_py, m)?)?; m.add_function(wrap_pyfunction!(convert_raw_image_to_svg, m)?)?; m.add_function(wrap_pyfunction!(convert_pixels_to_svg, m)?)?;