PyO3 / PyO3/pyo3

Expose PyEval_EvalCodeEx e.g. as Python::run_ex

Open
#2,281 11 comments 0 reactions 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

I have a use-case where I need to evaluate some code and set args. It would be possible by exposing PyEval_EvalCodeEx e.g. as a Python::run_ex method. Or perhaps call it run_with_args?

I am trying to implement it myself for contribution to pyo3, but I am a little stuck on the correct method signature and type conversions. Here is what I have so far. It is mostly just copied from Python::run_code:

fn run_code_ex(
    self,
    code: &str,
    start: c_int,
    globals: Option<&PyDict>,
    locals: Option<&PyDict>,
    args: Option<&PyTuple>,
    kws: Option<&PyDict>,
    defs: Option<&PyTuple>,
    kwdefs: Option<&PyDict>,
    closure: Option<&PyTuple> // TODO no idea what this is. docs say 'a closure tuple of cells.'
) -> PyResult<&'py PyAny> {
    let code = CString::new(code)?;
    unsafe {
        let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _);
        if mptr.is_null() {
            return Err(PyErr::fetch(self));
        }

        let globals = globals
            .map(AsPyPointer::as_ptr)
            .unwrap_or_else(|| ffi::PyModule_GetDict(mptr));
        let locals = locals.map(AsPyPointer::as_ptr).unwrap_or(globals);

        let args = args.map(AsPyPointer::as_ptr).unwrap_or(std::ptr::null_mut());

        let code_obj = ffi::Py_CompileString(code.as_ptr(), "<string>\0".as_ptr() as _, start);
        if code_obj.is_null() {
            return Err(PyErr::fetch(self));
        }
        let res_ptr = ffi::PyEval_EvalCodeEx(
            code_obj,
            globals,
            locals,
            args, // ERROR: expecting PyObject *const *args
            0, // TODO
            std::ptr::null_mut(), // TODO
            0, // TODO
            std::ptr::null_mut(), // TODO
            0, // TODO
            std::ptr::null_mut(), // TODO
            std::ptr::null_mut(), // TODO
        );
        ffi::Py_DECREF(code_obj);

        self.from_owned_ptr_or_err(res_ptr)
    }
}

The error at the args line looks like this:

    = note: expected raw pointer `*mut *mut pyo3_ffi::PyObject`
               found raw pointer `*mut pyo3_ffi::PyObject`

It seems like I am passing a pointer to the tuple object, but the method is expecting an array of the tuple elements?

A bit of guidance would be appreciated :)

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 from the existing Python::run_code implementation and the PyEval_EvalCodeEx documentation linked in the issue. Check the FFI signature and the conversions needed for the argument tuple, keyword arguments, defaults, keyword defaults, and closure; done means exposing the requested evaluation capability with a settled method signature.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
api
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.