PyO3 / PyO3/pyo3

Feature request: Support for allowing easily emitting `DeprecationWarning`s from Rust to Python

Open
#4,316 13 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
16.2k
Forks
1k
Avg merge
2d 6h
Merged PRs (30d)
66

Description

Hi!

It would be great if PyO3 supported marking items in the compiled API as deprecated when used from Python.

My main use for PyO3 involves writing library code in Rust and exposing its interface to Python, essentially speeding up Python scripts by several orders of magnitude. Marking API functionality as deprecated is a useful concept, but currently there doesn't seem to be a straightforward way to do it with PyO3 for the functions callable from Python.

If possible, using Rust's existing #[deprecated] attribute for this would be neat. Currently, marking #[pyfunction]s with it causes a Rust-side compile-time deprecation warning, e.g.:

warning: use of deprecated function `pyo3_deprecated::deprecated_with_rust_attribute`
  --> src/lib.rs:10:8
   |
10 |     fn deprecated_with_rust_attribute() -> PyResult<()> {
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default
Example code

pyo3_deprecated/src/lib.rs:

use pyo3::prelude::*;
use pyo3::exceptions::PyDeprecationWarning;

#[pymodule]
mod pyo3_deprecated {
    use super::*;

    #[pyfunction]
    #[deprecated]
    fn deprecated_with_rust_attribute() -> PyResult<()> {
        println!("fn: deprecated_with_rust_attribute");
        Ok(())
    }

    #[pyfunction]
    fn deprecated_by_warning() -> PyResult<()> {
        println!("fn: deprecated_by_warning");
        Python::with_gil(|py| {
            let builtins = py.import_bound("builtins").unwrap();
            let deprecation_warning = builtins.getattr("DeprecationWarning").unwrap();
            let warnings = py.import_bound("warnings").unwrap();
            warnings.getattr("warn")
                .unwrap()
                .call1(("This function is deprecated", deprecation_warning))
                .unwrap();
        });
        Ok(())
    }

    #[pyfunction]
    fn deprecated_by_raising() -> PyResult<()> {
        println!("fn: deprecated_by_raising");
        Err(PyDeprecationWarning::new_err("This function is deprecated"))
    }
}

pyo3_deprecated/script.py:

import pyo3_deprecated

pyo3_deprecated.deprecated_with_rust_attribute()
pyo3_deprecated.deprecated_by_warning()
pyo3_deprecated.deprecated_by_raising()

Output of command python3 script.py:

$ python script.py 
fn: deprecated_with_rust_attribute
fn: deprecated_by_warning
/<redacted>/pyo3_deprecated/script.py:4: DeprecationWarning: This function is deprecated
  pyo3_deprecated.deprecated_by_warning()
fn: deprecated_by_raising
Traceback (most recent call last):
  File "/<redacted>/pyo3_deprecated/script.py", line 5, in <module>
    pyo3_deprecated.deprecated_by_raising()
DeprecationWarning: This function is deprecated

I'm not very familiar with PyO3's code base or CPython's C API, but I guess these resources could be useful:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the example in pyo3_deprecated/src/lib.rs and pyo3_deprecated/script.py to understand the requested Python-facing behavior. Then read CPython's pyport.h macros and PEP 702, as linked in the issue, before tracing how PyO3 exposes #[pyfunction] items. Done means Rust deprecation annotations have a defined, tested effect for Python callers.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.