-1

I want a function that simply creates and returns a tuple as an example.

Basic template starting code (maturin new) looks like:

use pyo3::prelude::*;

/// Formats the sum of two numbers as string.
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())
}

/// A Python module implemented in Rust.
#[pymodule]
fn tuple(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
    Ok(())
}

I have tried something like this but can't figure out what combination of things is required to even compile.

#[pyfunction]
fn f_ret_tuple() -> PyResult<&'static PyTuple> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let tuple: &PyTuple;
    let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
    tuple = PyTuple::new(py, elements);
    Ok(tuple)
}
mathtick
  • 6,487
  • 13
  • 56
  • 101
  • What is the error you are getting? Error output needs to be part of your [mcve]. – Herohtar Oct 20 '22 at 21:17
  • @Herhtar I got something to work by googling and copy paste, no idea if it is "correct". Will update and ask for feedback on that. – mathtick Oct 20 '22 at 21:23
  • @Herohtar The error depends on what you try. You need to install rust, pyo3 and try else there is no way to guess merely based on error. I posted one that works now. Looking for feedback on that one. – mathtick Oct 20 '22 at 21:25
  • Updated with the error from that specific first guess. Remember this is a *how* not a "why error" question. "how" meaning what are the various ways and their benefits/costs etc. – mathtick Oct 20 '22 at 21:31
  • The question states, *"I can't figure out what combination of things is required to even compile"* -- that indicates that you are getting a compile error with whatever your "guess" may be, so you need to include your guess (show what you have tried) *and* the error output (show the result). This helps people reading the question more quickly identify the problem. If someone has to set up an entire system and guess at what *your* guesses were, they can't tell what you are specifically having issues with and give an accurate answer. – Herohtar Oct 20 '22 at 21:44

1 Answers1

2

The problem is that the compiler can't prove your tuple will not outlive the GIL acquisition. But per the docs,

In a function or method annotated with #[pyfunction] or #[pymethods] you can declare it as a parameter, and PyO3 will pass in the token when Python code calls it.

So:

#[pyfunction]
fn f_ret_tuple(py: Python<'_>) -> PyResult<&PyTuple> {
    let tuple: &PyTuple;
    let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
    tuple = PyTuple::new(py, elements);
    Ok(tuple)
}
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • 1
    An alternative is to convert the tuple to [a GIL-independent reference](https://docs.rs/pyo3/latest/pyo3/prelude/struct.Py.html). These can exist outside of a GIL scope, but you have to provide a GIL handle in order to manipulate the object itself. – Masklinn Oct 21 '22 at 13:32
  • 2
    @Masklinn This is possible, but redundant since the GIL is anyway acquired. – Chayim Friedman Oct 23 '22 at 05:55