Skip to content

Commit 18af44b

Browse files
authored
Merge pull request #4276 from Gelox/main
Add example for calling between rust and python
2 parents b9ed63e + 340816d commit 18af44b

File tree

2 files changed

+108
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)