polars-df 0.15.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +274 -0
- data/Cargo.lock +1465 -867
- data/Cargo.toml +3 -0
- data/LICENSE.txt +2 -2
- data/README.md +87 -37
- data/ext/polars/Cargo.toml +47 -16
- data/ext/polars/src/c_api/allocator.rs +7 -0
- data/ext/polars/src/c_api/mod.rs +1 -0
- data/ext/polars/src/catalog/mod.rs +1 -0
- data/ext/polars/src/catalog/unity.rs +470 -0
- data/ext/polars/src/conversion/any_value.rs +99 -84
- data/ext/polars/src/conversion/categorical.rs +30 -0
- data/ext/polars/src/conversion/chunked_array.rs +71 -62
- data/ext/polars/src/conversion/datetime.rs +63 -0
- data/ext/polars/src/conversion/mod.rs +796 -312
- data/ext/polars/src/dataframe/construction.rs +6 -18
- data/ext/polars/src/dataframe/export.rs +30 -39
- data/ext/polars/src/dataframe/general.rs +294 -362
- data/ext/polars/src/dataframe/io.rs +33 -150
- data/ext/polars/src/dataframe/map.rs +175 -0
- data/ext/polars/src/dataframe/mod.rs +37 -5
- data/ext/polars/src/dataframe/serde.rs +23 -8
- data/ext/polars/src/error.rs +44 -7
- data/ext/polars/src/exceptions.rs +21 -8
- data/ext/polars/src/expr/array.rs +86 -22
- data/ext/polars/src/expr/binary.rs +50 -1
- data/ext/polars/src/expr/bitwise.rs +39 -0
- data/ext/polars/src/expr/categorical.rs +20 -0
- data/ext/polars/src/expr/datatype.rs +51 -0
- data/ext/polars/src/expr/datetime.rs +99 -41
- data/ext/polars/src/expr/extension.rs +12 -0
- data/ext/polars/src/expr/general.rs +252 -128
- data/ext/polars/src/expr/list.rs +56 -60
- data/ext/polars/src/expr/meta.rs +30 -35
- data/ext/polars/src/expr/mod.rs +28 -6
- data/ext/polars/src/expr/name.rs +29 -14
- data/ext/polars/src/expr/rolling.rs +111 -3
- data/ext/polars/src/expr/selector.rs +219 -0
- data/ext/polars/src/expr/serde.rs +28 -0
- data/ext/polars/src/expr/string.rs +118 -20
- data/ext/polars/src/expr/struct.rs +14 -1
- data/ext/polars/src/file.rs +194 -86
- data/ext/polars/src/functions/aggregation.rs +13 -12
- data/ext/polars/src/functions/business.rs +2 -3
- data/ext/polars/src/functions/eager.rs +3 -2
- data/ext/polars/src/functions/io.rs +90 -18
- data/ext/polars/src/functions/lazy.rs +267 -118
- data/ext/polars/src/functions/meta.rs +8 -7
- data/ext/polars/src/functions/misc.rs +1 -1
- data/ext/polars/src/functions/mod.rs +2 -1
- data/ext/polars/src/functions/range.rs +88 -31
- data/ext/polars/src/functions/strings.rs +6 -0
- data/ext/polars/src/functions/utils.rs +8 -0
- data/ext/polars/src/interop/arrow/mod.rs +52 -1
- data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
- data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
- data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
- data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
- data/ext/polars/src/io/cloud_options.rs +107 -0
- data/ext/polars/src/io/mod.rs +4 -0
- data/ext/polars/src/io/scan_options.rs +113 -0
- data/ext/polars/src/io/sink_options.rs +46 -0
- data/ext/polars/src/io/sink_output.rs +21 -0
- data/ext/polars/src/lazyframe/exitable.rs +39 -0
- data/ext/polars/src/lazyframe/general.rs +846 -368
- data/ext/polars/src/lazyframe/mod.rs +58 -5
- data/ext/polars/src/lazyframe/optflags.rs +59 -0
- data/ext/polars/src/lazyframe/serde.rs +36 -4
- data/ext/polars/src/lazyframe/sink.rs +46 -0
- data/ext/polars/src/lazygroupby.rs +38 -9
- data/ext/polars/src/lib.rs +574 -165
- data/ext/polars/src/map/lazy.rs +44 -74
- data/ext/polars/src/map/mod.rs +18 -254
- data/ext/polars/src/map/series.rs +241 -1087
- data/ext/polars/src/on_startup.rs +192 -9
- data/ext/polars/src/prelude.rs +1 -0
- data/ext/polars/src/rb_modules.rs +10 -57
- data/ext/polars/src/ruby/exceptions.rs +26 -0
- data/ext/polars/src/ruby/gvl.rs +104 -0
- data/ext/polars/src/ruby/lazy.rs +46 -0
- data/ext/polars/src/ruby/mod.rs +11 -0
- data/ext/polars/src/ruby/numo.rs +52 -0
- data/ext/polars/src/ruby/plan_callback.rs +198 -0
- data/ext/polars/src/ruby/rb_modules.rs +16 -0
- data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
- data/ext/polars/src/ruby/ruby_function.rs +11 -0
- data/ext/polars/src/ruby/ruby_udf.rs +164 -0
- data/ext/polars/src/ruby/thread.rs +65 -0
- data/ext/polars/src/ruby/utils.rs +39 -0
- data/ext/polars/src/series/aggregation.rs +116 -91
- data/ext/polars/src/series/arithmetic.rs +16 -22
- data/ext/polars/src/series/comparison.rs +101 -222
- data/ext/polars/src/series/construction.rs +80 -70
- data/ext/polars/src/series/export.rs +98 -56
- data/ext/polars/src/series/general.rs +323 -440
- data/ext/polars/src/series/import.rs +22 -5
- data/ext/polars/src/series/map.rs +103 -0
- data/ext/polars/src/series/mod.rs +57 -15
- data/ext/polars/src/series/scatter.rs +139 -82
- data/ext/polars/src/sql.rs +16 -9
- data/ext/polars/src/testing/frame.rs +31 -0
- data/ext/polars/src/testing/mod.rs +5 -0
- data/ext/polars/src/testing/series.rs +31 -0
- data/ext/polars/src/timeout.rs +105 -0
- data/ext/polars/src/utils.rs +105 -4
- data/lib/polars/array_expr.rb +500 -22
- data/lib/polars/array_name_space.rb +384 -10
- data/lib/polars/batched_csv_reader.rb +48 -66
- data/lib/polars/binary_expr.rb +217 -0
- data/lib/polars/binary_name_space.rb +155 -1
- data/lib/polars/cat_expr.rb +224 -0
- data/lib/polars/cat_name_space.rb +132 -32
- data/lib/polars/catalog/unity/catalog_info.rb +20 -0
- data/lib/polars/catalog/unity/column_info.rb +31 -0
- data/lib/polars/catalog/unity/namespace_info.rb +21 -0
- data/lib/polars/catalog/unity/table_info.rb +50 -0
- data/lib/polars/catalog.rb +448 -0
- data/lib/polars/collect_batches.rb +22 -0
- data/lib/polars/config.rb +3 -3
- data/lib/polars/convert.rb +201 -36
- data/lib/polars/data_frame.rb +2851 -1017
- data/lib/polars/data_frame_plot.rb +173 -0
- data/lib/polars/data_type_expr.rb +52 -0
- data/lib/polars/data_type_group.rb +6 -0
- data/lib/polars/data_types.rb +118 -18
- data/lib/polars/date_time_expr.rb +426 -84
- data/lib/polars/date_time_name_space.rb +384 -111
- data/lib/polars/dynamic_group_by.rb +102 -10
- data/lib/polars/exceptions.rb +50 -5
- data/lib/polars/expr.rb +2159 -915
- data/lib/polars/extension_expr.rb +39 -0
- data/lib/polars/extension_name_space.rb +39 -0
- data/lib/polars/functions/aggregation/horizontal.rb +11 -6
- data/lib/polars/functions/aggregation/vertical.rb +2 -3
- data/lib/polars/functions/as_datatype.rb +290 -8
- data/lib/polars/functions/business.rb +95 -0
- data/lib/polars/functions/col.rb +6 -5
- data/lib/polars/functions/datatype.rb +62 -0
- data/lib/polars/functions/eager.rb +426 -24
- data/lib/polars/functions/escape_regex.rb +21 -0
- data/lib/polars/functions/lazy.rb +813 -195
- data/lib/polars/functions/lit.rb +21 -10
- data/lib/polars/functions/range/int_range.rb +74 -2
- data/lib/polars/functions/range/linear_space.rb +195 -0
- data/lib/polars/functions/range/time_range.rb +1 -1
- data/lib/polars/functions/repeat.rb +7 -12
- data/lib/polars/functions/whenthen.rb +2 -2
- data/lib/polars/group_by.rb +188 -58
- data/lib/polars/iceberg_dataset.rb +108 -0
- data/lib/polars/in_process_query.rb +37 -0
- data/lib/polars/io/cloud.rb +18 -0
- data/lib/polars/io/csv.rb +336 -128
- data/lib/polars/io/database.rb +19 -4
- data/lib/polars/io/delta.rb +134 -0
- data/lib/polars/io/iceberg.rb +34 -0
- data/lib/polars/io/ipc.rb +63 -63
- data/lib/polars/io/json.rb +16 -0
- data/lib/polars/io/lines.rb +172 -0
- data/lib/polars/io/ndjson.rb +176 -20
- data/lib/polars/io/parquet.rb +173 -95
- data/lib/polars/io/scan_options.rb +55 -0
- data/lib/polars/io/sink_options.rb +27 -0
- data/lib/polars/io/utils.rb +17 -0
- data/lib/polars/lazy_frame.rb +3017 -622
- data/lib/polars/lazy_group_by.rb +436 -2
- data/lib/polars/list_expr.rb +551 -59
- data/lib/polars/list_name_space.rb +465 -51
- data/lib/polars/meta_expr.rb +146 -24
- data/lib/polars/name_expr.rb +87 -2
- data/lib/polars/query_opt_flags.rb +264 -0
- data/lib/polars/rolling_group_by.rb +90 -5
- data/lib/polars/scan_cast_options.rb +86 -0
- data/lib/polars/schema.rb +128 -0
- data/lib/polars/selector.rb +245 -0
- data/lib/polars/selectors.rb +1048 -201
- data/lib/polars/series.rb +2522 -774
- data/lib/polars/series_plot.rb +72 -0
- data/lib/polars/slice.rb +1 -1
- data/lib/polars/sql_context.rb +13 -6
- data/lib/polars/string_cache.rb +19 -72
- data/lib/polars/string_expr.rb +561 -107
- data/lib/polars/string_name_space.rb +781 -109
- data/lib/polars/struct_expr.rb +139 -18
- data/lib/polars/struct_name_space.rb +19 -1
- data/lib/polars/testing.rb +24 -273
- data/lib/polars/utils/constants.rb +2 -0
- data/lib/polars/utils/construction/data_frame.rb +410 -0
- data/lib/polars/utils/construction/series.rb +350 -0
- data/lib/polars/utils/construction/utils.rb +9 -0
- data/lib/polars/utils/convert.rb +18 -8
- data/lib/polars/utils/deprecation.rb +11 -0
- data/lib/polars/utils/parse.rb +62 -9
- data/lib/polars/utils/reduce_balanced.rb +43 -0
- data/lib/polars/utils/serde.rb +22 -0
- data/lib/polars/utils/unstable.rb +19 -0
- data/lib/polars/utils/various.rb +86 -1
- data/lib/polars/utils.rb +63 -48
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +85 -2
- metadata +80 -28
- data/ext/polars/src/allocator.rs +0 -13
- data/ext/polars/src/batched_csv.rs +0 -138
- data/ext/polars/src/functions/string_cache.rs +0 -25
- data/ext/polars/src/map/dataframe.rs +0 -338
- data/lib/polars/plot.rb +0 -109
|
@@ -1,13 +1,30 @@
|
|
|
1
|
-
use
|
|
1
|
+
use arrow::array::Array;
|
|
2
|
+
use arrow::ffi;
|
|
3
|
+
use arrow::ffi::{ArrowArrayStream, ArrowArrayStreamReader};
|
|
2
4
|
use magnus::Value;
|
|
3
|
-
use
|
|
4
|
-
use polars::export::arrow::ffi::{ArrowArrayStream, ArrowArrayStreamReader};
|
|
5
|
+
use magnus::prelude::*;
|
|
5
6
|
use polars::prelude::*;
|
|
6
7
|
|
|
7
8
|
use super::RbSeries;
|
|
8
9
|
|
|
9
|
-
use crate::exceptions::RbValueError;
|
|
10
10
|
use crate::RbResult;
|
|
11
|
+
use crate::ruby::exceptions::RbValueError;
|
|
12
|
+
|
|
13
|
+
pub(crate) fn import_schema_rbcapsule(schema_capsule: Value) -> RbResult<arrow::datatypes::Field> {
|
|
14
|
+
let capsule_pointer: usize = schema_capsule.funcall("to_i", ())?;
|
|
15
|
+
|
|
16
|
+
// # Safety
|
|
17
|
+
// schema_capsule holds a valid C ArrowSchema pointer, as defined by the Arrow PyCapsule
|
|
18
|
+
// Interface
|
|
19
|
+
unsafe {
|
|
20
|
+
let schema_ptr = (capsule_pointer as *const ffi::ArrowSchema)
|
|
21
|
+
.as_ref()
|
|
22
|
+
.unwrap();
|
|
23
|
+
let field = ffi::import_field_from_c(schema_ptr).unwrap();
|
|
24
|
+
|
|
25
|
+
Ok(field)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
11
28
|
|
|
12
29
|
/// Import `arrow_c_stream` across Ruby boundary.
|
|
13
30
|
fn call_arrow_c_stream(ob: Value) -> RbResult<Value> {
|
|
@@ -39,7 +56,7 @@ pub(crate) fn import_stream_rbcapsule(capsule: Value) -> RbResult<RbSeries> {
|
|
|
39
56
|
|
|
40
57
|
// Series::try_from fails for an empty vec of chunks
|
|
41
58
|
let s = if produced_arrays.is_empty() {
|
|
42
|
-
let polars_dt = DataType::
|
|
59
|
+
let polars_dt = DataType::from_arrow_field(stream.field());
|
|
43
60
|
Series::new_empty(stream.field().name.clone(), &polars_dt)
|
|
44
61
|
} else {
|
|
45
62
|
Series::try_from((stream.field(), produced_arrays)).unwrap()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
use magnus::{IntoValue, Ruby, Value, value::Opaque, value::ReprValue};
|
|
2
|
+
|
|
3
|
+
use super::RbSeries;
|
|
4
|
+
use crate::map::series::ApplyLambdaGeneric;
|
|
5
|
+
use crate::prelude::*;
|
|
6
|
+
use crate::ruby::gvl::GvlExt;
|
|
7
|
+
use crate::ruby::utils::TryIntoValue;
|
|
8
|
+
use crate::series::construction::series_from_objects;
|
|
9
|
+
use crate::{RbPolarsErr, RbResult};
|
|
10
|
+
use crate::{apply_all_polars_dtypes, raise_err};
|
|
11
|
+
|
|
12
|
+
impl RbSeries {
|
|
13
|
+
pub fn map_elements(
|
|
14
|
+
&self,
|
|
15
|
+
function: Value,
|
|
16
|
+
return_dtype: Option<Wrap<DataType>>,
|
|
17
|
+
skip_nulls: bool,
|
|
18
|
+
) -> RbResult<Self> {
|
|
19
|
+
let series = &self.series.read().clone(); // Clone so we don't deadlock on re-entrance.
|
|
20
|
+
|
|
21
|
+
if return_dtype.is_none() {
|
|
22
|
+
polars_warn!(
|
|
23
|
+
MapWithoutReturnDtypeWarning,
|
|
24
|
+
"Calling `map_elements` without specifying `return_dtype` can lead to unpredictable results. \
|
|
25
|
+
Specify `return_dtype` to silence this warning."
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if skip_nulls && (series.null_count() == series.len()) {
|
|
30
|
+
if let Some(return_dtype) = return_dtype {
|
|
31
|
+
return Ok(
|
|
32
|
+
Series::full_null(series.name().clone(), series.len(), &return_dtype.0).into(),
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
let msg = "The output type of the 'map_elements' function cannot be determined.\n\
|
|
36
|
+
The function was never called because 'skip_nulls: true' and all values are null.\n\
|
|
37
|
+
Consider setting 'skip_nulls: false' or setting the 'return_dtype'.";
|
|
38
|
+
raise_err!(msg, ComputeError)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let return_dtype = return_dtype.map(|dt| dt.0);
|
|
42
|
+
|
|
43
|
+
Ruby::attach(|rb| {
|
|
44
|
+
let s = match &return_dtype {
|
|
45
|
+
Some(DataType::Object(_)) => {
|
|
46
|
+
// If the return dtype is Object we should not go through AnyValue.
|
|
47
|
+
call_and_collect_objects(
|
|
48
|
+
rb,
|
|
49
|
+
series.name().clone(),
|
|
50
|
+
function,
|
|
51
|
+
series.len(),
|
|
52
|
+
series.iter().map(|av| av.null_to_none().map(Wrap)),
|
|
53
|
+
skip_nulls,
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
Some(return_dtype) => {
|
|
57
|
+
apply_all_polars_dtypes!(
|
|
58
|
+
series,
|
|
59
|
+
apply_generic_with_dtype,
|
|
60
|
+
rb,
|
|
61
|
+
function,
|
|
62
|
+
return_dtype,
|
|
63
|
+
skip_nulls
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
None => apply_all_polars_dtypes!(series, apply_generic, rb, function, skip_nulls),
|
|
67
|
+
};
|
|
68
|
+
s.map(RbSeries::from)
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn call_and_collect_objects<T, I>(
|
|
74
|
+
rb: &Ruby,
|
|
75
|
+
name: PlSmallStr,
|
|
76
|
+
lambda: Value,
|
|
77
|
+
len: usize,
|
|
78
|
+
iter: I,
|
|
79
|
+
skip_nulls: bool,
|
|
80
|
+
) -> RbResult<Series>
|
|
81
|
+
where
|
|
82
|
+
T: TryIntoValue,
|
|
83
|
+
I: Iterator<Item = Option<T>>,
|
|
84
|
+
{
|
|
85
|
+
let mut objects = Vec::with_capacity(len);
|
|
86
|
+
for opt_val in iter {
|
|
87
|
+
let arg = match opt_val {
|
|
88
|
+
None if skip_nulls => {
|
|
89
|
+
objects.push(ObjectValue {
|
|
90
|
+
inner: Opaque::from(rb.qnil().into_value_with(rb)),
|
|
91
|
+
});
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
None => rb.qnil().into_value_with(rb),
|
|
95
|
+
Some(val) => val.try_into_value_with(rb)?,
|
|
96
|
+
};
|
|
97
|
+
let out: Value = lambda.funcall("call", (arg,))?;
|
|
98
|
+
objects.push(ObjectValue {
|
|
99
|
+
inner: Opaque::from(out),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
Ok(series_from_objects(rb, name, objects))
|
|
103
|
+
}
|
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
mod aggregation;
|
|
2
2
|
mod arithmetic;
|
|
3
3
|
mod comparison;
|
|
4
|
-
mod construction;
|
|
4
|
+
pub(crate) mod construction;
|
|
5
5
|
mod export;
|
|
6
6
|
mod general;
|
|
7
7
|
mod import;
|
|
8
|
+
mod map;
|
|
8
9
|
mod scatter;
|
|
9
10
|
|
|
10
|
-
use
|
|
11
|
+
pub(crate) use import::import_schema_rbcapsule;
|
|
12
|
+
|
|
13
|
+
use magnus::{DataTypeFunctions, RArray, Ruby, TypedData, gc, prelude::*};
|
|
14
|
+
use parking_lot::RwLock;
|
|
11
15
|
use polars::prelude::*;
|
|
12
|
-
use std::cell::RefCell;
|
|
13
16
|
|
|
14
|
-
use crate::RbResult;
|
|
17
|
+
use crate::{ObjectValue, RbResult};
|
|
15
18
|
|
|
16
|
-
#[
|
|
19
|
+
#[derive(TypedData)]
|
|
20
|
+
#[magnus(class = "Polars::RbSeries", mark)]
|
|
17
21
|
pub struct RbSeries {
|
|
18
|
-
pub series:
|
|
22
|
+
pub series: RwLock<Series>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl Clone for RbSeries {
|
|
26
|
+
fn clone(&self) -> Self {
|
|
27
|
+
Self {
|
|
28
|
+
series: RwLock::new(self.series.read().clone()),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
impl From<Series> for RbSeries {
|
|
22
34
|
fn from(series: Series) -> Self {
|
|
23
|
-
|
|
35
|
+
Self::new(series)
|
|
24
36
|
}
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
impl RbSeries {
|
|
28
40
|
pub fn new(series: Series) -> Self {
|
|
29
41
|
RbSeries {
|
|
30
|
-
series:
|
|
42
|
+
series: RwLock::new(series),
|
|
31
43
|
}
|
|
32
44
|
}
|
|
33
45
|
}
|
|
@@ -35,15 +47,45 @@ impl RbSeries {
|
|
|
35
47
|
pub fn to_series(rs: RArray) -> RbResult<Vec<Series>> {
|
|
36
48
|
let mut series = Vec::new();
|
|
37
49
|
for item in rs.into_iter() {
|
|
38
|
-
series.push(<&RbSeries>::try_convert(item)?.series.
|
|
50
|
+
series.push(<&RbSeries>::try_convert(item)?.series.read().clone());
|
|
39
51
|
}
|
|
40
52
|
Ok(series)
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
pub
|
|
44
|
-
RArray
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
55
|
+
pub(crate) trait ToRbSeries {
|
|
56
|
+
fn to_rbseries(self, rb: &Ruby) -> RArray;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
impl ToRbSeries for Vec<Column> {
|
|
60
|
+
fn to_rbseries(self, rb: &Ruby) -> RArray {
|
|
61
|
+
rb.ary_from_iter(
|
|
62
|
+
self.into_iter()
|
|
63
|
+
.map(|c| c.take_materialized_series())
|
|
64
|
+
.map(RbSeries::new),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pub fn mark_series(marker: &gc::Marker, series: &Series) {
|
|
70
|
+
if let DataType::Object(_) = series.dtype() {
|
|
71
|
+
for i in 0..series.len() {
|
|
72
|
+
let obj: Option<&ObjectValue> = series.get_object(i).map(|any| any.into());
|
|
73
|
+
if let Some(o) = obj {
|
|
74
|
+
marker.mark(o.inner);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
impl DataTypeFunctions for RbSeries {
|
|
81
|
+
fn mark(&self, marker: &gc::Marker) {
|
|
82
|
+
// this is not ideal, as objects will not be marked if unable to borrow
|
|
83
|
+
// this should never happen, but log for now to avoid panic,
|
|
84
|
+
// as most series will not use Object datatype
|
|
85
|
+
if let Some(s) = &self.series.try_read() {
|
|
86
|
+
mark_series(marker, s);
|
|
87
|
+
} else {
|
|
88
|
+
eprintln!("[polars] Could not borrow!");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
49
91
|
}
|
|
@@ -1,107 +1,164 @@
|
|
|
1
|
-
use
|
|
1
|
+
use arrow::array::Array;
|
|
2
2
|
use polars::prelude::*;
|
|
3
3
|
|
|
4
|
-
use crate::
|
|
5
|
-
use crate::{
|
|
4
|
+
use crate::utils::EnterPolarsExt;
|
|
5
|
+
use crate::{RbResult, RbSeries, Ruby};
|
|
6
6
|
|
|
7
7
|
impl RbSeries {
|
|
8
|
-
pub fn scatter(&
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
pub fn scatter(rb: &Ruby, self_: &Self, idx: &RbSeries, values: &RbSeries) -> RbResult<()> {
|
|
9
|
+
rb.enter_polars(|| {
|
|
10
|
+
// We take the value because we want a ref count of 1 so that we can
|
|
11
|
+
// have mutable access cheaply via _get_inner_mut().
|
|
12
|
+
let mut lock = self_.series.write();
|
|
13
|
+
let s = std::mem::take(&mut *lock);
|
|
14
|
+
let result = scatter(
|
|
15
|
+
s,
|
|
16
|
+
&idx.clone().series.into_inner(),
|
|
17
|
+
&values.clone().series.into_inner(),
|
|
18
|
+
);
|
|
19
|
+
match result {
|
|
20
|
+
Ok(out) => {
|
|
21
|
+
*lock = out;
|
|
22
|
+
Ok(())
|
|
23
|
+
}
|
|
24
|
+
Err((s, e)) => {
|
|
25
|
+
*lock = s; // Restore original series.
|
|
26
|
+
Err(e)
|
|
27
|
+
}
|
|
14
28
|
}
|
|
15
|
-
|
|
16
|
-
}
|
|
29
|
+
})
|
|
17
30
|
}
|
|
18
31
|
}
|
|
19
32
|
|
|
20
|
-
fn scatter(
|
|
33
|
+
fn scatter(s: Series, idx: &Series, values: &Series) -> Result<Series, (Series, PolarsError)> {
|
|
21
34
|
let logical_dtype = s.dtype().clone();
|
|
22
|
-
let
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
let converted_values;
|
|
36
|
+
let values = if logical_dtype.is_categorical() || logical_dtype.is_enum() {
|
|
37
|
+
if matches!(
|
|
38
|
+
values.dtype(),
|
|
39
|
+
DataType::Categorical(_, _) | DataType::Enum(_, _) | DataType::String | DataType::Null
|
|
40
|
+
) {
|
|
41
|
+
converted_values = values.strict_cast(&logical_dtype);
|
|
42
|
+
match converted_values {
|
|
43
|
+
Ok(ref values) => values,
|
|
44
|
+
Err(err) => return Err((s, err)),
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
return Err((
|
|
48
|
+
s,
|
|
49
|
+
polars_err!(InvalidOperation: "invalid values dtype '{}' for scattering into dtype '{}'", values.dtype(), logical_dtype),
|
|
50
|
+
));
|
|
51
|
+
}
|
|
52
|
+
} else if logical_dtype.is_decimal() {
|
|
53
|
+
if values.dtype().is_numeric() {
|
|
54
|
+
converted_values = values.strict_cast(&logical_dtype);
|
|
55
|
+
match converted_values {
|
|
56
|
+
Ok(ref values) => values,
|
|
57
|
+
Err(err) => return Err((s, err)),
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
return Err((
|
|
61
|
+
s,
|
|
62
|
+
polars_err!(InvalidOperation: "invalid values dtype '{}' for scattering into dtype '{}'", values.dtype(), logical_dtype),
|
|
63
|
+
));
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
values
|
|
67
|
+
};
|
|
26
68
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
69
|
+
let null_on_oob = false;
|
|
70
|
+
let idx = match polars_ops::prelude::convert_and_bound_index(idx, s.len(), null_on_oob) {
|
|
71
|
+
Ok(idx) => idx,
|
|
72
|
+
Err(err) => return Err((s, err)),
|
|
73
|
+
};
|
|
74
|
+
let idx = idx.rechunk();
|
|
75
|
+
let idx = idx.downcast_as_array();
|
|
76
|
+
if idx.has_nulls() {
|
|
77
|
+
return Err((
|
|
78
|
+
s,
|
|
79
|
+
PolarsError::ComputeError("index values should not be null".into()),
|
|
30
80
|
));
|
|
31
81
|
}
|
|
32
|
-
|
|
33
82
|
let idx = idx.values().as_slice();
|
|
34
83
|
|
|
35
|
-
let values = values.to_physical_repr().cast(&s.dtype().to_physical())
|
|
84
|
+
let mut values = match values.to_physical_repr().cast(&s.dtype().to_physical()) {
|
|
85
|
+
Ok(values) => values,
|
|
86
|
+
Err(err) => return Err((s, err)),
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Broadcast values input.
|
|
90
|
+
if values.len() == 1 && idx.len() > 1 {
|
|
91
|
+
values = values.new_from_index(0, idx.len());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let mut phys = s.to_physical_repr().into_owned();
|
|
95
|
+
drop(s); // Reduce refcount to make use of in-place mutation of possible.
|
|
96
|
+
let ret = scatter_impl(&mut phys, &logical_dtype, idx, &values);
|
|
97
|
+
match ret {
|
|
98
|
+
Ok(s) => Ok(unsafe { s.from_physical_unchecked(&logical_dtype).unwrap() }),
|
|
99
|
+
Err(e) => Err((
|
|
100
|
+
unsafe { phys.from_physical_unchecked(&logical_dtype).unwrap() },
|
|
101
|
+
e,
|
|
102
|
+
)),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
36
105
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
106
|
+
macro_rules! with_match_physical_numeric_polars_type {(
|
|
107
|
+
$key_type:expr, | $_:tt $T:ident | $($body:tt)*
|
|
108
|
+
) => ({
|
|
109
|
+
macro_rules! __with_ty__ {( $_ $T:ident ) => ( $($body)* )}
|
|
110
|
+
use polars_core::datatypes::DataType::*;
|
|
111
|
+
match $key_type {
|
|
112
|
+
Int8 => __with_ty__! { Int8Type },
|
|
113
|
+
Int16 => __with_ty__! { Int16Type },
|
|
114
|
+
Int32 => __with_ty__! { Int32Type },
|
|
115
|
+
Int64 => __with_ty__! { Int64Type },
|
|
116
|
+
Int128 => __with_ty__! { Int128Type },
|
|
117
|
+
UInt8 => __with_ty__! { UInt8Type },
|
|
118
|
+
UInt16 => __with_ty__! { UInt16Type },
|
|
119
|
+
UInt32 => __with_ty__! { UInt32Type },
|
|
120
|
+
UInt64 => __with_ty__! { UInt64Type },
|
|
121
|
+
UInt128 => __with_ty__! { UInt128Type },
|
|
122
|
+
Float16 => __with_ty__! { Float16Type },
|
|
123
|
+
Float32 => __with_ty__! { Float32Type },
|
|
124
|
+
Float64 => __with_ty__! { Float64Type },
|
|
125
|
+
dt => panic!("not implemented for dtype {:?}", dt),
|
|
126
|
+
}
|
|
127
|
+
})}
|
|
128
|
+
|
|
129
|
+
fn scatter_impl(
|
|
130
|
+
s: &mut Series,
|
|
131
|
+
logical_dtype: &DataType,
|
|
132
|
+
idx: &[IdxSize],
|
|
133
|
+
values: &Series,
|
|
134
|
+
) -> PolarsResult<Series> {
|
|
40
135
|
let mutable_s = s._get_inner_mut();
|
|
41
136
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let ca: &mut ChunkedArray<Int16Type> = mutable_s.as_mut();
|
|
50
|
-
let values = values.i16()?;
|
|
51
|
-
std::mem::take(ca).scatter(idx, values)
|
|
52
|
-
}
|
|
53
|
-
DataType::Int32 => {
|
|
54
|
-
let ca: &mut ChunkedArray<Int32Type> = mutable_s.as_mut();
|
|
55
|
-
let values = values.i32()?;
|
|
56
|
-
std::mem::take(ca).scatter(idx, values)
|
|
57
|
-
}
|
|
58
|
-
DataType::Int64 => {
|
|
59
|
-
let ca: &mut ChunkedArray<Int64Type> = mutable_s.as_mut();
|
|
60
|
-
let values = values.i64()?;
|
|
61
|
-
std::mem::take(ca).scatter(idx, values)
|
|
62
|
-
}
|
|
63
|
-
DataType::UInt8 => {
|
|
64
|
-
let ca: &mut ChunkedArray<UInt8Type> = mutable_s.as_mut();
|
|
65
|
-
let values = values.u8()?;
|
|
66
|
-
std::mem::take(ca).scatter(idx, values)
|
|
67
|
-
}
|
|
68
|
-
DataType::UInt16 => {
|
|
69
|
-
let ca: &mut ChunkedArray<UInt16Type> = mutable_s.as_mut();
|
|
70
|
-
let values = values.u16()?;
|
|
71
|
-
std::mem::take(ca).scatter(idx, values)
|
|
72
|
-
}
|
|
73
|
-
DataType::UInt32 => {
|
|
74
|
-
let ca: &mut ChunkedArray<UInt32Type> = mutable_s.as_mut();
|
|
75
|
-
let values = values.u32()?;
|
|
76
|
-
std::mem::take(ca).scatter(idx, values)
|
|
77
|
-
}
|
|
78
|
-
DataType::UInt64 => {
|
|
79
|
-
let ca: &mut ChunkedArray<UInt64Type> = mutable_s.as_mut();
|
|
80
|
-
let values = values.u64()?;
|
|
81
|
-
std::mem::take(ca).scatter(idx, values)
|
|
82
|
-
}
|
|
83
|
-
DataType::Float32 => {
|
|
84
|
-
let ca: &mut ChunkedArray<Float32Type> = mutable_s.as_mut();
|
|
85
|
-
let values = values.f32()?;
|
|
86
|
-
std::mem::take(ca).scatter(idx, values)
|
|
87
|
-
}
|
|
88
|
-
DataType::Float64 => {
|
|
89
|
-
let ca: &mut ChunkedArray<Float64Type> = mutable_s.as_mut();
|
|
90
|
-
let values = values.f64()?;
|
|
91
|
-
std::mem::take(ca).scatter(idx, values)
|
|
137
|
+
match mutable_s.dtype() {
|
|
138
|
+
dt if dt.is_primitive_numeric() => {
|
|
139
|
+
with_match_physical_numeric_polars_type!(dt, |$T| {
|
|
140
|
+
let ca: &mut ChunkedArray<$T> = mutable_s.as_mut();
|
|
141
|
+
let values: &ChunkedArray<$T> = values.as_ref().as_ref();
|
|
142
|
+
ca.scatter(idx, values.iter())
|
|
143
|
+
})
|
|
92
144
|
}
|
|
93
145
|
DataType::Boolean => {
|
|
94
|
-
let ca =
|
|
146
|
+
let ca: &mut ChunkedArray<BooleanType> = mutable_s.as_mut();
|
|
95
147
|
let values = values.bool()?;
|
|
96
|
-
ca.scatter(idx, values)
|
|
148
|
+
ca.scatter(idx, values.iter())
|
|
149
|
+
}
|
|
150
|
+
DataType::Binary => {
|
|
151
|
+
let ca: &mut ChunkedArray<BinaryType> = mutable_s.as_mut();
|
|
152
|
+
let values = values.binary()?;
|
|
153
|
+
ca.scatter(idx, values.iter())
|
|
97
154
|
}
|
|
98
155
|
DataType::String => {
|
|
99
|
-
let ca =
|
|
156
|
+
let ca: &mut ChunkedArray<StringType> = mutable_s.as_mut();
|
|
100
157
|
let values = values.str()?;
|
|
101
|
-
ca.scatter(idx, values)
|
|
158
|
+
ca.scatter(idx, values.iter())
|
|
102
159
|
}
|
|
103
|
-
_ =>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
160
|
+
_ => Err(PolarsError::ComputeError(
|
|
161
|
+
format!("not yet implemented for dtype: {logical_dtype}").into(),
|
|
162
|
+
)),
|
|
163
|
+
}
|
|
107
164
|
}
|
data/ext/polars/src/sql.rs
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
use parking_lot::RwLock;
|
|
1
2
|
use polars::sql::SQLContext;
|
|
2
|
-
use std::cell::RefCell;
|
|
3
3
|
|
|
4
4
|
use crate::{RbLazyFrame, RbPolarsErr, RbResult};
|
|
5
5
|
|
|
6
6
|
#[magnus::wrap(class = "Polars::RbSQLContext")]
|
|
7
7
|
#[repr(transparent)]
|
|
8
|
-
#[derive(Clone)]
|
|
9
8
|
pub struct RbSQLContext {
|
|
10
|
-
pub context:
|
|
9
|
+
pub context: RwLock<SQLContext>,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
impl Clone for RbSQLContext {
|
|
13
|
+
fn clone(&self) -> Self {
|
|
14
|
+
Self {
|
|
15
|
+
context: RwLock::new(self.context.read().clone()),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
#[allow(
|
|
@@ -19,30 +26,30 @@ impl RbSQLContext {
|
|
|
19
26
|
#[allow(clippy::new_without_default)]
|
|
20
27
|
pub fn new() -> RbSQLContext {
|
|
21
28
|
RbSQLContext {
|
|
22
|
-
context: SQLContext::new()
|
|
29
|
+
context: RwLock::new(SQLContext::new()),
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
pub fn execute(&self, query: String) -> RbResult<RbLazyFrame> {
|
|
27
34
|
Ok(self
|
|
28
35
|
.context
|
|
29
|
-
.
|
|
36
|
+
.write()
|
|
30
37
|
.execute(&query)
|
|
31
38
|
.map_err(RbPolarsErr::from)?
|
|
32
39
|
.into())
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
pub fn get_tables(&self) -> RbResult<Vec<String>> {
|
|
36
|
-
Ok(self.context.
|
|
43
|
+
Ok(self.context.read().get_tables())
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
pub fn register(&self, name: String, lf: &RbLazyFrame) {
|
|
40
47
|
self.context
|
|
41
|
-
.
|
|
42
|
-
.register(&name, lf.
|
|
48
|
+
.write()
|
|
49
|
+
.register(&name, lf.clone().ldf.into_inner())
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
pub fn unregister(&self, name: String) {
|
|
46
|
-
self.context.
|
|
53
|
+
self.context.write().unregister(&name)
|
|
47
54
|
}
|
|
48
55
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
use polars_testing::asserts::{DataFrameEqualOptions, assert_dataframe_equal};
|
|
2
|
+
|
|
3
|
+
use crate::error::RbPolarsErr;
|
|
4
|
+
use crate::{RbDataFrame, RbResult};
|
|
5
|
+
|
|
6
|
+
pub fn assert_dataframe_equal_rb(
|
|
7
|
+
left: &RbDataFrame,
|
|
8
|
+
right: &RbDataFrame,
|
|
9
|
+
check_row_order: bool,
|
|
10
|
+
check_column_order: bool,
|
|
11
|
+
check_dtypes: bool,
|
|
12
|
+
check_exact: bool,
|
|
13
|
+
rel_tol: f64,
|
|
14
|
+
abs_tol: f64,
|
|
15
|
+
categorical_as_str: bool,
|
|
16
|
+
) -> RbResult<()> {
|
|
17
|
+
let left_df = &left.df.read();
|
|
18
|
+
let right_df = &right.df.read();
|
|
19
|
+
|
|
20
|
+
let options = DataFrameEqualOptions {
|
|
21
|
+
check_row_order,
|
|
22
|
+
check_column_order,
|
|
23
|
+
check_dtypes,
|
|
24
|
+
check_exact,
|
|
25
|
+
rel_tol,
|
|
26
|
+
abs_tol,
|
|
27
|
+
categorical_as_str,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
assert_dataframe_equal(left_df, right_df, options).map_err(|e| RbPolarsErr::from(e).into())
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
use polars_testing::asserts::{SeriesEqualOptions, assert_series_equal};
|
|
2
|
+
|
|
3
|
+
use crate::error::RbPolarsErr;
|
|
4
|
+
use crate::{RbResult, RbSeries};
|
|
5
|
+
|
|
6
|
+
pub fn assert_series_equal_rb(
|
|
7
|
+
left: &RbSeries,
|
|
8
|
+
right: &RbSeries,
|
|
9
|
+
check_dtypes: bool,
|
|
10
|
+
check_names: bool,
|
|
11
|
+
check_order: bool,
|
|
12
|
+
check_exact: bool,
|
|
13
|
+
rel_tol: f64,
|
|
14
|
+
abs_tol: f64,
|
|
15
|
+
categorical_as_str: bool,
|
|
16
|
+
) -> RbResult<()> {
|
|
17
|
+
let left_series = &left.series.read();
|
|
18
|
+
let right_series = &right.series.read();
|
|
19
|
+
|
|
20
|
+
let options = SeriesEqualOptions {
|
|
21
|
+
check_dtypes,
|
|
22
|
+
check_names,
|
|
23
|
+
check_order,
|
|
24
|
+
check_exact,
|
|
25
|
+
rel_tol,
|
|
26
|
+
abs_tol,
|
|
27
|
+
categorical_as_str,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
assert_series_equal(left_series, right_series, options).map_err(|e| RbPolarsErr::from(e).into())
|
|
31
|
+
}
|