PyO3 / pyo3

Rust bindings for the Python interpreter
https://pyo3.rs
Apache License 2.0
12.31k stars 759 forks source link

`#[pyclass]` with `__call__` raises `ValueError` with `inspect.signature` #2992

Open jymchng opened 1 year ago

jymchng commented 1 year ago

I implemented the PyNRICContainer struct in Rust with the following methods __iter__, __next__ and __call__. I have also annotated PyNRICContainer with the #[pyo3(text_signature=...)] macro with an appropriate text_signature. The __call__ method is not allowed to have a text_signature annotation but I annotated it with a #[pyo3(signature=...)] annotation. The error I got from passing the callable object into the function signature of the inspect module (i.e. inspect.signature(pycallableobj)) is a ValueError that reads ''callable is not supported by signature'"

Here are the codes:

#[pyclass(name = "PyNRICContainer")]
#[derive(Debug)]
#[pyo3(text_signature = "(cls, value, values, config, field)")]
pub struct PyNRICContainer {
    #[pyo3(get, set)]
    boolean: bool,
}

#[pymethods]
impl PyNRICContainer {

    #[new]
    pub fn new() -> PyResult<PyNRICContainer> {
        Ok(PyNRICContainer { boolean: true })
    }

    pub fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
        slf
    }

    pub fn __next__(mut slf: PyRefMut<'_, Self>) -> IterNextOutput<PyRefMut<'_, Self>, &'static str> {
        if slf.boolean {
            slf.boolean = false;
            IterNextOutput::Yield(slf)
        } else {
            IterNextOutput::Return("No Longer Iterable.")
        }
    }

    #[pyo3(signature="(cls, value, values, config, field)")]
    pub fn __call__(value: &PyString, values: &PyDict, config: &PyAny, field: &PyAny) -> PyResult<PyNRIC> {
        let v: String = value.extract()?;
        PyNRIC::new(v)
    }

}

My question is, how to make callable objects compatible with the inspect.signature function? Or rather, is there a way to force the __call__ method implemented in rust to have a text_signature?

davidhewitt commented 1 year ago

I took a brief look at this, and my conclusion is that __call__ for a native type like in PyO3 isn't currently supported by inspect.

The error comes from: https://github.com/python/cpython/blob/d01cf5072be5511595b6d0c35ace6c1b07716f8d/Lib/inspect.py#L2616

None of the options supported by that method seem applicable for the __call__ method. I think this probably needs upstream support.

jymchng commented 1 year ago

Hi @davidhewitt, thank you for spending your time and looking at this issue.

Can I ask what do you mean by upstream? Do you mean pyo3 or is there a dependency to which I should raise this issue to?

👍😂

adamreichold commented 1 year ago

"upstream" in this case would the Python interpreter itself, i.e. CPython at https://github.com/python/cpython