Skip to content

add python 3.15 support - #176

Open
abraaoz wants to merge 3 commits into
psqlpy-python:mainfrom
abraaoz:python-3.15-support
Open

add python 3.15 support#176
abraaoz wants to merge 3 commits into
psqlpy-python:mainfrom
abraaoz:python-3.15-support

Conversation

@abraaoz

@abraaoz abraaoz commented Sep 2, 2026

Copy link
Copy Markdown

Adds CPython 3.15 to the supported versions. Unlike the 3.14 PR (#159), the CI matrix alone is not enough: pyo3 0.25.1 refuses the interpreter outright (the configured Python interpreter version (3.15) is newer than), and PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 does not help, it gets past the version check and then fails to compile (the trait bound PyTime: PyTypeInfo is not satisfied, 4 errors). So this bumps pyo3 0.25.1 -> 0.29 and migrates the code with it.

Migrations applied, all from PyO3's own migration guide

change sites
Python::with_gil -> Python::attach 30
.downcast*() -> .cast*() 6
GILOnceCell -> PyOnceLock 2
FromPyObject<'py> -> FromPyObject<'_, 'py> with type Error and extract(Borrowed<..>) 3 impls
pyo3::PyObject -> Py<PyAny> (alias deprecated) 3 files
conversion::FromPyObjectBound -> FromPyObject 1
TaskLocals::clone_ref -> clone 1

Two that are not renames:

  • rustdriver_future's T gains Send + 'static, which pyo3_async_runtimes::tokio::future_into_py now requires.
  • extract::<T>() on a #[pyclass] returns PyClassGuardError, which RustPSQLDriverError cannot absorb. Converted via PyErr at the two macro sites, since RustPSQLDriverError::RustPyError already carries #[from] pyo3::PyErr.

Verified

Built and installed against CPython 3.15.0rc2 on macOS arm64, then imported:

installed ok
  python: 3.15.0rc2
  psqlpy imported: psqlpy
  ConnectionPool: <class 'builtins.ConnectionPool'>

Your prek hooks pass locally on Rust 1.98.0, which is what ubuntu-latest currently ships, read from their exit codes: cargo fmt --check with your config, cargo clippy -p psqlpy -- -W clippy::all -W clippy::pedantic -D warnings, and cargo check, all 0.

The test suite runs, on 3.15.0rc2, against a real PostgreSQL: 259 passed, 13 failed. All 13 are test_ssl_mode.py, on a server with ssl = off. They are not a regression: the released psqlpy==0.12.1 on 3.14 fails the same 13 against the same server.

Not verified, and worth saying

test_binary_copy.py did not run. It needs pyarrow, which publishes no cp315 wheel and whose source build wants Arrow C++; that is a test-dependency gap in 3.15's ecosystem, not something this branch touches.

The SSL tests were not exercised against a TLS-enabled server, only shown to fail identically with and without this change.

One lint that is new, not broken

Clippy 1.98 adds clippy::unused_async_trait_impl, split out of unused_async, and pyo3 0.29 expands async #[pymethods] as trait impls, so it fires on four functions that already carry #[allow(clippy::unused_async)]. The new name was added beside the old one rather than restructuring those functions into impl Future, since the async there is your choice about the Python-facing API.

One unrelated line

src/statement/query.rs:53 had format!("${}", &counter), which current clippy rejects as a redundant reference. It is not part of this migration and I did not otherwise touch that file, but the hook lints the whole crate, so the branch cannot go green without it. Dropped to format!("${counter}").

Two things for you to decide

pyo3-async-runtimes now points at the released crate (0.29) instead of your fork's psqlpy branch. The fork is pinned to the old pyo3 line and does not build against 0.29; upstream has since published 0.29.0. I do not know what your fork carries that upstream does not, so if that branch holds a patch you need, this dependency line should be rebased instead of replaced. That is your call, not mine.

All 20 #[pyclass] types opted IN to the FromPyObject derive. PyO3 0.29 makes that derive opt-in for #[pyclass] types implementing Clone, and prek runs clippy with -D warnings, so the deprecation is a hard failure rather than a note. Every one of them got from_py_object, which keeps today's behaviour exactly; skip_from_py_object would have removed those conversions from your public API, which is not a migration PR's call to make.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant