Skip to content

Commit 2518e16

Browse files
authored
feat(native): Python - support tuple type (#7128)
1 parent 7cb9ace commit 2518e16

File tree

7 files changed

+60
-3
lines changed

7 files changed

+60
-3
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use neon::prelude::*;
44
use neon::result::Throw;
55
use neon::types::JsDate;
66
use pyo3::exceptions::{PyNotImplementedError, PyTypeError};
7-
use pyo3::types::{PyBool, PyDict, PyFloat, PyFunction, PyInt, PyList, PySet, PyString};
7+
use pyo3::types::{PyBool, PyDict, PyFloat, PyFunction, PyInt, PyList, PySet, PyString, PyTuple};
88
use pyo3::{Py, PyAny, PyErr, PyObject, Python, ToPyObject};
99
use std::cell::RefCell;
1010
use std::collections::hash_map::{IntoIter, Iter, Keys};
@@ -59,6 +59,7 @@ pub enum CLReprKind {
5959
Bool,
6060
Float,
6161
Int,
62+
Tuple,
6263
Array,
6364
Object,
6465
JsFunction,
@@ -77,6 +78,7 @@ pub enum CLRepr {
7778
Bool(bool),
7879
Float(f64),
7980
Int(i64),
81+
Tuple(Vec<CLRepr>),
8082
Array(Vec<CLRepr>),
8183
Object(CLReprObject),
8284
JsFunction(Arc<Root<JsFunction>>),
@@ -157,6 +159,7 @@ impl CLRepr {
157159
CLRepr::Bool(_) => CLReprKind::Bool,
158160
CLRepr::Float(_) => CLReprKind::Float,
159161
CLRepr::Int(_) => CLReprKind::Int,
162+
CLRepr::Tuple(_) => CLReprKind::Tuple,
160163
CLRepr::Array(_) => CLReprKind::Array,
161164
CLRepr::Object(_) => CLReprKind::Object,
162165
CLRepr::JsFunction(_) => CLReprKind::JsFunction,
@@ -274,6 +277,15 @@ impl CLRepr {
274277
}
275278

276279
Self::Array(r)
280+
} else if v.get_type().is_subclass_of::<PyTuple>()? {
281+
let l = v.downcast::<PyTuple>()?;
282+
let mut r = Vec::with_capacity(l.len());
283+
284+
for v in l.iter() {
285+
r.push(Self::from_python_ref(v)?);
286+
}
287+
288+
Self::Tuple(r)
277289
} else {
278290
return Err(PyErr::new::<PyTypeError, _>(format!(
279291
"Unable to represent {} type as CLR from Python",
@@ -295,7 +307,7 @@ impl CLRepr {
295307
CLRepr::Bool(v) => cx.boolean(v).upcast(),
296308
CLRepr::Float(v) => cx.number(v).upcast(),
297309
CLRepr::Int(v) => cx.number(v as f64).upcast(),
298-
CLRepr::Array(arr) => {
310+
CLRepr::Tuple(arr) | CLRepr::Array(arr) => {
299311
let r = cx.empty_array();
300312

301313
for (k, v) in arr.into_iter().enumerate() {
@@ -389,6 +401,15 @@ impl CLRepr {
389401

390402
PyList::new(py, elements).to_object(py)
391403
}
404+
CLRepr::Tuple(arr) => {
405+
let mut elements = Vec::with_capacity(arr.len());
406+
407+
for el in arr.into_iter() {
408+
elements.push(Self::into_py_impl(el, py)?);
409+
}
410+
411+
PyTuple::new(py, elements).to_object(py)
412+
}
392413
CLRepr::Object(obj) => {
393414
let r = PyDict::new(py);
394415

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ pub fn from_minijinja_value(from: &mj::value::Value) -> Result<CLRepr, mj::Error
261261

262262
pub fn to_minijinja_value(from: CLRepr) -> Value {
263263
match from {
264-
CLRepr::Array(inner) => Value::from_seq_object(JinjaSequenceObject { inner }),
264+
CLRepr::Tuple(inner) | CLRepr::Array(inner) => {
265+
Value::from_seq_object(JinjaSequenceObject { inner })
266+
}
265267
CLRepr::Object(inner) => Value::from_object(JinjaDynamicObject { inner }),
266268
CLRepr::String(v) => Value::from(v),
267269
CLRepr::Float(v) => Value::from(v),

packages/cubejs-backend-native/test/__snapshots__/jinja.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ exports[`Jinja render arguments-test.yml.jinja: arguments-test.yml.jinja 1`] = `
184184
arg_null: none
185185
arg_seq_1: [1, 2, 3, 4, 5]
186186
arg_seq_2: [5, 4, 3, 2, 1]
187+
arg_sum_tuple: 3
187188
arg_sum_map: 20"
188189
`;
189190

packages/cubejs-backend-native/test/jinja.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ suite('Python model', () => {
6363
arg_sum_integers: expect.any(Object),
6464
arg_str: expect.any(Object),
6565
arg_null: expect.any(Object),
66+
arg_sum_tuple: expect.any(Object),
6667
arg_sum_map: expect.any(Object),
6768
arg_seq: expect.any(Object),
69+
new_int_tuple: expect.any(Object),
70+
new_str_tuple: expect.any(Object),
6871
});
6972
});
7073
});
@@ -80,8 +83,11 @@ darwinSuite('Scope Python model', () => {
8083
arg_sum_integers: expect.any(Object),
8184
arg_str: expect.any(Object),
8285
arg_null: expect.any(Object),
86+
arg_sum_tuple: expect.any(Object),
8387
arg_sum_map: expect.any(Object),
8488
arg_seq: expect.any(Object),
89+
new_int_tuple: expect.any(Object),
90+
new_str_tuple: expect.any(Object),
8591
});
8692
});
8793
});

packages/cubejs-backend-native/test/templates/arguments-test.yml.jinja

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{%- set my_sequence_1 = [1,2,3,4,5] -%}
22
{%- set my_sequence_2 = [5,4,3,2,1] -%}
33
{%- set my_map = {'field_a' : 5, 'field_b' : 15} -%}
4+
{%- set my_int_tuple = new_int_tuple() -%}
5+
{%- set my_str_tuple = new_str_tuple() -%}
46

57
test:
68
arg_sum_integers_int_int: {{ arg_sum_integers(1, 1) }}
@@ -11,4 +13,5 @@ test:
1113
arg_null: {{ arg_null(null) }}
1214
arg_seq_1: {{ arg_seq(my_sequence_1) }}
1315
arg_seq_2: {{ arg_seq(my_sequence_2) }}
16+
arg_sum_tuple: {{ arg_sum_tuple(my_int_tuple) }}
1417
arg_sum_map: {{ arg_sum_map(my_map) }}

packages/cubejs-backend-native/test/templates/scoped-utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def arg_str(a):
1717
def arg_null(a):
1818
return a
1919
20+
@context_func
21+
def arg_sum_tuple(tu):
22+
return tu[0] + tu[1]
23+
2024
@context_func
2125
def arg_sum_map(obj):
2226
return obj['field_a'] + obj['field_b']
@@ -25,6 +29,14 @@ def arg_sum_map(obj):
2529
def arg_seq(a):
2630
return a
2731
32+
@context_func
33+
def new_int_tuple():
34+
return (1,2)
35+
36+
@context_func
37+
def new_str_tuple():
38+
return ("hello", "word")
39+
2840
@context_func
2941
def load_data_sync():
3042
client = MyApiClient("google.com")

packages/cubejs-backend-native/test/templates/utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def arg_str(a):
1616
def arg_null(a):
1717
return a
1818

19+
@context_func
20+
def arg_sum_tuple(tu):
21+
return tu[0] + tu[1]
22+
1923
@context_func
2024
def arg_sum_map(obj):
2125
return obj['field_a'] + obj['field_b']
@@ -24,6 +28,14 @@ def arg_sum_map(obj):
2428
def arg_seq(a):
2529
return a
2630

31+
@context_func
32+
def new_int_tuple():
33+
return (1,2)
34+
35+
@context_func
36+
def new_str_tuple():
37+
return ("1", "2")
38+
2739
@context_func
2840
def load_data_sync():
2941
client = MyApiClient("google.com")

0 commit comments

Comments
 (0)