polars-df 0.25.1 → 0.26.1

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/Cargo.lock +278 -106
  4. data/Cargo.toml +0 -3
  5. data/LICENSE.txt +1 -1
  6. data/README.md +7 -3
  7. data/ext/polars/Cargo.toml +18 -18
  8. data/ext/polars/src/catalog/unity.rs +15 -20
  9. data/ext/polars/src/conversion/any_value.rs +25 -24
  10. data/ext/polars/src/conversion/chunked_array.rs +58 -56
  11. data/ext/polars/src/conversion/datetime.rs +58 -7
  12. data/ext/polars/src/conversion/mod.rs +205 -142
  13. data/ext/polars/src/dataframe/export.rs +15 -12
  14. data/ext/polars/src/dataframe/general.rs +5 -4
  15. data/ext/polars/src/dataframe/map.rs +6 -4
  16. data/ext/polars/src/error.rs +1 -1
  17. data/ext/polars/src/expr/array.rs +0 -24
  18. data/ext/polars/src/expr/datatype.rs +3 -2
  19. data/ext/polars/src/expr/datetime.rs +4 -4
  20. data/ext/polars/src/expr/general.rs +27 -15
  21. data/ext/polars/src/expr/list.rs +0 -26
  22. data/ext/polars/src/functions/business.rs +2 -2
  23. data/ext/polars/src/functions/io.rs +4 -3
  24. data/ext/polars/src/functions/lazy.rs +58 -46
  25. data/ext/polars/src/functions/meta.rs +6 -5
  26. data/ext/polars/src/functions/mod.rs +0 -1
  27. data/ext/polars/src/functions/utils.rs +4 -2
  28. data/ext/polars/src/interop/arrow/mod.rs +4 -2
  29. data/ext/polars/src/interop/arrow/to_rb.rs +17 -12
  30. data/ext/polars/src/interop/numo/to_numo_series.rs +26 -25
  31. data/ext/polars/src/io/scan_options.rs +6 -3
  32. data/ext/polars/src/io/sink_options.rs +2 -0
  33. data/ext/polars/src/lazyframe/general.rs +32 -16
  34. data/ext/polars/src/lazyframe/optflags.rs +2 -1
  35. data/ext/polars/src/lib.rs +21 -37
  36. data/ext/polars/src/map/lazy.rs +5 -2
  37. data/ext/polars/src/map/series.rs +19 -18
  38. data/ext/polars/src/on_startup.rs +16 -7
  39. data/ext/polars/src/ruby/capsule.rs +27 -0
  40. data/ext/polars/src/ruby/mod.rs +1 -0
  41. data/ext/polars/src/ruby/numo.rs +3 -4
  42. data/ext/polars/src/ruby/rb_modules.rs +2 -4
  43. data/ext/polars/src/ruby/ruby_udf.rs +7 -9
  44. data/ext/polars/src/ruby/utils.rs +12 -1
  45. data/ext/polars/src/series/aggregation.rs +13 -1
  46. data/ext/polars/src/series/export.rs +38 -38
  47. data/ext/polars/src/series/general.rs +4 -3
  48. data/ext/polars/src/series/map.rs +3 -2
  49. data/ext/polars/src/series/scatter.rs +4 -4
  50. data/ext/polars/src/utils.rs +31 -7
  51. data/lib/polars/array_expr.rb +23 -7
  52. data/lib/polars/array_name_space.rb +16 -2
  53. data/lib/polars/binary_name_space.rb +32 -0
  54. data/lib/polars/data_frame.rb +83 -11
  55. data/lib/polars/date_time_expr.rb +91 -3
  56. data/lib/polars/date_time_name_space.rb +7 -1
  57. data/lib/polars/expr.rb +122 -44
  58. data/lib/polars/functions/aggregation/horizontal.rb +4 -4
  59. data/lib/polars/functions/business.rb +2 -2
  60. data/lib/polars/functions/eager.rb +80 -7
  61. data/lib/polars/functions/lazy.rb +5 -2
  62. data/lib/polars/iceberg_dataset.rb +81 -14
  63. data/lib/polars/io/csv.rb +27 -5
  64. data/lib/polars/io/delta.rb +4 -0
  65. data/lib/polars/io/ipc.rb +1 -1
  66. data/lib/polars/io/lines.rb +4 -4
  67. data/lib/polars/io/sink_options.rb +4 -2
  68. data/lib/polars/lazy_frame.rb +97 -14
  69. data/lib/polars/list_expr.rb +21 -7
  70. data/lib/polars/list_name_space.rb +16 -2
  71. data/lib/polars/query_opt_flags.rb +22 -5
  72. data/lib/polars/schema.rb +9 -0
  73. data/lib/polars/selectors.rb +1 -1
  74. data/lib/polars/series.rb +106 -19
  75. data/lib/polars/sql_context.rb +2 -2
  76. data/lib/polars/string_cache.rb +19 -72
  77. data/lib/polars/string_expr.rb +1 -7
  78. data/lib/polars/string_name_space.rb +1 -7
  79. data/lib/polars/utils/construction/series.rb +8 -3
  80. data/lib/polars/utils/convert.rb +16 -6
  81. data/lib/polars/utils/parse.rb +7 -0
  82. data/lib/polars/utils/reduce_balanced.rb +43 -0
  83. data/lib/polars/utils/various.rb +5 -0
  84. data/lib/polars/version.rb +1 -1
  85. data/lib/polars.rb +5 -1
  86. metadata +4 -17
  87. data/ext/polars/src/functions/string_cache.rs +0 -24
@@ -2,7 +2,7 @@ use std::hash::BuildHasher;
2
2
 
3
3
  use arrow::bitmap::MutableBitmap;
4
4
  use either::Either;
5
- use magnus::{IntoValue, RArray, Ruby, Value, prelude::*, value::Opaque};
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()).into_value_with(ruby));
153
- ruby.ary_from_iter(iter)
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.iter_mut().map(|it| Wrap(it.next().unwrap()));
32
- let tpl = rb.ary_from_iter(iter);
33
- lambda.funcall::<_, _, Value>("call", (tpl,))
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.
@@ -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
  }
@@ -38,30 +38,10 @@ impl RbExpr {
38
38
  self.inner.clone().arr().median().into()
39
39
  }
40
40
 
41
- pub fn arr_unique(&self, maintain_order: bool) -> Self {
42
- if maintain_order {
43
- self.inner.clone().arr().unique_stable().into()
44
- } else {
45
- self.inner.clone().arr().unique().into()
46
- }
47
- }
48
-
49
- pub fn arr_n_unique(&self) -> Self {
50
- self.inner.clone().arr().n_unique().into()
51
- }
52
-
53
41
  pub fn arr_to_list(&self) -> Self {
54
42
  self.inner.clone().arr().to_list().into()
55
43
  }
56
44
 
57
- pub fn arr_all(&self) -> Self {
58
- self.inner.clone().arr().all().into()
59
- }
60
-
61
- pub fn arr_any(&self) -> Self {
62
- self.inner.clone().arr().any().into()
63
- }
64
-
65
45
  pub fn arr_sort(&self, descending: bool, nulls_last: bool) -> Self {
66
46
  self.inner
67
47
  .clone()
@@ -74,10 +54,6 @@ impl RbExpr {
74
54
  .into()
75
55
  }
76
56
 
77
- pub fn arr_reverse(&self) -> Self {
78
- self.inner.clone().arr().reverse().into()
79
- }
80
-
81
57
  pub fn arr_arg_min(&self) -> Self {
82
58
  self.inner.clone().arr().arg_min().into()
83
59
  }
@@ -1,7 +1,8 @@
1
- use magnus::{IntoValue, RArray, Ruby, TryConvert, Value};
1
+ use magnus::{RArray, Ruby, TryConvert, Value};
2
2
  use polars::prelude::{DataType, DataTypeExpr, PlSmallStr, Schema};
3
3
 
4
4
  use crate::prelude::Wrap;
5
+ use crate::ruby::utils::TryIntoValue;
5
6
  use crate::{RbExpr, RbPolarsErr, RbResult};
6
7
 
7
8
  #[magnus::wrap(class = "Polars::RbDataTypeExpr")]
@@ -36,7 +37,7 @@ impl RbDataTypeExpr {
36
37
  .inner
37
38
  .into_datatype(&schema.0)
38
39
  .map_err(RbPolarsErr::from)?;
39
- Ok(Wrap(dtype).into_value_with(ruby))
40
+ Wrap(dtype).try_into_value_with(ruby)
40
41
  }
41
42
 
42
43
  pub fn struct_with_fields(rb_fields: RArray) -> RbResult<Self> {
@@ -8,13 +8,13 @@ impl RbExpr {
8
8
  &self,
9
9
  n: &RbExpr,
10
10
  week_mask: [bool; 7],
11
- holidays: Vec<i32>,
11
+ holidays: &RbExpr,
12
12
  roll: Wrap<Roll>,
13
13
  ) -> Self {
14
14
  self.inner
15
15
  .clone()
16
16
  .dt()
17
- .add_business_days(n.inner.clone(), week_mask, holidays, roll.0)
17
+ .add_business_days(n.inner.clone(), week_mask, holidays.inner.clone(), roll.0)
18
18
  .into()
19
19
  }
20
20
 
@@ -133,11 +133,11 @@ impl RbExpr {
133
133
  self.clone().inner.dt().year().into()
134
134
  }
135
135
 
136
- pub fn dt_is_business_day(&self, week_mask: [bool; 7], holidays: Vec<i32>) -> Self {
136
+ pub fn dt_is_business_day(&self, week_mask: [bool; 7], holidays: &RbExpr) -> Self {
137
137
  self.inner
138
138
  .clone()
139
139
  .dt()
140
- .is_business_day(week_mask, holidays)
140
+ .is_business_day(week_mask, holidays.inner.clone())
141
141
  .into()
142
142
  }
143
143
 
@@ -5,13 +5,13 @@ use polars::lazy::dsl;
5
5
  use polars::prelude::*;
6
6
  use polars::series::ops::NullBehavior;
7
7
  use polars_core::chunked_array::cast::CastOptions;
8
- use polars_core::series::IsSorted;
8
+ use polars_plan::plans::AExprSorted;
9
9
 
10
10
  use super::datatype::RbDataTypeExpr;
11
11
  use super::selector::RbSelector;
12
12
  use crate::conversion::{Wrap, parse_fill_null_strategy};
13
13
  use crate::expr::ToExprs;
14
- use crate::{RbExpr, RbPolarsErr, RbResult};
14
+ use crate::{RbDataType, RbExpr, RbPolarsErr, RbResult};
15
15
 
16
16
  impl RbExpr {
17
17
  pub fn add(&self, rhs: &Self) -> RbResult<Self> {
@@ -182,8 +182,8 @@ impl RbExpr {
182
182
  self.inner.clone().item(allow_empty).into()
183
183
  }
184
184
 
185
- pub fn implode(&self) -> Self {
186
- self.inner.clone().implode().into()
185
+ pub fn implode(&self, maintain_order: bool) -> Self {
186
+ self.inner.clone().implode(maintain_order).into()
187
187
  }
188
188
 
189
189
  pub fn quantile(&self, quantile: &Self, interpolation: Wrap<QuantileMethod>) -> Self {
@@ -366,8 +366,11 @@ impl RbExpr {
366
366
  .into()
367
367
  }
368
368
 
369
- pub fn gather(&self, idx: &Self) -> Self {
370
- self.inner.clone().gather(idx.inner.clone()).into()
369
+ pub fn gather(&self, idx: &Self, null_on_oob: bool) -> Self {
370
+ self.inner
371
+ .clone()
372
+ .gather(idx.inner.clone(), null_on_oob)
373
+ .into()
371
374
  }
372
375
 
373
376
  pub fn get(&self, idx: &Self, null_on_oob: bool) -> Self {
@@ -530,6 +533,10 @@ impl RbExpr {
530
533
  self.clone().inner.round_sig_figs(digits).into()
531
534
  }
532
535
 
536
+ pub fn truncate(&self, decimals: u32) -> Self {
537
+ self.inner.clone().truncate(decimals).into()
538
+ }
539
+
533
540
  pub fn floor(&self) -> Self {
534
541
  self.inner.clone().floor().into()
535
542
  }
@@ -727,8 +734,11 @@ impl RbExpr {
727
734
  self.inner.clone().dot(other.inner.clone()).into()
728
735
  }
729
736
 
730
- pub fn reinterpret(&self, signed: bool) -> Self {
731
- self.inner.clone().reinterpret(signed).into()
737
+ pub fn reinterpret(&self, signed: Option<bool>, dtype: Option<RbDataType>) -> Self {
738
+ self.inner
739
+ .clone()
740
+ .reinterpret(signed, dtype.map(|dt| dt.0))
741
+ .into()
732
742
  }
733
743
 
734
744
  pub fn mode(&self, maintain_order: bool) -> Self {
@@ -904,6 +914,10 @@ impl RbExpr {
904
914
  self.inner.clone().all(drop_nulls).into()
905
915
  }
906
916
 
917
+ pub fn is_empty(&self, ignore_nulls: bool) -> Self {
918
+ self.inner.clone().is_empty(ignore_nulls).into()
919
+ }
920
+
907
921
  pub fn log(&self, base: &RbExpr) -> Self {
908
922
  self.inner.clone().log(base.inner.clone()).into()
909
923
  }
@@ -924,13 +938,11 @@ impl RbExpr {
924
938
  self.inner.clone().hash(seed, seed_1, seed_2, seed_3).into()
925
939
  }
926
940
 
927
- pub fn set_sorted_flag(&self, descending: bool) -> Self {
928
- let is_sorted = if descending {
929
- IsSorted::Descending
930
- } else {
931
- IsSorted::Ascending
932
- };
933
- self.inner.clone().set_sorted_flag(is_sorted).into()
941
+ pub fn set_sorted_flag(&self, descending: bool, nulls_last: bool) -> Self {
942
+ let sortedness = AExprSorted::default()
943
+ .with_desc(Some(descending))
944
+ .with_nulls_last(Some(nulls_last));
945
+ self.inner.clone().set_sorted_flag(sortedness).into()
934
946
  }
935
947
 
936
948
  pub fn replace(&self, old: &Self, new: &Self) -> Self {
@@ -7,14 +7,6 @@ use crate::conversion::Wrap;
7
7
  use crate::{RbExpr, RbResult};
8
8
 
9
9
  impl RbExpr {
10
- pub fn list_all(&self) -> Self {
11
- self.inner.clone().list().all().into()
12
- }
13
-
14
- pub fn list_any(&self) -> Self {
15
- self.inner.clone().list().any().into()
16
- }
17
-
18
10
  pub fn list_arg_max(&self) -> Self {
19
11
  self.inner.clone().list().arg_max().into()
20
12
  }
@@ -103,10 +95,6 @@ impl RbExpr {
103
95
  self.inner.clone().list().min().into()
104
96
  }
105
97
 
106
- pub fn list_reverse(&self) -> Self {
107
- self.inner.clone().list().reverse().into()
108
- }
109
-
110
98
  pub fn list_shift(&self, periods: &RbExpr) -> Self {
111
99
  self.inner
112
100
  .clone()
@@ -213,20 +201,6 @@ impl RbExpr {
213
201
  .into())
214
202
  }
215
203
 
216
- pub fn list_n_unique(&self) -> Self {
217
- self.inner.clone().list().n_unique().into()
218
- }
219
-
220
- pub fn list_unique(&self, maintain_order: bool) -> Self {
221
- let e = self.inner.clone();
222
-
223
- if maintain_order {
224
- e.list().unique_stable().into()
225
- } else {
226
- e.list().unique().into()
227
- }
228
- }
229
-
230
204
  pub fn list_set_operation(&self, other: &RbExpr, operation: Wrap<SetOperation>) -> Self {
231
205
  let e = self.inner.clone().list();
232
206
  match operation.0 {
@@ -6,9 +6,9 @@ pub fn business_day_count(
6
6
  start: &RbExpr,
7
7
  end: &RbExpr,
8
8
  week_mask: [bool; 7],
9
- holidays: Vec<i32>,
9
+ holidays: &RbExpr,
10
10
  ) -> RbExpr {
11
11
  let start = start.inner.clone();
12
12
  let end = end.inner.clone();
13
- dsl::business_day_count(start, end, week_mask, holidays).into()
13
+ dsl::business_day_count(start, end, week_mask, holidays.inner.clone()).into()
14
14
  }
@@ -8,6 +8,7 @@ use crate::conversion::Wrap;
8
8
  use crate::file::{EitherRustRubyFile, get_either_file};
9
9
  use crate::io::cloud_options::OptRbCloudOptions;
10
10
  use crate::ruby::gvl::GvlExt;
11
+ use crate::ruby::utils::TryIntoValue;
11
12
  use crate::{RbPolarsErr, RbResult};
12
13
 
13
14
  pub fn read_ipc_schema(rb: &Ruby, rb_f: Value) -> RbResult<RHash> {
@@ -32,7 +33,6 @@ pub fn read_parquet_metadata(
32
33
  ) -> RbResult<RHash> {
33
34
  use std::io::Cursor;
34
35
 
35
- use polars_io::pl_async::get_runtime;
36
36
  use polars_parquet::read::read_metadata;
37
37
  use polars_parquet::read::schema::read_custom_key_value_metadata;
38
38
 
@@ -53,7 +53,7 @@ pub fn read_parquet_metadata(
53
53
  use polars_error::PolarsResult;
54
54
 
55
55
  rb.detach(|| {
56
- get_runtime().block_on(async {
56
+ polars_core::runtime::ASYNC.block_on(async {
57
57
  let mut reader =
58
58
  ParquetObjectStore::from_uri(p, cloud_options.as_ref(), None).await?;
59
59
  let result = reader.get_metadata().await?;
@@ -97,9 +97,10 @@ pub fn read_parquet_schema(rb_f: Value) -> RbResult<RHash> {
97
97
  }
98
98
 
99
99
  fn fields_to_rbdict(schema: &ArrowSchema, dict: &RHash) -> RbResult<()> {
100
+ let ruby = &Ruby::get_with(*dict);
100
101
  for field in schema.iter_values() {
101
102
  let dt = Wrap(polars::prelude::DataType::from_arrow_field(field));
102
- dict.aset(field.name.as_str(), dt)?;
103
+ dict.aset(field.name.as_str(), dt.try_into_value_with(ruby)?)?;
103
104
  }
104
105
  Ok(())
105
106
  }
@@ -1,17 +1,23 @@
1
1
  use magnus::encoding::EncodingCapable;
2
- use magnus::{Float, Integer, RArray, RString, Ruby, Value, prelude::*, typed_data::Obj};
2
+ use magnus::{
3
+ Float, Integer, RArray, RString, Ruby, Value, prelude::*, typed_data::Obj, value::Qfalse,
4
+ value::Qtrue,
5
+ };
3
6
  use polars::lazy::dsl;
4
7
  use polars::prelude::*;
8
+ use polars_plan::plans::DynLiteralValue;
5
9
 
10
+ use crate::conversion::any_value::rb_object_to_any_value;
6
11
  use crate::conversion::{Wrap, get_lf, get_rbseq};
7
12
  use crate::expr::ToExprs;
8
13
  use crate::expr::datatype::RbDataTypeExpr;
9
14
  use crate::lazyframe::RbOptFlags;
15
+ use crate::ruby::exceptions::{RbTypeError, RbValueError};
10
16
  use crate::ruby::plan_callback::PlanCallbackExt;
11
17
  use crate::ruby::ruby_function::RubyObject;
12
18
  use crate::ruby::thread::start_background_ruby_thread;
13
19
  use crate::utils::EnterPolarsExt;
14
- use crate::{RbDataFrame, RbExpr, RbLazyFrame, RbPolarsErr, RbResult, RbSeries, RbValueError, map};
20
+ use crate::{RbDataFrame, RbExpr, RbLazyFrame, RbPolarsErr, RbResult, RbSeries, map};
15
21
 
16
22
  macro_rules! set_unwrapped_or_0 {
17
23
  ($($var:ident),+ $(,)?) => {
@@ -378,34 +384,28 @@ pub fn fold(
378
384
  .into())
379
385
  }
380
386
 
381
- pub fn lit(value: Value, allow_object: bool, is_scalar: bool) -> RbResult<RbExpr> {
387
+ pub fn lit(rb: &Ruby, value: Value, allow_object: bool, is_scalar: bool) -> RbResult<RbExpr> {
382
388
  let ruby = Ruby::get_with(value);
383
- if value.is_kind_of(ruby.class_true_class()) || value.is_kind_of(ruby.class_false_class()) {
384
- Ok(dsl::lit(bool::try_convert(value)?).into())
385
- } else if let Some(v) = Integer::from_value(value) {
386
- match v.to_i64() {
387
- Ok(val) => {
388
- if val > 0 && val < i32::MAX as i64 || val < 0 && val > i32::MIN as i64 {
389
- Ok(dsl::lit(val as i32).into())
390
- } else {
391
- Ok(dsl::lit(val).into())
392
- }
393
- }
394
- _ => {
395
- let val = v.to_u64()?;
396
- Ok(dsl::lit(val).into())
397
- }
398
- }
399
- } else if let Some(v) = Float::from_value(value) {
400
- Ok(dsl::lit(v.to_f64()).into())
401
- } else if let Some(v) = RString::from_value(value) {
402
- if v.enc_get() == ruby.utf8_encindex() {
403
- Ok(dsl::lit(v.to_string()?).into())
389
+ if Qtrue::from_value(value).is_some() {
390
+ Ok(dsl::lit(true).into())
391
+ } else if Qfalse::from_value(value).is_some() {
392
+ Ok(dsl::lit(false).into())
393
+ } else if let Some(int) = Integer::from_value(value) {
394
+ let v = i128::try_convert(int.as_value())
395
+ .map_err(|e| polars_err!(InvalidOperation: "integer too large for Polars: {e}"))
396
+ .map_err(RbPolarsErr::from)?;
397
+ Ok(Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(v))).into())
398
+ } else if let Some(float) = Float::from_value(value) {
399
+ let val = f64::try_convert(float.as_value())?;
400
+ Ok(Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Float(val))).into())
401
+ } else if let Some(rbstr) = RString::from_value(value) {
402
+ if rbstr.enc_get() == ruby.utf8_encindex() {
403
+ Ok(dsl::lit(rbstr.to_string()?).into())
404
404
  } else {
405
- Ok(dsl::lit(unsafe { v.as_slice() }).into())
405
+ Ok(dsl::lit(unsafe { rbstr.as_slice() }).into())
406
406
  }
407
- } else if let Ok(series) = Obj::<RbSeries>::try_convert(value) {
408
- let s = series.series.read();
407
+ } else if let Ok(series) = <&RbSeries>::try_convert(value) {
408
+ let s = series.clone().series.into_inner();
409
409
  if is_scalar {
410
410
  let av = s
411
411
  .get(0)
@@ -413,17 +413,39 @@ pub fn lit(value: Value, allow_object: bool, is_scalar: bool) -> RbResult<RbExpr
413
413
  let av = av.into_static();
414
414
  Ok(dsl::lit(Scalar::new(s.dtype().clone(), av)).into())
415
415
  } else {
416
- Ok(dsl::lit(s.clone()).into())
416
+ Ok(dsl::lit(s).into())
417
417
  }
418
418
  } else if value.is_nil() {
419
419
  Ok(dsl::lit(Null {}).into())
420
- } else if allow_object {
421
- todo!()
422
420
  } else {
423
- Err(RbValueError::new_err(format!(
424
- "could not convert value {:?} as a Literal",
425
- value.to_string()
426
- )))
421
+ let raise = || {
422
+ RbTypeError::new_err(format!(
423
+ "cannot create expression literal for value of type {}.\
424
+ \n\nHint: Pass `allow_object: true` to accept any value and create a literal of type Object.",
425
+ unsafe { value.classname() },
426
+ ))
427
+ };
428
+
429
+ let av = rb_object_to_any_value(value, true, allow_object).map_err(|_| raise())?;
430
+ match av {
431
+ AnyValue::ObjectOwned(_) => {
432
+ // Check again for object allowance as for cached addresses this is not checked.
433
+ if allow_object {
434
+ let s = RbSeries::new_object(
435
+ rb,
436
+ "".to_string(),
437
+ rb.ary_new_from_values(&[value]),
438
+ false,
439
+ )?
440
+ .series
441
+ .into_inner();
442
+ Ok(dsl::lit(s).into())
443
+ } else {
444
+ Err(raise())
445
+ }
446
+ }
447
+ _ => Ok(Expr::Literal(LiteralValue::from(av)).into()),
448
+ }
427
449
  }
428
450
  }
429
451
 
@@ -461,7 +483,7 @@ pub fn reduce(
461
483
  .into())
462
484
  }
463
485
 
464
- pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbResult<RbExpr> {
486
+ pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbExpr {
465
487
  let mut value = value.inner.clone();
466
488
  let n = n.inner.clone();
467
489
 
@@ -469,17 +491,7 @@ pub fn repeat(value: &RbExpr, n: &RbExpr, dtype: Option<Wrap<DataType>>) -> RbRe
469
491
  value = value.cast(dtype.0);
470
492
  }
471
493
 
472
- if let Expr::Literal(lv) = &value {
473
- let av = lv.to_any_value().unwrap();
474
- // Integer inputs that fit in Int32 are parsed as such
475
- if let DataType::Int64 = av.dtype() {
476
- let int_value = av.try_extract::<i64>().unwrap();
477
- if int_value >= i32::MIN as i64 && int_value <= i32::MAX as i64 {
478
- value = value.cast(DataType::Int32);
479
- }
480
- }
481
- }
482
- Ok(dsl::repeat(value, n).into())
494
+ dsl::repeat(value, n).into()
483
495
  }
484
496
 
485
497
  pub fn spearman_rank_corr(a: &RbExpr, b: &RbExpr, propagate_nans: bool) -> RbExpr {
@@ -1,18 +1,19 @@
1
- use magnus::{IntoValue, Ruby, Value};
1
+ use magnus::{Ruby, Value};
2
2
  use polars_core;
3
- use polars_core::POOL;
4
3
  use polars_core::fmt::FloatFmt;
5
4
  use polars_core::prelude::IDX_DTYPE;
5
+ use polars_core::runtime::RAYON;
6
6
 
7
7
  use crate::conversion::Wrap;
8
+ use crate::ruby::utils::TryIntoValue;
8
9
  use crate::{RbResult, RbValueError};
9
10
 
10
- pub fn get_index_type(ruby: &Ruby) -> Value {
11
- Wrap(IDX_DTYPE).into_value_with(ruby)
11
+ pub fn get_index_type(ruby: &Ruby) -> RbResult<Value> {
12
+ Wrap(IDX_DTYPE).try_into_value_with(ruby)
12
13
  }
13
14
 
14
15
  pub fn thread_pool_size() -> usize {
15
- POOL.current_num_threads()
16
+ RAYON.current_num_threads()
16
17
  }
17
18
 
18
19
  pub fn set_float_fmt(fmt: String) -> RbResult<()> {
@@ -7,7 +7,6 @@ pub mod meta;
7
7
  pub mod misc;
8
8
  pub mod random;
9
9
  pub mod range;
10
- pub mod string_cache;
11
10
  pub mod strings;
12
11
  pub mod utils;
13
12
  pub mod whenthen;
@@ -1,6 +1,8 @@
1
1
  use crate::RbResult;
2
- use polars_core::config::get_engine_affinity;
3
2
 
4
3
  pub fn rb_get_engine_affinity() -> RbResult<String> {
5
- Ok(get_engine_affinity())
4
+ Ok(polars_config::config()
5
+ .engine_affinity()
6
+ .as_static_str()
7
+ .to_string())
6
8
  }
@@ -1,10 +1,11 @@
1
1
  use magnus::prelude::*;
2
- use magnus::{RHash, Value};
2
+ use magnus::{RHash, Ruby, Value};
3
3
  use polars::prelude::{ArrowDataType, DataType};
4
4
  use polars_error::polars_err;
5
5
 
6
6
  use crate::interop::arrow::to_rust::normalize_arrow_fields;
7
7
  use crate::prelude::Wrap;
8
+ use crate::ruby::utils::TryIntoValue;
8
9
  use crate::series::import_schema_rbcapsule;
9
10
  use crate::utils::to_rb_err;
10
11
  use crate::{RbResult, RbValueError};
@@ -16,6 +17,7 @@ pub fn init_polars_schema_from_arrow_c_schema(
16
17
  polars_schema: RHash,
17
18
  schema_object: Value,
18
19
  ) -> RbResult<()> {
20
+ let ruby = &Ruby::get_with(polars_schema);
19
21
  let schema_capsule = schema_object.funcall("arrow_c_schema", ())?;
20
22
 
21
23
  let field = import_schema_rbcapsule(schema_capsule)?;
@@ -33,7 +35,7 @@ pub fn init_polars_schema_from_arrow_c_schema(
33
35
  let dtype = DataType::from_arrow_field(&field);
34
36
 
35
37
  let name = field.name.as_str();
36
- let dtype = Wrap(dtype);
38
+ let dtype = Wrap(dtype).try_into_value_with(ruby)?;
37
39
 
38
40
  if polars_schema.get(name).is_some() {
39
41
  return Err(to_rb_err(polars_err!(
@@ -6,20 +6,12 @@ use polars::frame::DataFrame;
6
6
  use polars::prelude::{ArrayRef, ArrowField, PlSmallStr, PolarsResult, SchemaExt};
7
7
  use polars::series::Series;
8
8
  use polars_core::utils::arrow;
9
+ use std::ffi::CString;
9
10
 
10
11
  use crate::RbResult;
12
+ use crate::ruby::capsule::RbCapsule;
11
13
 
12
- #[magnus::wrap(class = "Polars::ArrowArrayStream")]
13
- pub struct RbArrowArrayStream {
14
- pub(crate) stream: ffi::ArrowArrayStream,
15
- }
16
-
17
- impl RbArrowArrayStream {
18
- pub fn to_i(&self) -> usize {
19
- (&self.stream as *const _) as usize
20
- }
21
- }
22
-
14
+ // TODO switch to RbCapsule in 0.27.0
23
15
  #[magnus::wrap(class = "Polars::ArrowSchema")]
24
16
  pub struct RbArrowSchema {
25
17
  pub(crate) schema: ffi::ArrowSchema,
@@ -31,11 +23,24 @@ impl RbArrowSchema {
31
23
  }
32
24
  }
33
25
 
26
+ pub(crate) fn series_to_stream(series: &Series, ruby: &Ruby) -> RbResult<Value> {
27
+ let field = series.field().to_arrow(CompatLevel::newest());
28
+ let series = series.clone();
29
+ let iter = Box::new(
30
+ (0..series.n_chunks()).map(move |i| Ok(series.to_arrow(i, CompatLevel::newest()))),
31
+ ) as _;
32
+
33
+ let stream = ffi::export_iterator(iter, field);
34
+ let stream_capsule_name = CString::new("arrow_array_stream").unwrap();
35
+ Ok(RbCapsule::new(stream, Some(stream_capsule_name)).into_value_with(ruby))
36
+ }
37
+
34
38
  pub(crate) fn dataframe_to_stream(df: &DataFrame, ruby: &Ruby) -> RbResult<Value> {
35
39
  let iter = Box::new(DataFrameStreamIterator::new(df));
36
40
  let field = iter.field();
37
41
  let stream = ffi::export_iterator(iter, field);
38
- Ok(RbArrowArrayStream { stream }.into_value_with(ruby))
42
+ let stream_capsule_name = CString::new("arrow_array_stream").unwrap();
43
+ Ok(RbCapsule::new(stream, Some(stream_capsule_name)).into_value_with(ruby))
39
44
  }
40
45
 
41
46
  pub(crate) fn polars_schema_to_rbcapsule(