I would like to execute a function in a Python module using Rust. This module can have imports, which are unknown at programming time.
Example of a file to be run:
import testmod
def main():
print("Hello World!")
testmod.test_fun()
return 0
I would like a way to pass a file to PyO3 and have it resolve and import all the dependencies specified in the file. It seems like something that should be in the PyO3 package, but I could not find any documentation online.
Right now I am using this code, which does not work because the Python modules are not executing according to their dependency relationships:
pub fn python(args: &WatchCommand) -> PyResult<()> {
let main = std::fs::canonicalize(&args.main)?;
let parent = main.parent().unwrap();
debug!("Loading Python Module...");
// Load file contents
let file_contents = std::fs::read_to_string(&args.main)?;
// Run Python Code
Python::with_gil(|py| -> PyResult<()> {
// Load modules in the same folder
debug!("Search Folder: {:?}", parent);
for entry in WalkDir::new(&parent) {
match entry {
Ok(res) => {
if res.path().is_file() && res.path().extension().unwrap_or_default() == "py" {
debug!("Loading module: {:?}", res.path());
let file_content = std::fs::read_to_string(res.path())?;
let name = res.path().file_stem().unwrap().to_str().unwrap();
PyModule::from_code(py, &file_content, name, name)?;
}
}
Err(e) => error!("Error loading module: {}", e),
}
}
let main = PyModule::from_code(py, &file_contents, "main.py", "main");
// Build arguments
let args = ();
// let kwargs = [("slope", 0.2)].into_py_dict(py);clap
let result: i16 = main?.getattr("main")?.call(args, None)?.extract()?;
Ok(())
})
}
This results in the following output:
DEBUG Loading Python Module...
DEBUG Search Folder: "..."
DEBUG Loading module: "...\main.py"
ERROR Error running python code: ModuleNotFoundError: No module named 'testmod'
Any help is greatly appreciated,
Riccardo