Skip to content

Commit 357cf78

Browse files
committed
Add example for calling between rust and python
Add an example which illustrates how to call between rust and python. Most importantly there no examples which illustrate how to call rust from python and it is not obvious how to do this.
1 parent ab47293 commit 357cf78

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from rust_py_module import RustStruct, rust_function
2+
3+
class PythonPerson:
4+
def __init__(self, name):
5+
self.name = name
6+
7+
def python_callback():
8+
python_person = PythonPerson("Peter Python")
9+
rust_object = rust_function(42, "This is a python string", python_person)
10+
rust_object.print_in_rust_from_python()
11+
12+
def take_string(string):
13+
print("Calling python function from rust with string: " + string)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use rustpython_vm::{
2+
builtins::PyStr,
3+
function::{FuncArgs, KwArgs, PosArgs},
4+
pyclass, pymodule, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject,
5+
VirtualMachine,
6+
};
7+
8+
pub(crate) use rust_py_module::make_module;
9+
10+
pub fn main() {
11+
let interp = rustpython_vm::Interpreter::with_init(Default::default(), |vm| {
12+
vm.add_native_modules(rustpython_stdlib::get_module_inits());
13+
vm.add_native_module("rust_py_module".to_owned(), Box::new(make_module));
14+
});
15+
16+
interp.enter(|vm| {
17+
vm.insert_sys_path(vm.new_pyobj("examples"))
18+
.expect("add path");
19+
20+
let module = vm.import("call_between_rust_and_python", None, 0).unwrap();
21+
let init_fn = module.get_attr("python_callback", vm).unwrap();
22+
23+
vm.invoke(&init_fn, ()).unwrap();
24+
25+
let pystr = PyObjectRef::from(PyStr::new_ref(
26+
unsafe {
27+
PyStr::new_ascii_unchecked(String::from("Rust string sent to python").into_bytes())
28+
},
29+
vm.as_ref(),
30+
));
31+
let take_string_args = FuncArgs::new(PosArgs::new(vec![pystr]), KwArgs::default());
32+
let take_string_fn = module.get_attr("take_string", vm).unwrap();
33+
34+
vm.invoke(&take_string_fn, take_string_args).unwrap();
35+
})
36+
}
37+
38+
#[pymodule]
39+
mod rust_py_module {
40+
use super::*;
41+
42+
#[pyfunction]
43+
fn rust_function(
44+
num: i32,
45+
s: String,
46+
python_person: PyObjectRef,
47+
vm: &VirtualMachine,
48+
) -> PyResult<RustStruct> {
49+
println!(
50+
"Calling standalone rust function from python passing args:
51+
num: {},
52+
string: {},
53+
python_person.name: {}",
54+
num,
55+
s,
56+
python_person.try_into_value::<PythonPerson>(vm).unwrap().name
57+
);
58+
Ok(RustStruct)
59+
}
60+
61+
#[pyattr]
62+
#[pyclass(module = "rust_py_module", name = "RustStruct")]
63+
#[derive(Debug, PyPayload)]
64+
struct RustStruct;
65+
66+
#[pyclass]
67+
impl RustStruct {
68+
#[pymethod]
69+
fn print_in_rust_from_python(&self) {
70+
println!("Calling a rust method from python");
71+
}
72+
}
73+
74+
struct PythonPerson {
75+
name: String,
76+
}
77+
78+
impl TryFromBorrowedObject for PythonPerson {
79+
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
80+
let name = obj
81+
.get_attr("name", vm)
82+
.unwrap()
83+
.try_into_value::<String>(vm)
84+
.unwrap();
85+
Ok(PythonPerson { name })
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)