Skip to content

Commit 54a0f2b

Browse files
authored
refactor(native): Python - extract calling (#7378)
1 parent fb01582 commit 54a0f2b

File tree

4 files changed

+90
-71
lines changed

4 files changed

+90
-71
lines changed

packages/cubejs-backend-native/src/python/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ mod entry;
44
pub(crate) mod linux_dylib;
55
pub(crate) mod python_model;
66
pub(crate) mod runtime;
7+
pub mod utils;
78

89
pub use entry::python_register_module;
10+
pub use utils::{python_fn_call_sync, python_obj_call_sync, python_obj_method_call_sync};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use crate::cross::*;
2+
use pyo3::exceptions::PyNotImplementedError;
3+
use pyo3::prelude::*;
4+
use pyo3::types::{PyFunction, PyString, PyTuple};
5+
use pyo3::AsPyPointer;
6+
7+
pub fn python_fn_call_sync(py_fun: &Py<PyFunction>, arguments: Vec<CLRepr>) -> PyResult<CLRepr> {
8+
Python::with_gil(|py| {
9+
let mut args_tuple = Vec::with_capacity(arguments.len());
10+
11+
for arg in arguments {
12+
args_tuple.push(arg.into_py(py)?);
13+
}
14+
15+
let tuple = PyTuple::new(py, args_tuple);
16+
17+
let call_res = py_fun.call1(py, tuple)?;
18+
19+
let is_coroutine = unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
20+
if is_coroutine {
21+
Err(PyErr::new::<PyNotImplementedError, _>(
22+
"Calling function with async response is not supported",
23+
))
24+
} else {
25+
CLRepr::from_python_ref(call_res.as_ref(py))
26+
}
27+
})
28+
}
29+
30+
pub fn python_obj_call_sync(py_fun: &PyObject, arguments: Vec<CLRepr>) -> PyResult<CLRepr> {
31+
Python::with_gil(|py| {
32+
let mut args_tuple = Vec::with_capacity(arguments.len());
33+
34+
for arg in arguments {
35+
args_tuple.push(arg.into_py(py)?);
36+
}
37+
38+
let tuple = PyTuple::new(py, args_tuple);
39+
40+
let call_res = py_fun.call1(py, tuple)?;
41+
42+
let is_coroutine = unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
43+
if is_coroutine {
44+
Err(PyErr::new::<PyNotImplementedError, _>(
45+
"Calling object with async response is not supported",
46+
))
47+
} else {
48+
CLRepr::from_python_ref(call_res.as_ref(py))
49+
}
50+
})
51+
}
52+
53+
pub fn python_obj_method_call_sync<N>(
54+
py_fun: &PyObject,
55+
name: N,
56+
arguments: Vec<CLRepr>,
57+
) -> PyResult<CLRepr>
58+
where
59+
N: IntoPy<Py<PyString>>,
60+
{
61+
Python::with_gil(|py| {
62+
let mut args_tuple = Vec::with_capacity(arguments.len());
63+
64+
for arg in arguments {
65+
args_tuple.push(arg.into_py(py)?);
66+
}
67+
68+
let tuple = PyTuple::new(py, args_tuple);
69+
70+
let call_res = py_fun.call_method1(py, name, tuple)?;
71+
72+
let is_coroutine = unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
73+
if is_coroutine {
74+
Err(PyErr::new::<PyNotImplementedError, _>(
75+
"Calling object method with async response is not supported",
76+
))
77+
} else {
78+
CLRepr::from_python_ref(call_res.as_ref(py))
79+
}
80+
})
81+
}

packages/cubejs-backend-native/src/template/engine_python.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::cross::*;
2+
use crate::python::python_fn_call_sync;
23
use crate::template::mj_value::{from_minijinja_value, to_minijinja_value};
34
use minijinja as mj;
45
use neon::prelude::*;
5-
use pyo3::prelude::*;
6-
use pyo3::{exceptions::PyNotImplementedError, types::PyTuple, AsPyPointer};
76

87
pub fn mj_inject_python_extension(
98
cx: &mut FunctionContext,
@@ -50,28 +49,7 @@ pub fn mj_inject_python_extension(
5049
arguments.push(from_minijinja_value(arg)?);
5150
}
5251

53-
let python_call_res = Python::with_gil(|py| {
54-
let mut args_tuple = Vec::with_capacity(args.len());
55-
56-
for arg in arguments {
57-
args_tuple.push(arg.into_py(py)?);
58-
}
59-
60-
let tuple = PyTuple::new(py, args_tuple);
61-
62-
let call_res = py_fun.call1(py, tuple)?;
63-
64-
let is_coroutine =
65-
unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
66-
if is_coroutine {
67-
Err(PyErr::new::<PyNotImplementedError, _>(
68-
"Calling async is not supported",
69-
))
70-
} else {
71-
CLRepr::from_python_ref(call_res.as_ref(py))
72-
}
73-
});
74-
match python_call_res {
52+
match python_fn_call_sync(&py_fun, arguments) {
7553
Ok(r) => Ok(to_minijinja_value(r)),
7654
Err(err) => Err(mj::Error::new(
7755
minijinja::ErrorKind::InvalidOperation,

packages/cubejs-backend-native/src/template/mj_value/python.rs

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::cross::*;
22
use crate::python::runtime::py_runtime;
3+
use crate::python::{python_obj_call_sync, python_obj_method_call_sync};
34
use crate::template::mj_value::to_minijinja_value;
45
use crate::tokio_runtime;
56
use log::error;
67
use minijinja as mj;
78
use minijinja::value as mjv;
89
use minijinja::value::{Object, ObjectKind, StructObject, Value};
9-
use pyo3::exceptions::PyNotImplementedError;
10-
use pyo3::types::{PyDict, PyFunction, PyTuple};
11-
use pyo3::{AsPyPointer, Py, PyErr, PyObject, PyResult, Python};
10+
use pyo3::types::{PyDict, PyFunction};
11+
use pyo3::{Py, PyObject, PyResult, Python};
1212
use std::convert::TryInto;
1313
use std::sync::Arc;
1414

@@ -131,28 +131,7 @@ impl Object for JinjaPythonObject {
131131
arguments.push(from_minijinja_value(arg)?);
132132
}
133133

134-
let python_call_res = Python::with_gil(move |py| -> PyResult<CLRepr> {
135-
let mut args_tuple = Vec::with_capacity(args.len());
136-
137-
for arg in arguments {
138-
args_tuple.push(arg.into_py(py)?);
139-
}
140-
141-
let tuple = PyTuple::new(py, args_tuple);
142-
143-
let call_res = obj_ref.call_method1(py, name, tuple)?;
144-
145-
let is_coroutine = unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
146-
if is_coroutine {
147-
Err(PyErr::new::<PyNotImplementedError, _>(
148-
"Calling async methods are not supported",
149-
))
150-
} else {
151-
CLRepr::from_python_ref(call_res.as_ref(py))
152-
}
153-
});
154-
155-
match python_call_res {
134+
match python_obj_method_call_sync(obj_ref, name, arguments) {
156135
Ok(r) => Ok(to_minijinja_value(r)),
157136
Err(err) => Err(mj::Error::new(
158137
minijinja::ErrorKind::InvalidOperation,
@@ -170,28 +149,7 @@ impl Object for JinjaPythonObject {
170149
arguments.push(from_minijinja_value(arg)?);
171150
}
172151

173-
let python_call_res = Python::with_gil(move |py| -> PyResult<CLRepr> {
174-
let mut args_tuple = Vec::with_capacity(args.len());
175-
176-
for arg in arguments {
177-
args_tuple.push(arg.into_py(py)?);
178-
}
179-
180-
let tuple = PyTuple::new(py, args_tuple);
181-
182-
let call_res = obj_ref.call1(py, tuple)?;
183-
184-
let is_coroutine = unsafe { pyo3::ffi::PyCoro_CheckExact(call_res.as_ptr()) == 1 };
185-
if is_coroutine {
186-
Err(PyErr::new::<PyNotImplementedError, _>(
187-
"Calling async is not supported",
188-
))
189-
} else {
190-
CLRepr::from_python_ref(call_res.as_ref(py))
191-
}
192-
});
193-
194-
match python_call_res {
152+
match python_obj_call_sync(obj_ref, arguments) {
195153
Ok(r) => Ok(to_minijinja_value(r)),
196154
Err(err) => Err(mj::Error::new(
197155
minijinja::ErrorKind::InvalidOperation,

0 commit comments

Comments
 (0)