0

I have a rust struct with which I had implemented python's magic methods __iter__, __next__, and __call__.

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

Here are the implementations:

#[pymethods]
impl PyNRICContainer {

    #[new]
    #[pyo3(signature = "(cls, value, values)")]
    fn new() -> PyResult<PyNRICContainer> {
        Ok(PyNRICContainer { boolean: true })
    }

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

    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.")
        }
    }


    #[classmethod]
    fn __call__(&mut self, py: Python<'_>, value: &PyString, values: Option<&PyDict>) -> PyResult<PyNRIC> {
        let v: String = value.extract()?;
        PyNRIC::new(v)
    }
    
}

With this, I enabled the behavior of yield this object through the following python codes.

g = PyNRICContainer()
gs = (
      *(g if g else ()),
  )
  print("gs", gs)

The output of the above snippet is:

gs (<builtins.PyNRICContainer object at 0x0000021250B37650>,)

Now, as inspect.signature method cannot get a signature out of g in the above snippet, it raises a ValueError shown below.

ValueError: callable <builtins.PyNRICContainer object at 0x0000021250B37650> is not supported by signature

In the pyo3's documentations, there is a mention of the macro #[pyo3(text_signature)], I tried to implement it above the fn __call__ but it couldn't compile as:

error: `text_signature` cannot be used with `__call__`

My objective is to have a python callable object which is also 'yieldable', i.e. I should be able to yield the object, e.g. yield g in a function or using to * operator to unpack the function from which g was yielded.

E.g.

def yield_g():
    yield g

gs = (
    *(yield_g() if yield_g else None),
)

And it should output something like (g,). I have also tried printing type(g).text_signature but it gives an AttributeError.

Is it possible to make a pyo3::types::PyFunction a PyIterator such that it is yieldable?

Jim
  • 450
  • 2
  • 10
  • I don't know what you're going for with "yieldable", but I suspect you're misunderstanding something about how `yield` works. – user2357112 Feb 26 '23 at 18:50

0 Answers0