Rust 使用cpython板条箱导入Python模块时发生ModuleNotFoundError

Rust 使用cpython板条箱导入Python模块时发生ModuleNotFoundError,rust,cpython,Rust,Cpython,我写了防锈代码: myapp/src/main.rs 并将Python模块保存为myapp/pyth/fibo.py 但我得到了一个错误: 线程“main”在“Err”值上调用“Result::unwrap”时惊慌失措:PyErr{ptype:,pvvalue:SomeModuleNotFoundErrorNo名为“fibo”的模块,ptraceback:None},libcore/Result.rs:945:5 我希望知道的关于目录pyth的代码部分是:let module=cpython::

我写了防锈代码:

myapp/src/main.rs

并将Python模块保存为myapp/pyth/fibo.py

但我得到了一个错误:

线程“main”在“Err”值上调用“Result::unwrap”时惊慌失措:PyErr{ptype:,pvvalue:SomeModuleNotFoundErrorNo名为“fibo”的模块,ptraceback:None},libcore/Result.rs:945:5 我希望知道的关于目录pyth的代码部分是:let module=cpython::PyModule::importpy,fibo.unwrap

我找到了解决办法

梅因


如果希望将fibo.py作为独立于可执行文件的文件保存,我看到两种解决方案:

您可以将pyth文件夹添加到Python路径: 这假设Rust可执行文件是从父文件夹或项目运行的,这意味着pyth是当前路径的子文件夹

或者可以导入pyth.fibo,就像在Python中一样:
这假设pyth位于Python路径的某个位置,如果需要将父文件夹添加到该路径,请参见第一个解决方案。

您希望了解目录pyth的代码的哪部分?@Shepmaster,这部分:let module=cpython::PyModule::importpy,fibo.unwrap;对不起,我想我没有把问题说清楚。为什么cpython::PyModule::import会知道名为pyth的目录?如果你叫它pyt或者pytho或者我把我的代码放在这里呢?pyth是某种特殊的硬编码目录吗?如果是这样的话,你能指出一些描述它的文档吗?@Shepmaster,嗯,我只需要它来运行模块fibo.py,所以我认为最好将它放在一个单独的文件夹中,仅此而已:请注意,这个解决方案将在你的可执行文件中嵌入Python代码,因此,每次Python代码更改时,您都需要重新编译Rust可执行文件。请参阅我的答案,了解保持Python文件独立的解决方案
extern crate cpython;

use cpython::Python;

fn main() {
    let gil = Python::acquire_gil();
    println!("Hello from Rust!");
    let py = gil.python();
    let module = cpython::PyModule::import(py, "fibo").unwrap();

    module.call(py, "fib", (1,), None).unwrap();
}
extern crate cpython;

use cpython::{PyModule, PyResult, Python};

const FIBO_PY: &'static str = include_str!("../pyth/fibo.py");

fn main() {
    let gil = Python::acquire_gil();
    let py = gil.python();

    example(py).unwrap();
}

fn example(py: Python<'_>) -> PyResult<()> {
    let m = module_from_str(py, "fibo", FIBO_PY)?;

    let out: Vec<i32> = m.call(py, "fib", (2,), None)?.extract(py)?;
    println!(
        "successfully found fibo.py at compiletime.  Output: {:?}",
        out
    );

    Ok(())
}

/// Import a module from the given file contents.
///
/// This is a wrapper around `PyModule::new` and `Python::run` which simulates
/// the behavior of the builtin function `exec`. `name` will be used as the
/// module's `__name__`, but is not otherwise important (it does not need
/// to match the file's name).

fn module_from_str(py: Python<'_>, name: &str, source: &str) -> PyResult<PyModule> {
    let m = PyModule::new(py, name)?;

    let builtins = cpython::PyModule::import(py, "builtins").unwrap();
    m.dict(py).set_item(py, "__builtins__", &builtins).unwrap();

   // OR
    m.add(py, "__builtins__", py.import("builtins")?)?;
    let m_locals = m.get(py, "__dict__")?.extract(py)?;

    // To avoid multiple import, and to add entry to the cache in `sys.modules`.
    let sys = cpython::PyModule::import(py, "sys").unwrap();
    sys.get(py, "modules").unwrap().set_item(py, name, &m).unwrap();

    // Finally, run the moduke
    py.run(source, Some(&m_locals), None)?;
    Ok(m)
}
let sys = py.import("sys")?;
PyList::downcast_from(py, sys.get("path")?)?.insert_item(py, 0, "pyth");
let module = py.import("fibo")?;
let module = py.import("pyth.fibo")?;