polars-df 0.25.1 → 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 +27 -1
- data/Cargo.lock +268 -95
- data/LICENSE.txt +1 -1
- data/README.md +1 -3
- data/ext/polars/Cargo.toml +18 -18
- data/ext/polars/src/catalog/unity.rs +15 -20
- data/ext/polars/src/conversion/any_value.rs +25 -24
- data/ext/polars/src/conversion/chunked_array.rs +58 -56
- data/ext/polars/src/conversion/datetime.rs +58 -7
- data/ext/polars/src/conversion/mod.rs +155 -141
- data/ext/polars/src/dataframe/export.rs +15 -12
- data/ext/polars/src/dataframe/general.rs +5 -4
- data/ext/polars/src/dataframe/map.rs +6 -4
- data/ext/polars/src/error.rs +1 -1
- data/ext/polars/src/expr/array.rs +0 -24
- data/ext/polars/src/expr/datatype.rs +3 -2
- data/ext/polars/src/expr/datetime.rs +4 -4
- data/ext/polars/src/expr/general.rs +27 -15
- data/ext/polars/src/expr/list.rs +0 -26
- data/ext/polars/src/functions/business.rs +2 -2
- data/ext/polars/src/functions/io.rs +4 -3
- data/ext/polars/src/functions/lazy.rs +58 -46
- data/ext/polars/src/functions/meta.rs +6 -5
- data/ext/polars/src/functions/mod.rs +0 -1
- data/ext/polars/src/functions/utils.rs +4 -2
- data/ext/polars/src/interop/arrow/mod.rs +4 -2
- data/ext/polars/src/interop/numo/to_numo_series.rs +26 -25
- data/ext/polars/src/io/scan_options.rs +6 -3
- data/ext/polars/src/io/sink_options.rs +2 -0
- data/ext/polars/src/lazyframe/general.rs +28 -13
- data/ext/polars/src/lazyframe/optflags.rs +2 -1
- data/ext/polars/src/lib.rs +14 -33
- data/ext/polars/src/map/lazy.rs +5 -2
- data/ext/polars/src/map/series.rs +19 -18
- data/ext/polars/src/on_startup.rs +16 -7
- data/ext/polars/src/ruby/numo.rs +3 -4
- data/ext/polars/src/ruby/rb_modules.rs +2 -4
- data/ext/polars/src/ruby/ruby_udf.rs +7 -9
- data/ext/polars/src/ruby/utils.rs +12 -1
- data/ext/polars/src/series/aggregation.rs +13 -1
- data/ext/polars/src/series/export.rs +33 -38
- data/ext/polars/src/series/general.rs +4 -3
- data/ext/polars/src/series/map.rs +3 -2
- data/ext/polars/src/series/scatter.rs +4 -4
- data/ext/polars/src/utils.rs +31 -7
- data/lib/polars/array_expr.rb +23 -7
- data/lib/polars/array_name_space.rb +16 -2
- data/lib/polars/binary_name_space.rb +32 -0
- data/lib/polars/data_frame.rb +73 -10
- data/lib/polars/date_time_expr.rb +91 -3
- data/lib/polars/date_time_name_space.rb +7 -1
- data/lib/polars/expr.rb +122 -44
- data/lib/polars/functions/business.rb +2 -2
- data/lib/polars/functions/eager.rb +80 -7
- data/lib/polars/functions/lazy.rb +5 -2
- data/lib/polars/io/csv.rb +27 -5
- data/lib/polars/io/ipc.rb +1 -1
- data/lib/polars/io/lines.rb +4 -4
- data/lib/polars/io/sink_options.rb +4 -2
- data/lib/polars/lazy_frame.rb +97 -14
- data/lib/polars/list_expr.rb +21 -7
- data/lib/polars/list_name_space.rb +16 -2
- data/lib/polars/query_opt_flags.rb +22 -5
- data/lib/polars/selectors.rb +1 -1
- data/lib/polars/series.rb +88 -19
- data/lib/polars/sql_context.rb +2 -2
- data/lib/polars/string_cache.rb +19 -72
- data/lib/polars/string_expr.rb +1 -7
- data/lib/polars/string_name_space.rb +1 -7
- data/lib/polars/utils/construction/series.rb +8 -3
- data/lib/polars/utils/convert.rb +16 -6
- data/lib/polars/utils/parse.rb +7 -0
- data/lib/polars/utils/reduce_balanced.rb +43 -0
- data/lib/polars/utils/various.rb +5 -0
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +1 -1
- metadata +3 -17
- data/ext/polars/src/functions/string_cache.rs +0 -24
|
@@ -16,6 +16,7 @@ use magnus::{
|
|
|
16
16
|
use polars::chunked_array::object::PolarsObjectSafe;
|
|
17
17
|
use polars::chunked_array::ops::{FillNullLimit, FillNullStrategy};
|
|
18
18
|
use polars::datatypes::AnyValue;
|
|
19
|
+
use polars::frame::PivotColumnNaming;
|
|
19
20
|
use polars::frame::row::Row;
|
|
20
21
|
use polars::io::avro::AvroCompression;
|
|
21
22
|
use polars::prelude::default_values::{
|
|
@@ -36,6 +37,8 @@ use polars_utils::total_ord::{TotalEq, TotalHash};
|
|
|
36
37
|
use crate::file::{RubyScanSourceInput, get_ruby_scan_source_input};
|
|
37
38
|
use crate::object::OBJECT_NAME;
|
|
38
39
|
use crate::rb_modules::pl_series;
|
|
40
|
+
use crate::ruby::gvl::GvlExt;
|
|
41
|
+
use crate::ruby::utils::TryIntoValue;
|
|
39
42
|
use crate::utils::to_rb_err;
|
|
40
43
|
use crate::{
|
|
41
44
|
RbDataFrame, RbExpr, RbLazyFrame, RbPolarsErr, RbResult, RbSeries, RbTypeError, RbValueError,
|
|
@@ -80,11 +83,9 @@ pub(crate) fn get_series(obj: Value) -> RbResult<Series> {
|
|
|
80
83
|
Ok(rbs.series.read().clone())
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
pub(crate) fn to_series(rb: &Ruby, s: RbSeries) -> Value {
|
|
86
|
+
pub(crate) fn to_series(rb: &Ruby, s: RbSeries) -> RbResult<Value> {
|
|
84
87
|
let series = pl_series(rb);
|
|
85
|
-
series
|
|
86
|
-
.funcall::<_, _, Value>("_from_rbseries", (s,))
|
|
87
|
-
.unwrap()
|
|
88
|
+
series.funcall::<_, _, Value>("_from_rbseries", (s,))
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
impl TryConvert for Wrap<PlSmallStr> {
|
|
@@ -116,140 +117,135 @@ impl TryConvert for Wrap<NullValues> {
|
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
fn struct_dict<'a>(
|
|
120
|
+
fn struct_dict<'a>(
|
|
121
|
+
ruby: &Ruby,
|
|
122
|
+
vals: impl Iterator<Item = AnyValue<'a>>,
|
|
123
|
+
flds: &[Field],
|
|
124
|
+
) -> RbResult<Value> {
|
|
120
125
|
let dict = ruby.hash_new();
|
|
121
126
|
for (fld, val) in flds.iter().zip(vals) {
|
|
122
|
-
dict.aset(fld.name().as_str(), Wrap(val)
|
|
127
|
+
dict.aset(fld.name().as_str(), Wrap(val).try_into_value_with(ruby)?)?;
|
|
123
128
|
}
|
|
124
|
-
dict.as_value()
|
|
129
|
+
Ok(dict.as_value())
|
|
125
130
|
}
|
|
126
131
|
|
|
127
|
-
impl
|
|
128
|
-
fn
|
|
132
|
+
impl TryIntoValue for Wrap<Series> {
|
|
133
|
+
fn try_into_value_with(self, ruby: &Ruby) -> RbResult<Value> {
|
|
129
134
|
to_series(ruby, RbSeries::new(self.0))
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
|
|
133
|
-
impl
|
|
134
|
-
fn
|
|
138
|
+
impl TryIntoValue for Wrap<DataType> {
|
|
139
|
+
fn try_into_value_with(self, ruby: &Ruby) -> RbResult<Value> {
|
|
135
140
|
let pl = crate::rb_modules::polars(ruby);
|
|
136
141
|
|
|
137
142
|
match self.0 {
|
|
138
143
|
DataType::Int8 => {
|
|
139
|
-
let class = pl.const_get::<_, Value>("Int8")
|
|
140
|
-
class.funcall("new", ())
|
|
144
|
+
let class = pl.const_get::<_, Value>("Int8")?;
|
|
145
|
+
class.funcall("new", ())
|
|
141
146
|
}
|
|
142
147
|
DataType::Int16 => {
|
|
143
|
-
let class = pl.const_get::<_, Value>("Int16")
|
|
144
|
-
class.funcall("new", ())
|
|
148
|
+
let class = pl.const_get::<_, Value>("Int16")?;
|
|
149
|
+
class.funcall("new", ())
|
|
145
150
|
}
|
|
146
151
|
DataType::Int32 => {
|
|
147
|
-
let class = pl.const_get::<_, Value>("Int32")
|
|
148
|
-
class.funcall("new", ())
|
|
152
|
+
let class = pl.const_get::<_, Value>("Int32")?;
|
|
153
|
+
class.funcall("new", ())
|
|
149
154
|
}
|
|
150
155
|
DataType::Int64 => {
|
|
151
|
-
let class = pl.const_get::<_, Value>("Int64")
|
|
152
|
-
class.funcall("new", ())
|
|
156
|
+
let class = pl.const_get::<_, Value>("Int64")?;
|
|
157
|
+
class.funcall("new", ())
|
|
153
158
|
}
|
|
154
159
|
DataType::Int128 => {
|
|
155
|
-
let class = pl.const_get::<_, Value>("Int128")
|
|
156
|
-
class.funcall("new", ())
|
|
160
|
+
let class = pl.const_get::<_, Value>("Int128")?;
|
|
161
|
+
class.funcall("new", ())
|
|
157
162
|
}
|
|
158
163
|
DataType::UInt8 => {
|
|
159
|
-
let class = pl.const_get::<_, Value>("UInt8")
|
|
160
|
-
class.funcall("new", ())
|
|
164
|
+
let class = pl.const_get::<_, Value>("UInt8")?;
|
|
165
|
+
class.funcall("new", ())
|
|
161
166
|
}
|
|
162
167
|
DataType::UInt16 => {
|
|
163
|
-
let class = pl.const_get::<_, Value>("UInt16")
|
|
164
|
-
class.funcall("new", ())
|
|
168
|
+
let class = pl.const_get::<_, Value>("UInt16")?;
|
|
169
|
+
class.funcall("new", ())
|
|
165
170
|
}
|
|
166
171
|
DataType::UInt32 => {
|
|
167
|
-
let class = pl.const_get::<_, Value>("UInt32")
|
|
168
|
-
class.funcall("new", ())
|
|
172
|
+
let class = pl.const_get::<_, Value>("UInt32")?;
|
|
173
|
+
class.funcall("new", ())
|
|
169
174
|
}
|
|
170
175
|
DataType::UInt64 => {
|
|
171
|
-
let class = pl.const_get::<_, Value>("UInt64")
|
|
172
|
-
class.funcall("new", ())
|
|
176
|
+
let class = pl.const_get::<_, Value>("UInt64")?;
|
|
177
|
+
class.funcall("new", ())
|
|
173
178
|
}
|
|
174
179
|
DataType::UInt128 => {
|
|
175
|
-
let class = pl.const_get::<_, Value>("UInt128")
|
|
176
|
-
class.funcall("new", ())
|
|
180
|
+
let class = pl.const_get::<_, Value>("UInt128")?;
|
|
181
|
+
class.funcall("new", ())
|
|
177
182
|
}
|
|
178
183
|
DataType::Float16 => {
|
|
179
|
-
let class = pl.const_get::<_, Value>("Float16")
|
|
180
|
-
class.funcall("new", ())
|
|
184
|
+
let class = pl.const_get::<_, Value>("Float16")?;
|
|
185
|
+
class.funcall("new", ())
|
|
181
186
|
}
|
|
182
187
|
DataType::Float32 => {
|
|
183
|
-
let class = pl.const_get::<_, Value>("Float32")
|
|
184
|
-
class.funcall("new", ())
|
|
188
|
+
let class = pl.const_get::<_, Value>("Float32")?;
|
|
189
|
+
class.funcall("new", ())
|
|
185
190
|
}
|
|
186
191
|
DataType::Float64 | DataType::Unknown(UnknownKind::Float) => {
|
|
187
|
-
let class = pl.const_get::<_, Value>("Float64")
|
|
188
|
-
class.funcall("new", ())
|
|
192
|
+
let class = pl.const_get::<_, Value>("Float64")?;
|
|
193
|
+
class.funcall("new", ())
|
|
189
194
|
}
|
|
190
195
|
DataType::Decimal(precision, scale) => {
|
|
191
|
-
let class = pl.const_get::<_, Value>("Decimal")
|
|
192
|
-
class
|
|
193
|
-
.funcall::<_, _, Value>("new", (precision, scale))
|
|
194
|
-
.unwrap()
|
|
196
|
+
let class = pl.const_get::<_, Value>("Decimal")?;
|
|
197
|
+
class.funcall::<_, _, Value>("new", (precision, scale))
|
|
195
198
|
}
|
|
196
199
|
DataType::Boolean => {
|
|
197
|
-
let class = pl.const_get::<_, Value>("Boolean")
|
|
198
|
-
class.funcall("new", ())
|
|
200
|
+
let class = pl.const_get::<_, Value>("Boolean")?;
|
|
201
|
+
class.funcall("new", ())
|
|
199
202
|
}
|
|
200
203
|
DataType::String | DataType::Unknown(UnknownKind::Str) => {
|
|
201
|
-
let class = pl.const_get::<_, Value>("String")
|
|
202
|
-
class.funcall("new", ())
|
|
204
|
+
let class = pl.const_get::<_, Value>("String")?;
|
|
205
|
+
class.funcall("new", ())
|
|
203
206
|
}
|
|
204
207
|
DataType::Binary => {
|
|
205
|
-
let class = pl.const_get::<_, Value>("Binary")
|
|
206
|
-
class.funcall("new", ())
|
|
208
|
+
let class = pl.const_get::<_, Value>("Binary")?;
|
|
209
|
+
class.funcall("new", ())
|
|
207
210
|
}
|
|
208
211
|
DataType::Array(inner, size) => {
|
|
209
|
-
let class = pl.const_get::<_, Value>("Array")
|
|
210
|
-
let inner = Wrap(*inner)
|
|
212
|
+
let class = pl.const_get::<_, Value>("Array")?;
|
|
213
|
+
let inner = Wrap(*inner).try_into_value_with(ruby)?;
|
|
211
214
|
let args = (inner, size);
|
|
212
|
-
class.funcall::<_, _, Value>("new", args)
|
|
215
|
+
class.funcall::<_, _, Value>("new", args)
|
|
213
216
|
}
|
|
214
217
|
DataType::List(inner) => {
|
|
215
|
-
let class = pl.const_get::<_, Value>("List")
|
|
216
|
-
let inner = Wrap(*inner)
|
|
217
|
-
class.funcall::<_, _, Value>("new", (inner,))
|
|
218
|
+
let class = pl.const_get::<_, Value>("List")?;
|
|
219
|
+
let inner = Wrap(*inner).try_into_value_with(ruby)?;
|
|
220
|
+
class.funcall::<_, _, Value>("new", (inner,))
|
|
218
221
|
}
|
|
219
222
|
DataType::Date => {
|
|
220
|
-
let class = pl.const_get::<_, Value>("Date")
|
|
221
|
-
class.funcall("new", ())
|
|
223
|
+
let class = pl.const_get::<_, Value>("Date")?;
|
|
224
|
+
class.funcall("new", ())
|
|
222
225
|
}
|
|
223
226
|
DataType::Datetime(tu, tz) => {
|
|
224
|
-
let datetime_class = pl.const_get::<_, Value>("Datetime")
|
|
225
|
-
datetime_class
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
.unwrap()
|
|
227
|
+
let datetime_class = pl.const_get::<_, Value>("Datetime")?;
|
|
228
|
+
datetime_class.funcall::<_, _, Value>(
|
|
229
|
+
"new",
|
|
230
|
+
(tu.to_ascii(), tz.as_deref().map(|x| x.as_str())),
|
|
231
|
+
)
|
|
231
232
|
}
|
|
232
233
|
DataType::Duration(tu) => {
|
|
233
|
-
let duration_class = pl.const_get::<_, Value>("Duration")
|
|
234
|
-
duration_class
|
|
235
|
-
.funcall::<_, _, Value>("new", (tu.to_ascii(),))
|
|
236
|
-
.unwrap()
|
|
234
|
+
let duration_class = pl.const_get::<_, Value>("Duration")?;
|
|
235
|
+
duration_class.funcall::<_, _, Value>("new", (tu.to_ascii(),))
|
|
237
236
|
}
|
|
238
237
|
DataType::Object(_) => {
|
|
239
|
-
let class = pl.const_get::<_, Value>("Object")
|
|
240
|
-
class.funcall("new", ())
|
|
238
|
+
let class = pl.const_get::<_, Value>("Object")?;
|
|
239
|
+
class.funcall("new", ())
|
|
241
240
|
}
|
|
242
241
|
DataType::Categorical(cats, _) => {
|
|
243
|
-
let categories_class = pl.const_get::<_, Value>("Categories")
|
|
244
|
-
let categorical_class = pl.const_get::<_, Value>("Categorical")
|
|
242
|
+
let categories_class = pl.const_get::<_, Value>("Categories")?;
|
|
243
|
+
let categorical_class = pl.const_get::<_, Value>("Categorical")?;
|
|
245
244
|
let categories: Value = categories_class
|
|
246
|
-
.funcall("_from_rb_categories", (RbCategories::from(cats.clone()),))
|
|
247
|
-
.unwrap();
|
|
245
|
+
.funcall("_from_rb_categories", (RbCategories::from(cats.clone()),))?;
|
|
248
246
|
let kwargs = ruby.hash_new();
|
|
249
|
-
kwargs
|
|
250
|
-
|
|
251
|
-
.unwrap();
|
|
252
|
-
categorical_class.funcall("new", (kwargs,)).unwrap()
|
|
247
|
+
kwargs.aset(ruby.to_symbol("categories"), categories)?;
|
|
248
|
+
categorical_class.funcall("new", (kwargs,))
|
|
253
249
|
}
|
|
254
250
|
DataType::Enum(_, mapping) => {
|
|
255
251
|
let categories = unsafe {
|
|
@@ -258,42 +254,38 @@ impl IntoValue for Wrap<DataType> {
|
|
|
258
254
|
vec![mapping.to_arrow(true)],
|
|
259
255
|
)
|
|
260
256
|
};
|
|
261
|
-
let class = pl.const_get::<_, Value>("Enum")
|
|
262
|
-
let series = to_series(ruby, categories.into_series().into())
|
|
263
|
-
class.funcall::<_, _, Value>("new", (series,))
|
|
257
|
+
let class = pl.const_get::<_, Value>("Enum")?;
|
|
258
|
+
let series = to_series(ruby, categories.into_series().into())?;
|
|
259
|
+
class.funcall::<_, _, Value>("new", (series,))
|
|
264
260
|
}
|
|
265
261
|
DataType::Time => {
|
|
266
|
-
let class = pl.const_get::<_, Value>("Time")
|
|
267
|
-
class.funcall("new", ())
|
|
262
|
+
let class = pl.const_get::<_, Value>("Time")?;
|
|
263
|
+
class.funcall("new", ())
|
|
268
264
|
}
|
|
269
265
|
DataType::Struct(fields) => {
|
|
270
|
-
let field_class = pl.const_get::<_, Value>("Field")
|
|
266
|
+
let field_class = pl.const_get::<_, Value>("Field")?;
|
|
271
267
|
let iter = fields.iter().map(|fld| {
|
|
272
268
|
let name = fld.name().as_str();
|
|
273
|
-
let dtype = Wrap(fld.dtype().clone());
|
|
274
|
-
field_class
|
|
275
|
-
.funcall::<_, _, Value>("new", (name, dtype))
|
|
276
|
-
.unwrap()
|
|
269
|
+
let dtype = Wrap(fld.dtype().clone()).try_into_value_with(ruby);
|
|
270
|
+
dtype.and_then(|dt| field_class.funcall::<_, _, Value>("new", (name, dt)))
|
|
277
271
|
});
|
|
278
|
-
let fields = ruby.
|
|
279
|
-
let struct_class = pl.const_get::<_, Value>("Struct")
|
|
280
|
-
struct_class
|
|
281
|
-
.funcall::<_, _, Value>("new", (fields,))
|
|
282
|
-
.unwrap()
|
|
272
|
+
let fields = ruby.ary_try_from_iter(iter)?;
|
|
273
|
+
let struct_class = pl.const_get::<_, Value>("Struct")?;
|
|
274
|
+
struct_class.funcall::<_, _, Value>("new", (fields,))
|
|
283
275
|
}
|
|
284
276
|
DataType::Null => {
|
|
285
|
-
let class = pl.const_get::<_, Value>("Null")
|
|
286
|
-
class.funcall("new", ())
|
|
277
|
+
let class = pl.const_get::<_, Value>("Null")?;
|
|
278
|
+
class.funcall("new", ())
|
|
287
279
|
}
|
|
288
280
|
DataType::Extension(_typ, _storage) => {
|
|
289
281
|
todo!();
|
|
290
282
|
}
|
|
291
283
|
DataType::Unknown(UnknownKind::Int(v)) => {
|
|
292
|
-
Wrap(materialize_dyn_int(v).dtype()).
|
|
284
|
+
Wrap(materialize_dyn_int(v).dtype()).try_into_value_with(ruby)
|
|
293
285
|
}
|
|
294
286
|
DataType::Unknown(_) => {
|
|
295
|
-
let class = pl.const_get::<_, Value>("Unknown")
|
|
296
|
-
class.funcall("new", ())
|
|
287
|
+
let class = pl.const_get::<_, Value>("Unknown")?;
|
|
288
|
+
class.funcall("new", ())
|
|
297
289
|
}
|
|
298
290
|
DataType::BinaryOffset => {
|
|
299
291
|
unimplemented!()
|
|
@@ -399,13 +391,12 @@ impl TryConvert for Wrap<DataType> {
|
|
|
399
391
|
"Polars::String" => DataType::String,
|
|
400
392
|
"Polars::Binary" => DataType::Binary,
|
|
401
393
|
"Polars::Categorical" => {
|
|
402
|
-
let categories: Value = ob.funcall("categories", ())
|
|
403
|
-
let rb_categories: &RbCategories =
|
|
404
|
-
categories.funcall("_categories", ()).unwrap();
|
|
394
|
+
let categories: Value = ob.funcall("categories", ())?;
|
|
395
|
+
let rb_categories: &RbCategories = categories.funcall("_categories", ())?;
|
|
405
396
|
DataType::from_categories(rb_categories.categories().clone())
|
|
406
397
|
}
|
|
407
398
|
"Polars::Enum" => {
|
|
408
|
-
let categories: Value = ob.funcall("categories", ())
|
|
399
|
+
let categories: Value = ob.funcall("categories", ())?;
|
|
409
400
|
let s = get_series(categories)?;
|
|
410
401
|
let ca = s.str().map_err(RbPolarsErr::from)?;
|
|
411
402
|
let categories = ca.downcast_iter().next().unwrap().clone();
|
|
@@ -417,7 +408,7 @@ impl TryConvert for Wrap<DataType> {
|
|
|
417
408
|
"Polars::Date" => DataType::Date,
|
|
418
409
|
"Polars::Time" => DataType::Time,
|
|
419
410
|
"Polars::Datetime" => {
|
|
420
|
-
let time_unit: Value = ob.funcall("time_unit", ())
|
|
411
|
+
let time_unit: Value = ob.funcall("time_unit", ())?;
|
|
421
412
|
let time_unit = Wrap::<TimeUnit>::try_convert(time_unit)?.0;
|
|
422
413
|
let time_zone: Option<String> = ob.funcall("time_zone", ())?;
|
|
423
414
|
DataType::Datetime(
|
|
@@ -426,7 +417,7 @@ impl TryConvert for Wrap<DataType> {
|
|
|
426
417
|
)
|
|
427
418
|
}
|
|
428
419
|
"Polars::Duration" => {
|
|
429
|
-
let time_unit: Value = ob.funcall("time_unit", ())
|
|
420
|
+
let time_unit: Value = ob.funcall("time_unit", ())?;
|
|
430
421
|
let time_unit = Wrap::<TimeUnit>::try_convert(time_unit)?.0;
|
|
431
422
|
DataType::Duration(time_unit)
|
|
432
423
|
}
|
|
@@ -437,13 +428,13 @@ impl TryConvert for Wrap<DataType> {
|
|
|
437
428
|
DataType::Decimal(precision, scale)
|
|
438
429
|
}
|
|
439
430
|
"Polars::List" => {
|
|
440
|
-
let inner: Value = ob.funcall("inner", ())
|
|
431
|
+
let inner: Value = ob.funcall("inner", ())?;
|
|
441
432
|
let inner = Wrap::<DataType>::try_convert(inner)?;
|
|
442
433
|
DataType::List(Box::new(inner.0))
|
|
443
434
|
}
|
|
444
435
|
"Polars::Array" => {
|
|
445
|
-
let inner: Value = ob.funcall("inner", ())
|
|
446
|
-
let size: Value = ob.funcall("size", ())
|
|
436
|
+
let inner: Value = ob.funcall("inner", ())?;
|
|
437
|
+
let size: Value = ob.funcall("size", ())?;
|
|
447
438
|
let inner = Wrap::<DataType>::try_convert(inner)?;
|
|
448
439
|
let size = usize::try_convert(size)?;
|
|
449
440
|
DataType::Array(Box::new(inner.0), size)
|
|
@@ -638,13 +629,13 @@ impl TryConvert for Wrap<ScanSources> {
|
|
|
638
629
|
}
|
|
639
630
|
}
|
|
640
631
|
|
|
641
|
-
impl
|
|
642
|
-
fn
|
|
632
|
+
impl TryIntoValue for Wrap<Schema> {
|
|
633
|
+
fn try_into_value_with(self, ruby: &Ruby) -> RbResult<Value> {
|
|
643
634
|
let dict = ruby.hash_new();
|
|
644
635
|
for (k, v) in self.0.iter() {
|
|
645
|
-
dict.aset(k.as_str(), Wrap(v.clone())
|
|
636
|
+
dict.aset(k.as_str(), Wrap(v.clone()).try_into_value_with(ruby)?)?;
|
|
646
637
|
}
|
|
647
|
-
dict.as_value()
|
|
638
|
+
Ok(dict.as_value())
|
|
648
639
|
}
|
|
649
640
|
}
|
|
650
641
|
|
|
@@ -655,18 +646,17 @@ pub struct ObjectValue {
|
|
|
655
646
|
|
|
656
647
|
impl Debug for ObjectValue {
|
|
657
648
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
658
|
-
f
|
|
659
|
-
.field("inner", &self.to_value())
|
|
660
|
-
.finish()
|
|
649
|
+
write!(f, "{}", self)
|
|
661
650
|
}
|
|
662
651
|
}
|
|
663
652
|
|
|
664
653
|
impl Hash for ObjectValue {
|
|
665
654
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
666
|
-
let h =
|
|
667
|
-
.
|
|
668
|
-
|
|
669
|
-
|
|
655
|
+
let h = Ruby::attach(|rb| {
|
|
656
|
+
rb.get_inner(self.inner)
|
|
657
|
+
.funcall::<_, _, isize>("hash", ())
|
|
658
|
+
.expect("should be hashable")
|
|
659
|
+
});
|
|
670
660
|
state.write_isize(h)
|
|
671
661
|
}
|
|
672
662
|
}
|
|
@@ -675,7 +665,11 @@ impl Eq for ObjectValue {}
|
|
|
675
665
|
|
|
676
666
|
impl PartialEq for ObjectValue {
|
|
677
667
|
fn eq(&self, other: &Self) -> bool {
|
|
678
|
-
|
|
668
|
+
Ruby::attach(|ruby| {
|
|
669
|
+
ruby.get_inner(self.inner)
|
|
670
|
+
.eql(ruby.get_inner(other.inner))
|
|
671
|
+
.unwrap_or(false)
|
|
672
|
+
})
|
|
679
673
|
}
|
|
680
674
|
}
|
|
681
675
|
|
|
@@ -696,7 +690,10 @@ impl TotalHash for ObjectValue {
|
|
|
696
690
|
|
|
697
691
|
impl Display for ObjectValue {
|
|
698
692
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
699
|
-
|
|
693
|
+
Ruby::attach(|rb| {
|
|
694
|
+
let v = rb.get_inner(self.inner);
|
|
695
|
+
write!(f, "{}", v)
|
|
696
|
+
})
|
|
700
697
|
}
|
|
701
698
|
}
|
|
702
699
|
|
|
@@ -724,12 +721,6 @@ impl From<&dyn PolarsObjectSafe> for &ObjectValue {
|
|
|
724
721
|
}
|
|
725
722
|
}
|
|
726
723
|
|
|
727
|
-
impl ObjectValue {
|
|
728
|
-
pub fn to_value(&self) -> Value {
|
|
729
|
-
self.clone().into_value_with(&Ruby::get().unwrap())
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
724
|
impl IntoValue for ObjectValue {
|
|
734
725
|
fn into_value_with(self, ruby: &Ruby) -> Value {
|
|
735
726
|
ruby.get_inner(self.inner)
|
|
@@ -738,9 +729,9 @@ impl IntoValue for ObjectValue {
|
|
|
738
729
|
|
|
739
730
|
impl Default for ObjectValue {
|
|
740
731
|
fn default() -> Self {
|
|
741
|
-
ObjectValue {
|
|
742
|
-
inner:
|
|
743
|
-
}
|
|
732
|
+
Ruby::attach(|rb| ObjectValue {
|
|
733
|
+
inner: rb.qnil().as_value().into(),
|
|
734
|
+
})
|
|
744
735
|
}
|
|
745
736
|
}
|
|
746
737
|
|
|
@@ -1125,6 +1116,21 @@ impl TryConvert for Wrap<SearchSortedSide> {
|
|
|
1125
1116
|
}
|
|
1126
1117
|
}
|
|
1127
1118
|
|
|
1119
|
+
impl TryConvert for Wrap<PivotColumnNaming> {
|
|
1120
|
+
fn try_convert(ob: Value) -> RbResult<Self> {
|
|
1121
|
+
let parsed = match String::try_convert(ob)?.as_str() {
|
|
1122
|
+
"auto" => PivotColumnNaming::Auto,
|
|
1123
|
+
"combine" => PivotColumnNaming::Combine,
|
|
1124
|
+
v => {
|
|
1125
|
+
return Err(RbValueError::new_err(format!(
|
|
1126
|
+
"`column_naming` must be one of {{'auto', 'combine'}}, got {v}",
|
|
1127
|
+
)));
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
Ok(Wrap(parsed))
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1128
1134
|
impl TryConvert for Wrap<ClosedInterval> {
|
|
1129
1135
|
fn try_convert(ob: Value) -> RbResult<Self> {
|
|
1130
1136
|
let parsed = match String::try_convert(ob)?.as_str() {
|
|
@@ -1234,15 +1240,25 @@ impl TryConvert for Wrap<CastColumnsPolicy> {
|
|
|
1234
1240
|
return Ok(out);
|
|
1235
1241
|
}
|
|
1236
1242
|
|
|
1237
|
-
let integer_upcast =
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1243
|
+
let mut integer_upcast = false;
|
|
1244
|
+
let mut integer_to_float_cast = false;
|
|
1245
|
+
|
|
1246
|
+
let integer_cast_object: Value = ob.funcall("integer_cast", ())?;
|
|
1247
|
+
|
|
1248
|
+
parse_multiple_options("integer_cast", integer_cast_object, |v| {
|
|
1249
|
+
match v {
|
|
1250
|
+
"upcast" => integer_upcast = true,
|
|
1251
|
+
"allow-float" => integer_to_float_cast = true,
|
|
1252
|
+
"forbid" => {}
|
|
1253
|
+
v => {
|
|
1254
|
+
return Err(RbValueError::new_err(format!(
|
|
1255
|
+
"unknown option for integer_cast: {v}"
|
|
1256
|
+
)));
|
|
1257
|
+
}
|
|
1244
1258
|
}
|
|
1245
|
-
|
|
1259
|
+
|
|
1260
|
+
Ok(())
|
|
1261
|
+
})?;
|
|
1246
1262
|
|
|
1247
1263
|
let mut float_upcast = false;
|
|
1248
1264
|
let mut float_downcast = false;
|
|
@@ -1318,6 +1334,7 @@ impl TryConvert for Wrap<CastColumnsPolicy> {
|
|
|
1318
1334
|
|
|
1319
1335
|
return Ok(Wrap(CastColumnsPolicy {
|
|
1320
1336
|
integer_upcast,
|
|
1337
|
+
integer_to_float_cast,
|
|
1321
1338
|
float_upcast,
|
|
1322
1339
|
float_downcast,
|
|
1323
1340
|
datetime_nanoseconds_downcast,
|
|
@@ -1364,12 +1381,9 @@ pub fn parse_fill_null_strategy(
|
|
|
1364
1381
|
"zero" => FillNullStrategy::Zero,
|
|
1365
1382
|
"one" => FillNullStrategy::One,
|
|
1366
1383
|
e => {
|
|
1367
|
-
return Err(
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
"strategy must be one of {{'forward', 'backward', 'min', 'max', 'mean', 'zero', 'one'}}, got {e}",
|
|
1371
|
-
),
|
|
1372
|
-
));
|
|
1384
|
+
return Err(RbValueError::new_err(format!(
|
|
1385
|
+
"`strategy` must be one of {{'forward', 'backward', 'min', 'max', 'mean', 'zero', 'one'}}, got {e}",
|
|
1386
|
+
)));
|
|
1373
1387
|
}
|
|
1374
1388
|
};
|
|
1375
1389
|
Ok(parsed)
|
|
@@ -1,39 +1,42 @@
|
|
|
1
|
-
use magnus::{
|
|
1
|
+
use magnus::{Ruby, Value, prelude::*};
|
|
2
2
|
|
|
3
3
|
use super::*;
|
|
4
4
|
use crate::RbResult;
|
|
5
5
|
use crate::conversion::{ObjectValue, Wrap};
|
|
6
6
|
use crate::interop::arrow::to_rb::dataframe_to_stream;
|
|
7
|
+
use crate::ruby::utils::TryIntoValue;
|
|
7
8
|
|
|
8
9
|
impl RbDataFrame {
|
|
9
|
-
pub fn row_tuple(ruby: &Ruby, self_: &Self, idx: i64) -> Value {
|
|
10
|
+
pub fn row_tuple(ruby: &Ruby, self_: &Self, idx: i64) -> RbResult<Value> {
|
|
10
11
|
let idx = if idx < 0 {
|
|
11
12
|
(self_.df.read().height() as i64 + idx) as usize
|
|
12
13
|
} else {
|
|
13
14
|
idx as usize
|
|
14
15
|
};
|
|
15
|
-
ruby.
|
|
16
|
+
ruby.ary_try_from_iter(self_.df.read().columns().iter().map(|s| match s.dtype() {
|
|
16
17
|
DataType::Object(_) => {
|
|
17
18
|
let obj: Option<&ObjectValue> = s.get_object(idx).map(|any| any.into());
|
|
18
|
-
|
|
19
|
+
// TODO remove unwrap and clone
|
|
20
|
+
obj.unwrap().clone().try_into_value_with(ruby)
|
|
19
21
|
}
|
|
20
|
-
_ => Wrap(s.get(idx).unwrap()).
|
|
22
|
+
_ => Wrap(s.get(idx).unwrap()).try_into_value_with(ruby),
|
|
21
23
|
}))
|
|
22
|
-
.as_value()
|
|
24
|
+
.map(|v| v.as_value())
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
pub fn row_tuples(ruby: &Ruby, self_: &Self) -> Value {
|
|
27
|
+
pub fn row_tuples(ruby: &Ruby, self_: &Self) -> RbResult<Value> {
|
|
26
28
|
let df = &self_.df;
|
|
27
|
-
ruby.
|
|
28
|
-
ruby.
|
|
29
|
+
ruby.ary_try_from_iter((0..df.read().height()).map(|idx| {
|
|
30
|
+
ruby.ary_try_from_iter(self_.df.read().columns().iter().map(|s| match s.dtype() {
|
|
29
31
|
DataType::Object(_) => {
|
|
30
32
|
let obj: Option<&ObjectValue> = s.get_object(idx).map(|any| any.into());
|
|
31
|
-
|
|
33
|
+
// TODO remove unwrap and clone
|
|
34
|
+
obj.unwrap().clone().try_into_value_with(ruby)
|
|
32
35
|
}
|
|
33
|
-
_ => Wrap(s.get(idx).unwrap()).
|
|
36
|
+
_ => Wrap(s.get(idx).unwrap()).try_into_value_with(ruby),
|
|
34
37
|
}))
|
|
35
38
|
}))
|
|
36
|
-
.as_value()
|
|
39
|
+
.map(|v| v.as_value())
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
pub fn __arrow_c_stream__(ruby: &Ruby, self_: &Self) -> RbResult<Value> {
|
|
@@ -2,7 +2,7 @@ use std::hash::BuildHasher;
|
|
|
2
2
|
|
|
3
3
|
use arrow::bitmap::MutableBitmap;
|
|
4
4
|
use either::Either;
|
|
5
|
-
use magnus::{
|
|
5
|
+
use magnus::{RArray, Ruby, Value, prelude::*, value::Opaque};
|
|
6
6
|
use polars::prelude::*;
|
|
7
7
|
|
|
8
8
|
use crate::conversion::*;
|
|
@@ -10,6 +10,7 @@ use crate::prelude::strings_to_pl_smallstr;
|
|
|
10
10
|
use crate::rb_modules::pl_utils;
|
|
11
11
|
use crate::ruby::exceptions::RbIndexError;
|
|
12
12
|
use crate::ruby::gvl::GvlExt;
|
|
13
|
+
use crate::ruby::utils::TryIntoValue;
|
|
13
14
|
use crate::series::ToRbSeries;
|
|
14
15
|
use crate::series::to_series;
|
|
15
16
|
use crate::utils::EnterPolarsExt;
|
|
@@ -144,13 +145,13 @@ impl RbDataFrame {
|
|
|
144
145
|
Ok(())
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
pub fn dtypes(ruby: &Ruby, self_: &Self) -> RArray {
|
|
148
|
+
pub fn dtypes(ruby: &Ruby, self_: &Self) -> RbResult<RArray> {
|
|
148
149
|
let df = self_.df.read();
|
|
149
150
|
let iter = df
|
|
150
151
|
.columns()
|
|
151
152
|
.iter()
|
|
152
|
-
.map(|s| Wrap(s.dtype().clone()).
|
|
153
|
-
ruby.
|
|
153
|
+
.map(|s| Wrap(s.dtype().clone()).try_into_value_with(ruby));
|
|
154
|
+
ruby.ary_try_from_iter(iter)
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
pub fn n_chunks(&self) -> usize {
|
|
@@ -5,7 +5,7 @@ use polars_core::utils::CustomIterTools;
|
|
|
5
5
|
use super::*;
|
|
6
6
|
use crate::error::RbPolarsErr;
|
|
7
7
|
use crate::prelude::*;
|
|
8
|
-
use crate::ruby::utils::to_pl_err;
|
|
8
|
+
use crate::ruby::utils::{TryIntoValue, to_pl_err};
|
|
9
9
|
use crate::series::construction::series_from_objects;
|
|
10
10
|
use crate::{RbResult, RbSeries, raise_err};
|
|
11
11
|
|
|
@@ -28,9 +28,11 @@ impl RbDataFrame {
|
|
|
28
28
|
drop(df); // Release lock before calling lambda.
|
|
29
29
|
|
|
30
30
|
let lambda_result_iter = (0..height).map(move |_| {
|
|
31
|
-
let iter = iters
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
let iter = iters
|
|
32
|
+
.iter_mut()
|
|
33
|
+
.map(|it| Wrap(it.next().unwrap()).try_into_value_with(rb));
|
|
34
|
+
rb.ary_try_from_iter(iter)
|
|
35
|
+
.and_then(|tpl| lambda.funcall::<_, _, Value>("call", (tpl,)))
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
// Simple case: return type set.
|
data/ext/polars/src/error.rs
CHANGED
|
@@ -63,7 +63,7 @@ impl From<RbPolarsErr> for Error {
|
|
|
63
63
|
PolarsError::StructFieldNotFound(name) => {
|
|
64
64
|
StructFieldNotFoundError::new_err(name.to_string())
|
|
65
65
|
}
|
|
66
|
-
PolarsError::Context { .. } => {
|
|
66
|
+
PolarsError::Context { .. } | PolarsError::ExprContext { .. } => {
|
|
67
67
|
let tmp = RbPolarsErr::Polars(err.context_trace());
|
|
68
68
|
RbErr::from(tmp)
|
|
69
69
|
}
|