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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -0,0 +1,105 @@
1
+ //! A global process-aborting timeout system, mainly intended for testing.
2
+
3
+ use std::cmp::Reverse;
4
+ use std::collections::BinaryHeap;
5
+ use std::sync::LazyLock;
6
+ use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender, channel};
7
+ use std::time::Duration;
8
+
9
+ use polars::prelude::{InitHashMaps, PlHashSet};
10
+ use polars_utils::priority::Priority;
11
+ use polars_utils::relaxed_cell::RelaxedCell;
12
+
13
+ static TIMEOUT_REQUEST_HANDLER: LazyLock<Sender<TimeoutRequest>> = LazyLock::new(|| {
14
+ let (send, recv) = channel();
15
+ std::thread::Builder::new()
16
+ .name("polars-timeout".to_string())
17
+ .spawn(move || timeout_thread(recv))
18
+ .unwrap();
19
+ send
20
+ });
21
+
22
+ enum TimeoutRequest {
23
+ Start(Duration, u64),
24
+ Cancel(u64),
25
+ }
26
+
27
+ pub fn get_timeout() -> Option<Duration> {
28
+ static TIMEOUT_DISABLED: RelaxedCell<bool> = RelaxedCell::new_bool(false);
29
+
30
+ // Fast path so we don't have to keep checking environment variables. Make
31
+ // sure that if you want to use POLARS_TIMEOUT_MS it is set before the first
32
+ // polars call.
33
+ if TIMEOUT_DISABLED.load() {
34
+ return None;
35
+ }
36
+
37
+ let Ok(timeout) = std::env::var("POLARS_TIMEOUT_MS") else {
38
+ TIMEOUT_DISABLED.store(true);
39
+ return None;
40
+ };
41
+
42
+ match timeout.parse() {
43
+ Ok(ms) => Some(Duration::from_millis(ms)),
44
+ Err(e) => {
45
+ eprintln!("failed to parse POLARS_TIMEOUT_MS: {e:?}");
46
+ None
47
+ }
48
+ }
49
+ }
50
+
51
+ fn timeout_thread(recv: Receiver<TimeoutRequest>) {
52
+ let mut active_timeouts: PlHashSet<u64> = PlHashSet::new();
53
+ let mut shortest_timeout: BinaryHeap<Priority<Reverse<Duration>, u64>> = BinaryHeap::new();
54
+ loop {
55
+ // Remove cancelled requests.
56
+ while let Some(Priority(_, id)) = shortest_timeout.peek() {
57
+ if active_timeouts.contains(id) {
58
+ break;
59
+ }
60
+ shortest_timeout.pop();
61
+ }
62
+
63
+ let request = if let Some(Priority(timeout, _)) = shortest_timeout.peek() {
64
+ match recv.recv_timeout(timeout.0) {
65
+ Err(RecvTimeoutError::Timeout) => {
66
+ eprintln!("exiting the process, POLARS_TIMEOUT_MS exceeded");
67
+ std::thread::sleep(Duration::from_secs_f64(1.0));
68
+ std::process::exit(1);
69
+ }
70
+ r => r.unwrap(),
71
+ }
72
+ } else {
73
+ recv.recv().unwrap()
74
+ };
75
+
76
+ match request {
77
+ TimeoutRequest::Start(duration, id) => {
78
+ shortest_timeout.push(Priority(Reverse(duration), id));
79
+ active_timeouts.insert(id);
80
+ }
81
+ TimeoutRequest::Cancel(id) => {
82
+ active_timeouts.remove(&id);
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ pub fn schedule_polars_timeout() -> Option<u64> {
89
+ static TIMEOUT_ID: RelaxedCell<u64> = RelaxedCell::new_u64(0);
90
+
91
+ let timeout = get_timeout()?;
92
+ let id = TIMEOUT_ID.fetch_add(1);
93
+ TIMEOUT_REQUEST_HANDLER
94
+ .send(TimeoutRequest::Start(timeout, id))
95
+ .unwrap();
96
+ Some(id)
97
+ }
98
+
99
+ pub fn cancel_polars_timeout(opt_id: Option<u64>) {
100
+ if let Some(id) = opt_id {
101
+ TIMEOUT_REQUEST_HANDLER
102
+ .send(TimeoutRequest::Cancel(id))
103
+ .unwrap();
104
+ }
105
+ }
@@ -1,24 +1,125 @@
1
+ use std::panic::AssertUnwindSafe;
2
+
3
+ use magnus::Ruby;
4
+ use polars::frame::DataFrame;
5
+ use polars::series::IntoSeries;
6
+ use polars_error::PolarsResult;
7
+ use polars_error::signals::{KeyboardInterrupt, catch_keyboard_interrupt};
8
+
9
+ use crate::ruby::exceptions::RbKeyboardInterrupt;
10
+ use crate::ruby::gvl::GvlExt;
11
+ use crate::timeout::{cancel_polars_timeout, schedule_polars_timeout};
12
+ use crate::{RbDataFrame, RbErr, RbPolarsErr, RbResult, RbSeries};
13
+
1
14
  #[macro_export]
2
- macro_rules! apply_method_all_arrow_series2 {
15
+ macro_rules! apply_all_polars_dtypes {
3
16
  ($self:expr, $method:ident, $($args:expr),*) => {
4
17
  match $self.dtype() {
5
18
  DataType::Boolean => $self.bool().unwrap().$method($($args),*),
6
- DataType::String => $self.str().unwrap().$method($($args),*),
7
19
  DataType::UInt8 => $self.u8().unwrap().$method($($args),*),
8
20
  DataType::UInt16 => $self.u16().unwrap().$method($($args),*),
9
21
  DataType::UInt32 => $self.u32().unwrap().$method($($args),*),
10
22
  DataType::UInt64 => $self.u64().unwrap().$method($($args),*),
23
+ DataType::UInt128 => $self.u128().unwrap().$method($($args),*),
11
24
  DataType::Int8 => $self.i8().unwrap().$method($($args),*),
12
25
  DataType::Int16 => $self.i16().unwrap().$method($($args),*),
13
26
  DataType::Int32 => $self.i32().unwrap().$method($($args),*),
14
27
  DataType::Int64 => $self.i64().unwrap().$method($($args),*),
28
+ DataType::Int128 => $self.i128().unwrap().$method($($args),*),
29
+ DataType::Float16 => $self.cast(&DataType::Float32).unwrap().f32().unwrap().$method($($args),*),
15
30
  DataType::Float32 => $self.f32().unwrap().$method($($args),*),
16
31
  DataType::Float64 => $self.f64().unwrap().$method($($args),*),
32
+ DataType::String => $self.str().unwrap().$method($($args),*),
33
+ DataType::Binary => $self.binary().unwrap().$method($($args),*),
34
+ DataType::Decimal(_, _) => $self.decimal().unwrap().$method($($args),*),
35
+
17
36
  DataType::Date => $self.date().unwrap().$method($($args),*),
18
37
  DataType::Datetime(_, _) => $self.datetime().unwrap().$method($($args),*),
19
- // DataType::List(_) => $self.list().unwrap().$method($($args),*),
38
+ DataType::Duration(_) => $self.duration().unwrap().$method($($args),*),
39
+ DataType::Time => $self.time().unwrap().$method($($args),*),
40
+
41
+ DataType::List(_) => $self.list().unwrap().$method($($args),*),
20
42
  DataType::Struct(_) => $self.struct_().unwrap().$method($($args),*),
21
- dt => panic!("dtype {:?} not supported", dt)
43
+ DataType::Array(_, _) => $self.array().unwrap().$method($($args),*),
44
+
45
+ dt @ (DataType::Categorical(_, _) | DataType::Enum(_, _)) => match dt.cat_physical().unwrap() {
46
+ CategoricalPhysical::U8 => $self.cat8().unwrap().$method($($args),*),
47
+ CategoricalPhysical::U16 => $self.cat16().unwrap().$method($($args),*),
48
+ CategoricalPhysical::U32 => $self.cat32().unwrap().$method($($args),*),
49
+ },
50
+
51
+ DataType::Object(_) => {
52
+ $self
53
+ .as_any()
54
+ .downcast_ref::<ObjectChunked<ObjectValue>>()
55
+ .unwrap()
56
+ .$method($($args),*)
57
+ },
58
+ DataType::Extension(_, _) => $self.ext().unwrap().$method($($args),*),
59
+
60
+ DataType::Null => $self.null().unwrap().$method($($args),*),
61
+
62
+ dt @ (DataType::BinaryOffset | DataType::Unknown(_)) => panic!("dtype {:?} not supported", dt)
63
+ }
64
+ }
65
+ }
66
+
67
+ /// Boilerplate for `|e| RbPolarsErr::from(e).into()`
68
+ pub(crate) fn to_rb_err<E: Into<RbPolarsErr>>(e: E) -> RbErr {
69
+ e.into().into()
70
+ }
71
+
72
+ pub trait EnterPolarsExt {
73
+ fn enter_polars<T, E, F>(self, f: F) -> RbResult<T>
74
+ where
75
+ F: Send + FnOnce() -> Result<T, E>,
76
+ T: Send,
77
+ E: Send + Into<RbPolarsErr>;
78
+
79
+ #[inline(always)]
80
+ fn enter_polars_ok<T, F>(self, f: F) -> RbResult<T>
81
+ where
82
+ Self: Sized,
83
+ F: Send + FnOnce() -> T,
84
+ T: Send,
85
+ {
86
+ self.enter_polars(move || PolarsResult::Ok(f()))
87
+ }
88
+
89
+ #[inline(always)]
90
+ fn enter_polars_df<F>(self, f: F) -> RbResult<RbDataFrame>
91
+ where
92
+ Self: Sized,
93
+ F: Send + FnOnce() -> PolarsResult<DataFrame>,
94
+ {
95
+ self.enter_polars(f).map(RbDataFrame::new)
96
+ }
97
+
98
+ #[inline(always)]
99
+ fn enter_polars_series<T, F>(self, f: F) -> RbResult<RbSeries>
100
+ where
101
+ Self: Sized,
102
+ T: Send + IntoSeries,
103
+ F: Send + FnOnce() -> PolarsResult<T>,
104
+ {
105
+ self.enter_polars(f).map(|s| RbSeries::new(s.into_series()))
106
+ }
107
+ }
108
+
109
+ impl EnterPolarsExt for &Ruby {
110
+ fn enter_polars<T, E, F>(self, f: F) -> RbResult<T>
111
+ where
112
+ F: Send + FnOnce() -> Result<T, E>,
113
+ T: Send,
114
+ E: Send + Into<RbPolarsErr>,
115
+ {
116
+ let timeout = schedule_polars_timeout();
117
+ let ret = self.detach(|| catch_keyboard_interrupt(AssertUnwindSafe(f)));
118
+ cancel_polars_timeout(timeout);
119
+ match ret {
120
+ Ok(Ok(ret)) => Ok(ret),
121
+ Ok(Err(err)) => Err(RbErr::from(err.into())),
122
+ Err(KeyboardInterrupt) => Err(RbKeyboardInterrupt::new_err("")),
22
123
  }
23
124
  }
24
125
  }