From 2e35d5b0ed7b9eca6383bc6df9d63ab266853102 Mon Sep 17 00:00:00 2001 From: Cory Grinstead Date: Thu, 12 Sep 2024 10:48:09 -0500 Subject: [PATCH] [CHORE]: Move jq out of core (#2828) --- Cargo.lock | 25 +++- Cargo.toml | 3 + daft/daft/__init__.pyi | 6 +- daft/expressions/expressions.py | 2 +- src/daft-core/Cargo.toml | 5 - src/daft-core/src/array/ops/json.rs | 104 -------------- src/daft-core/src/array/ops/mod.rs | 1 - src/daft-core/src/datatypes/mod.rs | 8 ++ src/daft-core/src/series/ops/json.rs | 17 --- src/daft-core/src/series/ops/mod.rs | 1 - src/daft-dsl/src/functions/json/mod.rs | 31 ----- src/daft-dsl/src/functions/json/query.rs | 51 ------- src/daft-dsl/src/functions/mod.rs | 4 - src/daft-dsl/src/python.rs | 5 - src/daft-functions-json/Cargo.toml | 27 ++++ src/daft-functions-json/src/expr.rs | 51 +++++++ src/daft-functions-json/src/lib.rs | 164 +++++++++++++++++++++++ src/daft-functions/Cargo.toml | 1 + src/lib.rs | 2 + 19 files changed, 282 insertions(+), 226 deletions(-) delete mode 100644 src/daft-core/src/array/ops/json.rs delete mode 100644 src/daft-core/src/series/ops/json.rs delete mode 100644 src/daft-dsl/src/functions/json/mod.rs delete mode 100644 src/daft-dsl/src/functions/json/query.rs create mode 100644 src/daft-functions-json/Cargo.toml create mode 100644 src/daft-functions-json/src/expr.rs create mode 100644 src/daft-functions-json/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 541d8a3ad6..a60b0c6a06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1680,6 +1680,7 @@ dependencies = [ "daft-csv", "daft-dsl", "daft-functions", + "daft-functions-json", "daft-image", "daft-io", "daft-json", @@ -1737,10 +1738,6 @@ dependencies = [ "hyperloglog", "indexmap 2.5.0", "itertools 0.11.0", - "jaq-core", - "jaq-interpret", - "jaq-parse", - "jaq-std", "lazy_static", "log", "mur3", @@ -1750,7 +1747,6 @@ dependencies = [ "pyo3", "regex", "serde", - "serde_json", "sketches-ddsketch", "unicode-normalization", "xxhash-rust", @@ -1840,6 +1836,25 @@ dependencies = [ "uuid 1.10.0", ] +[[package]] +name = "daft-functions-json" +version = "0.3.0-dev0" +dependencies = [ + "common-error", + "daft-core", + "daft-dsl", + "itertools 0.11.0", + "jaq-core", + "jaq-interpret", + "jaq-parse", + "jaq-std", + "lazy_static", + "pyo3", + "serde", + "serde_json", + "typetag", +] + [[package]] name = "daft-image" version = "0.3.0-dev0" diff --git a/Cargo.toml b/Cargo.toml index 5ad3f1ab49..55403d40bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ daft-core = {path = "src/daft-core", default-features = false} daft-csv = {path = "src/daft-csv", default-features = false} daft-dsl = {path = "src/daft-dsl", default-features = false} daft-functions = {path = "src/daft-functions", default-features = false} +daft-functions-json = {path = "src/daft-functions-json", default-features = false} daft-image = {path = "src/daft-image", default-features = false} daft-io = {path = "src/daft-io", default-features = false} daft-json = {path = "src/daft-json", default-features = false} @@ -53,6 +54,7 @@ python = [ "daft-sql/python", "daft-table/python", "daft-functions/python", + "daft-functions-json/python", "common-daft-config/python", "common-system-info/python", "common-display/python", @@ -129,6 +131,7 @@ members = [ "src/daft-scheduler", "src/daft-sketch", "src/daft-functions", + "src/daft-functions-json", "src/daft-sql", "src/hyperloglog" ] diff --git a/daft/daft/__init__.pyi b/daft/daft/__init__.pyi index f78e2ae166..8c4853d1f5 100644 --- a/daft/daft/__init__.pyi +++ b/daft/daft/__init__.pyi @@ -1165,7 +1165,6 @@ class PyExpr: def partitioning_years(self) -> PyExpr: ... def partitioning_iceberg_bucket(self, n: int) -> PyExpr: ... def partitioning_iceberg_truncate(self, w: int) -> PyExpr: ... - def json_query(self, query: str) -> PyExpr: ... ### # Helper methods required by optimizer: @@ -1256,6 +1255,11 @@ def image_encode(expr: PyExpr, image_format: ImageFormat) -> PyExpr: ... def image_resize(expr: PyExpr, w: int, h: int) -> PyExpr: ... def image_to_mode(expr: PyExpr, mode: ImageMode) -> PyExpr: ... +# --- +# expr.json namespace +# --- +def json_query(expr: PyExpr, query: str) -> PyExpr: ... + class PyCatalog: @staticmethod def new() -> PyCatalog: ... diff --git a/daft/expressions/expressions.py b/daft/expressions/expressions.py index e137977f41..3dc46487ec 100644 --- a/daft/expressions/expressions.py +++ b/daft/expressions/expressions.py @@ -3391,7 +3391,7 @@ def query(self, jq_query: str) -> Expression: Expression: Expression representing the result of the JQ query as a column of JSON-compatible strings """ - return Expression._from_pyexpr(self._expr.json_query(jq_query)) + return Expression._from_pyexpr(native.json_query(self._expr, jq_query)) class ExpressionEmbeddingNamespace(ExpressionNamespace): diff --git a/src/daft-core/Cargo.toml b/src/daft-core/Cargo.toml index 7c462ceb38..36ea9b68df 100644 --- a/src/daft-core/Cargo.toml +++ b/src/daft-core/Cargo.toml @@ -34,10 +34,6 @@ html-escape = {workspace = true} hyperloglog = {path = "../hyperloglog"} indexmap = {workspace = true, features = ["serde"]} itertools = {workspace = true} -jaq-core = {workspace = true} -jaq-interpret = {workspace = true} -jaq-parse = {workspace = true} -jaq-std = {workspace = true} lazy_static = {workspace = true} log = {workspace = true} mur3 = "0.1.0" @@ -46,7 +42,6 @@ num-traits = {workspace = true} pyo3 = {workspace = true, optional = true} regex = {workspace = true} serde = {workspace = true} -serde_json = {workspace = true} sketches-ddsketch = {workspace = true} unicode-normalization = "0.1.23" diff --git a/src/daft-core/src/array/ops/json.rs b/src/daft-core/src/array/ops/json.rs deleted file mode 100644 index eadfbcd02b..0000000000 --- a/src/daft-core/src/array/ops/json.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::sync::Mutex; - -use crate::datatypes::Utf8Array; - -use super::as_arrow::AsArrow; -use common_error::{DaftError, DaftResult}; -use itertools::Itertools; -use jaq_interpret::{Ctx, Filter, FilterT, ParseCtx, RcIter}; -use lazy_static::lazy_static; -use serde_json::Value; - -fn setup_parse_ctx() -> ParseCtx { - // set up the parse context with the core and std libraries https://github.com/01mf02/jaq/tree/main?tab=readme-ov-file#features - let mut defs = ParseCtx::new(Vec::new()); - defs.insert_natives(jaq_core::core()); - defs.insert_defs(jaq_std::std()); - defs -} - -lazy_static! { - static ref PARSE_CTX: Mutex = Mutex::new(setup_parse_ctx()); -} - -fn compile_filter(query: &str) -> DaftResult { - // parse the filter - let (filter, errs) = jaq_parse::parse(query, jaq_parse::main()); - if !errs.is_empty() { - return Err(DaftError::ValueError(format!( - "Error parsing json query ({query}): {}", - errs.iter().map(|e| e.to_string()).join(", ") - ))); - } - - // compile the filter executable - let mut defs = PARSE_CTX.lock().unwrap(); - let compiled_filter = defs.compile(filter.unwrap()); - if !defs.errs.is_empty() { - return Err(DaftError::ComputeError(format!( - "Error compiling json query ({query}): {}", - defs.errs.iter().map(|(e, _)| e.to_string()).join(", ") - ))); - } - - Ok(compiled_filter) -} - -impl Utf8Array { - pub fn json_query(&self, query: &str) -> DaftResult { - let compiled_filter = compile_filter(query)?; - let inputs = RcIter::new(core::iter::empty()); - - let self_arrow = self.as_arrow(); - let arrow_result = self_arrow - .iter() - .map(|opt| { - opt.map_or(Ok(None), |s| { - serde_json::from_str::(s) - .map_err(DaftError::from) - .and_then(|json| { - compiled_filter - .run((Ctx::new([], &inputs), json.into())) - .map(|result| { - result.map(|v| v.to_string()).map_err(|e| { - DaftError::ComputeError(format!( - "Error running json query ({query}): {e}" - )) - }) - }) - .collect::, _>>() - .map(|values| Some(values.join("\n"))) - }) - }) - }) - .collect::, _>>()? - .with_validity(self_arrow.validity().cloned()); - - Ok(Utf8Array::from((self.name(), Box::new(arrow_result)))) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_json_query() -> DaftResult<()> { - let data = Utf8Array::from(( - "data", - Box::new(arrow2::array::Utf8Array::::from(vec![ - r#"{"foo": {"bar": 1}}"#.into(), - r#"{"foo": {"bar": 2}}"#.into(), - r#"{"foo": {"bar": 3}}"#.into(), - ])), - )); - - let query = r#".foo.bar"#; - let result = &data.json_query(query)?; - assert_eq!(result.len(), 3); - assert_eq!(result.as_arrow().value(0), "1"); - assert_eq!(result.as_arrow().value(1), "2"); - assert_eq!(result.as_arrow().value(2), "3"); - Ok(()) - } -} diff --git a/src/daft-core/src/array/ops/mod.rs b/src/daft-core/src/array/ops/mod.rs index faeaab5fae..ba28710a52 100644 --- a/src/daft-core/src/array/ops/mod.rs +++ b/src/daft-core/src/array/ops/mod.rs @@ -30,7 +30,6 @@ mod hll_merge; mod hll_sketch; mod if_else; mod is_in; -mod json; mod len; mod list; mod list_agg; diff --git a/src/daft-core/src/datatypes/mod.rs b/src/daft-core/src/datatypes/mod.rs index a153bc4c0a..952455f38b 100644 --- a/src/daft-core/src/datatypes/mod.rs +++ b/src/daft-core/src/datatypes/mod.rs @@ -362,3 +362,11 @@ impl DataArray { self.as_arrow().values().as_slice() } } + +impl> FromIterator> for Utf8Array { + #[inline] + fn from_iter>>(iter: I) -> Self { + let arrow_arr = arrow2::array::Utf8Array::::from_iter(iter); + Self::from(("", Box::new(arrow_arr))) + } +} diff --git a/src/daft-core/src/series/ops/json.rs b/src/daft-core/src/series/ops/json.rs deleted file mode 100644 index 68d5c8cda8..0000000000 --- a/src/daft-core/src/series/ops/json.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::datatypes::DataType; -use crate::series::IntoSeries; -use crate::series::Series; -use common_error::DaftError; -use common_error::DaftResult; - -impl Series { - pub fn json_query(&self, query: &str) -> DaftResult { - match self.data_type() { - DataType::Utf8 => Ok(self.utf8()?.json_query(query)?.into_series()), - dt => Err(DaftError::TypeError(format!( - "json query not implemented for {}", - dt - ))), - } - } -} diff --git a/src/daft-core/src/series/ops/mod.rs b/src/daft-core/src/series/ops/mod.rs index 84587dbe62..d527d500f4 100644 --- a/src/daft-core/src/series/ops/mod.rs +++ b/src/daft-core/src/series/ops/mod.rs @@ -22,7 +22,6 @@ pub mod groups; pub mod hash; pub mod if_else; pub mod is_in; -pub mod json; pub mod len; pub mod list; pub mod log; diff --git a/src/daft-dsl/src/functions/json/mod.rs b/src/daft-dsl/src/functions/json/mod.rs deleted file mode 100644 index e929da00b4..0000000000 --- a/src/daft-dsl/src/functions/json/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -mod query; - -use query::JsonQueryEvaluator; -use serde::{Deserialize, Serialize}; - -use crate::{Expr, ExprRef}; - -use super::FunctionEvaluator; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub enum JsonExpr { - Query(String), -} - -impl JsonExpr { - #[inline] - pub fn get_evaluator(&self) -> &dyn FunctionEvaluator { - use JsonExpr::*; - match self { - Query(_) => &JsonQueryEvaluator {}, - } - } -} - -pub fn query(input: ExprRef, query: &str) -> ExprRef { - Expr::Function { - func: super::FunctionExpr::Json(JsonExpr::Query(query.to_string())), - inputs: vec![input], - } - .into() -} diff --git a/src/daft-dsl/src/functions/json/query.rs b/src/daft-dsl/src/functions/json/query.rs deleted file mode 100644 index a94c71112a..0000000000 --- a/src/daft-dsl/src/functions/json/query.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::ExprRef; -use daft_core::prelude::*; - -use crate::functions::FunctionExpr; -use common_error::{DaftError, DaftResult}; - -use super::{super::FunctionEvaluator, JsonExpr}; - -pub(super) struct JsonQueryEvaluator {} - -impl FunctionEvaluator for JsonQueryEvaluator { - fn fn_name(&self) -> &'static str { - "JsonQuery" - } - - fn to_field(&self, inputs: &[ExprRef], schema: &Schema, _: &FunctionExpr) -> DaftResult { - match inputs { - [input] => { - let input_field = input.to_field(schema)?; - match input_field.dtype { - DataType::Utf8 => Ok(Field::new(input_field.name, DataType::Utf8)), - _ => Err(DaftError::TypeError(format!( - "Expected input to be a string type, received: {}", - input_field.dtype - ))), - } - } - _ => Err(DaftError::SchemaMismatch(format!( - "Expected 1 input arg, got {}", - inputs.len() - ))), - } - } - - fn evaluate(&self, inputs: &[Series], expr: &FunctionExpr) -> DaftResult { - match inputs { - [input] => { - let query = match expr { - FunctionExpr::Json(JsonExpr::Query(query)) => query, - _ => panic!("Expected Json Query Expr, got {expr}"), - }; - - input.json_query(query) - } - _ => Err(DaftError::ValueError(format!( - "Expected 1 input arg, got {}", - inputs.len() - ))), - } - } -} diff --git a/src/daft-dsl/src/functions/mod.rs b/src/daft-dsl/src/functions/mod.rs index f26281001c..03d31cd49b 100644 --- a/src/daft-dsl/src/functions/mod.rs +++ b/src/daft-dsl/src/functions/mod.rs @@ -1,5 +1,4 @@ pub mod float; -pub mod json; pub mod list; pub mod map; pub mod numeric; @@ -17,7 +16,6 @@ use std::hash::Hash; use crate::{Expr, ExprRef, Operator}; use self::float::FloatExpr; -use self::json::JsonExpr; use self::list::ListExpr; use self::map::MapExpr; use self::numeric::NumericExpr; @@ -46,7 +44,6 @@ pub enum FunctionExpr { Map(MapExpr), Sketch(SketchExpr), Struct(StructExpr), - Json(JsonExpr), Python(PythonUDF), Partitioning(PartitioningExpr), } @@ -75,7 +72,6 @@ impl FunctionExpr { Map(expr) => expr.get_evaluator(), Sketch(expr) => expr.get_evaluator(), Struct(expr) => expr.get_evaluator(), - Json(expr) => expr.get_evaluator(), Python(expr) => expr.get_evaluator(), Partitioning(expr) => expr.get_evaluator(), } diff --git a/src/daft-dsl/src/python.rs b/src/daft-dsl/src/python.rs index c770d27ee1..58d62d4f0d 100644 --- a/src/daft-dsl/src/python.rs +++ b/src/daft-dsl/src/python.rs @@ -892,11 +892,6 @@ impl PyExpr { use crate::functions::partitioning::iceberg_truncate; Ok(iceberg_truncate(self.into(), w).into()) } - - pub fn json_query(&self, _query: &str) -> PyResult { - use crate::functions::json::query; - Ok(query(self.into(), _query).into()) - } } impl_bincode_py_state_serialization!(PyExpr); diff --git a/src/daft-functions-json/Cargo.toml b/src/daft-functions-json/Cargo.toml new file mode 100644 index 0000000000..e27077b497 --- /dev/null +++ b/src/daft-functions-json/Cargo.toml @@ -0,0 +1,27 @@ +[dependencies] +common-error = {path = "../common/error", default-features = false} +daft-core = {path = "../daft-core", default-features = false} +daft-dsl = {path = "../daft-dsl", default-features = false} +jaq-core = {workspace = true} +jaq-interpret = {workspace = true} +jaq-parse = {workspace = true} +jaq-std = {workspace = true} +lazy_static = {workspace = true} +pyo3 = {workspace = true, optional = true} +serde = {workspace = true} +serde_json = {workspace = true} +typetag = "0.2.18" +itertools.workspace = true + +[features] +python = [ + "dep:pyo3", + "common-error/python", + "daft-core/python", + "daft-dsl/python" +] + +[package] +name = "daft-functions-json" +edition.workspace = true +version.workspace = true diff --git a/src/daft-functions-json/src/expr.rs b/src/daft-functions-json/src/expr.rs new file mode 100644 index 0000000000..232f6f28c4 --- /dev/null +++ b/src/daft-functions-json/src/expr.rs @@ -0,0 +1,51 @@ +use daft_core::prelude::*; +use daft_dsl::{functions::ScalarUDF, ExprRef}; + +// use crate::functions::FunctionExpr; +use common_error::{DaftError, DaftResult}; +use serde::{Deserialize, Serialize}; + +use crate::json_query_series; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct JsonQuery { + pub query: String, +} + +#[typetag::serde] +impl ScalarUDF for JsonQuery { + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn name(&self) -> &'static str { + "json_query" + } + + fn evaluate(&self, inputs: &[Series]) -> DaftResult { + match inputs { + [input] => json_query_series(input, &self.query), + + _ => Err(DaftError::TypeError( + "Json query expects a single argument".to_string(), + )), + } + } + fn to_field(&self, inputs: &[ExprRef], schema: &Schema) -> DaftResult { + match inputs { + [input] => { + let input_field = input.to_field(schema)?; + match input_field.dtype { + DataType::Utf8 => Ok(Field::new(input_field.name, DataType::Utf8)), + _ => Err(DaftError::TypeError(format!( + "Expected input to be a string type, received: {}", + input_field.dtype + ))), + } + } + _ => Err(DaftError::SchemaMismatch(format!( + "Expected 1 input arg, got {}", + inputs.len() + ))), + } + } +} diff --git a/src/daft-functions-json/src/lib.rs b/src/daft-functions-json/src/lib.rs new file mode 100644 index 0000000000..f04a99fd82 --- /dev/null +++ b/src/daft-functions-json/src/lib.rs @@ -0,0 +1,164 @@ +mod expr; + +use std::sync::Mutex; + +use common_error::{DaftError, DaftResult}; +use daft_core::{ + prelude::{AsArrow, DataType, Utf8Array}, + series::Series, +}; +use daft_dsl::{functions::ScalarFunction, ExprRef}; +use expr::JsonQuery; +use itertools::Itertools; +use jaq_interpret::{Ctx, Filter, FilterT, ParseCtx, RcIter}; +use lazy_static::lazy_static; +use serde_json::Value; + +fn setup_parse_ctx() -> ParseCtx { + // set up the parse context with the core and std libraries https://github.com/01mf02/jaq/tree/main?tab=readme-ov-file#features + let mut defs = ParseCtx::new(Vec::new()); + defs.insert_natives(jaq_core::core()); + defs.insert_defs(jaq_std::std()); + defs +} + +lazy_static! { + static ref PARSE_CTX: Mutex = Mutex::new(setup_parse_ctx()); +} + +fn compile_filter(query: &str) -> DaftResult { + // parse the filter + let (filter, errs) = jaq_parse::parse(query, jaq_parse::main()); + if !errs.is_empty() { + return Err(DaftError::ValueError(format!( + "Error parsing json query ({query}): {}", + errs.iter().map(|e| e.to_string()).join(", ") + ))); + } + + // compile the filter executable + let mut defs = PARSE_CTX.lock().unwrap(); + let compiled_filter = defs.compile(filter.unwrap()); + if !defs.errs.is_empty() { + return Err(DaftError::ComputeError(format!( + "Error compiling json query ({query}): {}", + defs.errs.iter().map(|(e, _)| e.to_string()).join(", ") + ))); + } + + Ok(compiled_filter) +} + +fn json_query_impl(arr: &Utf8Array, query: &str) -> DaftResult { + let compiled_filter = compile_filter(query)?; + let inputs = RcIter::new(core::iter::empty()); + + let self_arrow = arr.as_arrow(); + let name = arr.name().to_string(); + + let values = self_arrow + .iter() + .map(|opt| { + opt.map_or(Ok(None), |s| { + serde_json::from_str::(s) + .map_err(DaftError::from) + .and_then(|json| { + let res = compiled_filter + .run((Ctx::new([], &inputs), json.into())) + .map(|result| { + result.map(|v| v.to_string()).map_err(|e| { + DaftError::ComputeError(format!( + "Error running json query ({query}): {e}" + )) + }) + }) + .collect::>>() + .map(|values| Some(values.join("\n"))); + res + }) + }) + }) + .collect::>()?; + + values + .rename(&name) + .with_validity(self_arrow.validity().cloned()) +} + +pub fn json_query_series(s: &Series, query: &str) -> DaftResult { + match s.data_type() { + DataType::Utf8 => { + let arr = s.utf8()?; + json_query_impl(arr, query).map(daft_core::series::IntoSeries::into_series) + } + dt => Err(DaftError::TypeError(format!( + "json query not implemented for {}", + dt + ))), + } +} + +/// Executes a JSON query on a UTF-8 string array. +/// +/// # Arguments +/// +/// * `arr` - The input UTF-8 array containing JSON strings. +/// * `query` - The JSON query string to execute. +/// +/// # Returns +/// +/// A `DaftResult` containing the resulting UTF-8 array after applying the query. +pub fn json_query(input: ExprRef, query: &str) -> ExprRef { + ScalarFunction::new( + JsonQuery { + query: query.to_string(), + }, + vec![input], + ) + .into() +} + +#[cfg(feature = "python")] +use { + daft_dsl::python::PyExpr, + pyo3::{prelude::*, pyfunction, PyResult}, +}; + +#[cfg(feature = "python")] +#[pyfunction] +#[pyo3(name = "json_query")] +pub fn py_json_query(expr: PyExpr, query: &str) -> PyResult { + Ok(json_query(expr.into(), query).into()) +} + +#[cfg(feature = "python")] +pub fn register_modules(parent: &Bound) -> PyResult<()> { + parent.add_function(wrap_pyfunction_bound!(py_json_query, parent)?)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_json_query() -> DaftResult<()> { + let data = Utf8Array::from_values( + "data", + vec![ + r#"{"foo": {"bar": 1}}"#.to_string(), + r#"{"foo": {"bar": 2}}"#.to_string(), + r#"{"foo": {"bar": 3}}"#.to_string(), + ] + .into_iter(), + ); + + let query = r#".foo.bar"#; + let result = json_query_impl(&data, query)?; + assert_eq!(result.len(), 3); + assert_eq!(result.as_arrow().value(0), "1"); + assert_eq!(result.as_arrow().value(1), "2"); + assert_eq!(result.as_arrow().value(2), "3"); + Ok(()) + } +} diff --git a/src/daft-functions/Cargo.toml b/src/daft-functions/Cargo.toml index bd9281b4ea..e411d32614 100644 --- a/src/daft-functions/Cargo.toml +++ b/src/daft-functions/Cargo.toml @@ -23,6 +23,7 @@ python = [ "common-error/python", "daft-core/python", "daft-io/python", + "daft-dsl/python", "daft-image/python", "common-io-config/python" ] diff --git a/src/lib.rs b/src/lib.rs index 604901b056..a7a1382538 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,6 +117,8 @@ pub mod pylib { daft_scheduler::register_modules(m)?; daft_sql::register_modules(m)?; daft_functions::register_modules(m)?; + daft_functions_json::register_modules(m)?; + m.add_wrapped(wrap_pyfunction!(version))?; m.add_wrapped(wrap_pyfunction!(build_type))?; m.add_wrapped(wrap_pyfunction!(refresh_logger))?;