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
@@ -26,37 +26,85 @@ module Polars
26
26
  #
27
27
  # @param name [String]
28
28
  # Name of the field
29
+ # @param more_names [Array]
30
+ # Additional struct field names.
29
31
  #
30
32
  # @return [Expr]
31
33
  #
32
34
  # @example
33
- # df = (
34
- # Polars::DataFrame.new(
35
- # {
36
- # "int" => [1, 2],
37
- # "str" => ["a", "b"],
38
- # "bool" => [true, nil],
39
- # "list" => [[1, 2], [3]]
40
- # }
41
- # )
42
- # .to_struct("my_struct")
43
- # .to_frame
44
- # )
45
- # df.select(Polars.col("my_struct").struct.field("str"))
35
+ # df = Polars::DataFrame.new(
36
+ # {
37
+ # "aaa" => [1, 2],
38
+ # "bbb" => ["ab", "cd"],
39
+ # "ccc" => [true, nil],
40
+ # "ddd" => [[1, 2], [3]]
41
+ # }
42
+ # ).select(Polars.struct("aaa", "bbb", "ccc", "ddd").alias("struct_col"))
43
+ # df.select(Polars.col("struct_col").struct.field("bbb"))
46
44
  # # =>
47
45
  # # shape: (2, 1)
48
46
  # # ┌─────┐
49
- # # │ str
47
+ # # │ bbb
50
48
  # # │ --- │
51
49
  # # │ str │
52
50
  # # ╞═════╡
53
- # # │ a
54
- # # │ b
51
+ # # │ ab
52
+ # # │ cd
55
53
  # # └─────┘
56
- def field(name)
54
+ #
55
+ # @example
56
+ # df.select(Polars.col("struct_col").struct.field("aaa", "bbb"))
57
+ # # =>
58
+ # # shape: (2, 2)
59
+ # # ┌─────┬─────┐
60
+ # # │ aaa ┆ bbb │
61
+ # # │ --- ┆ --- │
62
+ # # │ i64 ┆ str │
63
+ # # ╞═════╪═════╡
64
+ # # │ 1 ┆ ab │
65
+ # # │ 2 ┆ cd │
66
+ # # └─────┴─────┘
67
+ def field(name, *more_names)
68
+ if more_names.any?
69
+ name = (name.is_a?(::String) ? [name] : name) + more_names
70
+ end
71
+ if name.is_a?(::Array)
72
+ return Utils.wrap_expr(_rbexpr.struct_multiple_fields(name))
73
+ end
74
+
57
75
  Utils.wrap_expr(_rbexpr.struct_field_by_name(name))
58
76
  end
59
77
 
78
+ # Expand the struct into its individual fields.
79
+ #
80
+ # Alias for `Expr.struct.field("*")`.
81
+ #
82
+ # @return [Expr]
83
+ #
84
+ # @example
85
+ # df = Polars::DataFrame.new(
86
+ # {
87
+ # "aaa" => [1, 2],
88
+ # "bbb" => ["ab", "cd"],
89
+ # "ccc" => [true, nil],
90
+ # "ddd" => [[1, 2], [3]]
91
+ # }
92
+ # ).select(Polars.struct("aaa", "bbb", "ccc", "ddd").alias("struct_col"))
93
+ # df.select(Polars.col("struct_col").struct.unnest)
94
+ # # =>
95
+ # # shape: (2, 4)
96
+ # # ┌─────┬─────┬──────┬───────────┐
97
+ # # │ aaa ┆ bbb ┆ ccc ┆ ddd │
98
+ # # │ --- ┆ --- ┆ --- ┆ --- │
99
+ # # │ i64 ┆ str ┆ bool ┆ list[i64] │
100
+ # # ╞═════╪═════╪══════╪═══════════╡
101
+ # # │ 1 ┆ ab ┆ true ┆ [1, 2] │
102
+ # # │ 2 ┆ cd ┆ null ┆ [3] │
103
+ # # └─────┴─────┴──────┴───────────┘
104
+ def unnest
105
+ field("*")
106
+ end
107
+
60
108
  # Rename the fields of the struct.
61
109
  #
62
110
  # @param names [Array]
@@ -77,7 +125,7 @@ module Polars
77
125
  # .to_struct("my_struct")
78
126
  # .to_frame
79
127
  # )
80
- # df = df.with_column(
128
+ # df = df.with_columns(
81
129
  # Polars.col("my_struct").struct.rename_fields(["INT", "STR", "BOOL", "LIST"])
82
130
  # )
83
131
  # df.select(Polars.col("my_struct").struct.field("INT"))
@@ -94,5 +142,78 @@ module Polars
94
142
  def rename_fields(names)
95
143
  Utils.wrap_expr(_rbexpr.struct_rename_fields(names))
96
144
  end
145
+
146
+ # Convert this struct to a string column with json values.
147
+ #
148
+ # @return [Expr]
149
+ #
150
+ # @example
151
+ # Polars::DataFrame.new(
152
+ # {"a" => [{"a" => [1, 2], "b" => [45]}, {"a" => [9, 1, 3], "b" => nil}]}
153
+ # ).with_columns(Polars.col("a").struct.json_encode.alias("encoded"))
154
+ # # =>
155
+ # # shape: (2, 2)
156
+ # # ┌──────────────────┬────────────────────────┐
157
+ # # │ a ┆ encoded │
158
+ # # │ --- ┆ --- │
159
+ # # │ struct[2] ┆ str │
160
+ # # ╞══════════════════╪════════════════════════╡
161
+ # # │ {[1, 2],[45]} ┆ {"a":[1,2],"b":[45]} │
162
+ # # │ {[9, 1, 3],null} ┆ {"a":[9,1,3],"b":null} │
163
+ # # └──────────────────┴────────────────────────┘
164
+ def json_encode
165
+ Utils.wrap_expr(_rbexpr.struct_json_encode)
166
+ end
167
+
168
+ # Add or overwrite fields of this struct.
169
+ #
170
+ # This is similar to `with_columns` on `DataFrame`.
171
+ #
172
+ # @param exprs [Array]
173
+ # Field(s) to add, specified as positional arguments.
174
+ # Accepts expression input. Strings are parsed as column names, other
175
+ # non-expression inputs are parsed as literals.
176
+ # @param named_exprs [Hash]
177
+ # Additional fields to add, specified as keyword arguments.
178
+ # The columns will be renamed to the keyword used.
179
+ #
180
+ # @return [Expr]
181
+ #
182
+ # @example
183
+ # df = Polars::DataFrame.new(
184
+ # {
185
+ # "coords" => [{"x" => 1, "y" => 4}, {"x" => 4, "y" => 9}, {"x" => 9, "y" => 16}],
186
+ # "multiply" => [10, 2, 3]
187
+ # }
188
+ # )
189
+ # df.with_columns(
190
+ # Polars.col("coords").struct.with_fields(
191
+ # Polars.field("x").sqrt,
192
+ # y_mul: Polars.field("y") * Polars.col("multiply")
193
+ # )
194
+ # )
195
+ # # =>
196
+ # # shape: (3, 2)
197
+ # # ┌─────────────┬──────────┐
198
+ # # │ coords ┆ multiply │
199
+ # # │ --- ┆ --- │
200
+ # # │ struct[3] ┆ i64 │
201
+ # # ╞═════════════╪══════════╡
202
+ # # │ {1.0,4,40} ┆ 10 │
203
+ # # │ {2.0,9,18} ┆ 2 │
204
+ # # │ {3.0,16,48} ┆ 3 │
205
+ # # └─────────────┴──────────┘
206
+ def with_fields(
207
+ *exprs,
208
+ **named_exprs
209
+ )
210
+ structify = ENV.fetch("POLARS_AUTO_STRUCTIFY", 0).to_i != 0
211
+
212
+ rbexprs = Utils.parse_into_list_of_expressions(
213
+ *exprs, **named_exprs, __structify: structify
214
+ )
215
+
216
+ Utils.wrap_expr(_rbexpr.struct_with_fields(rbexprs))
217
+ end
97
218
  end
98
219
  end
@@ -80,7 +80,7 @@ module Polars
80
80
  super
81
81
  end
82
82
 
83
- # Get the struct definition as a name/dtype schema dict.
83
+ # Get the struct definition as a name/dtype schema hash.
84
84
  #
85
85
  # @return [Object]
86
86
  #
@@ -116,5 +116,23 @@ module Polars
116
116
  def unnest
117
117
  Utils.wrap_df(_s.struct_unnest)
118
118
  end
119
+
120
+ # Convert this struct to a string column with json values.
121
+ #
122
+ # @return [Series]
123
+ #
124
+ # @example
125
+ # s = Polars::Series.new("a", [{"a" => [1, 2], "b" => [45]}, {"a" => [9, 1, 3], "b" => nil}])
126
+ # s.struct.json_encode
127
+ # # =>
128
+ # # shape: (2,)
129
+ # # Series: 'a' [str]
130
+ # # [
131
+ # # "{"a":[1,2],"b":[45]}"
132
+ # # "{"a":[9,1,3],"b":null}"
133
+ # # ]
134
+ def json_encode
135
+ super
136
+ end
119
137
  end
120
138
  end
@@ -40,50 +40,22 @@ module Polars
40
40
  categorical_as_str: false
41
41
  )
42
42
  lazy = _assert_correct_input_type(left, right)
43
- objects = lazy ? "LazyFrames" : "DataFrames"
44
-
45
- _assert_frame_schema_equal(
46
- left,
47
- right,
48
- check_column_order: check_column_order,
49
- check_dtype: check_dtype,
50
- objects: objects,
51
- )
52
43
 
53
44
  if lazy
54
45
  left, right = left.collect, right.collect
55
46
  end
56
47
 
57
- if left.height != right.height
58
- raise_assertion_error(
59
- objects, "number of rows does not match", left.height, right.height
60
- )
61
- end
62
-
63
- if !check_row_order
64
- left, right = _sort_dataframes(left, right)
65
- end
66
-
67
- left.columns.each do |c|
68
- s_left, s_right = left.get_column(c), right.get_column(c)
69
- begin
70
- _assert_series_values_equal(
71
- s_left,
72
- s_right,
73
- check_exact: check_exact,
74
- rtol: rtol,
75
- atol: atol,
76
- categorical_as_str: categorical_as_str
77
- )
78
- rescue AssertionError
79
- raise_assertion_error(
80
- objects,
81
- "value mismatch for column #{c.inspect}",
82
- s_left.to_a,
83
- s_right.to_a
84
- )
85
- end
86
- end
48
+ Plr.assert_dataframe_equal_rb(
49
+ left._df,
50
+ right._df,
51
+ check_row_order,
52
+ check_column_order,
53
+ check_dtype,
54
+ check_exact,
55
+ rtol,
56
+ atol,
57
+ categorical_as_str,
58
+ )
87
59
  end
88
60
 
89
61
  # Assert that the left and right frame are **not** equal.
@@ -157,6 +129,8 @@ module Polars
157
129
  # Require data types to match.
158
130
  # @param check_names [Boolean]
159
131
  # Require names to match.
132
+ # @param check_order [Boolean]
133
+ # Requires elements to appear in the same order.
160
134
  # @param check_exact [Boolean]
161
135
  # Require float values to match exactly. If set to `false`, values are considered
162
136
  # equal when within tolerance of each other (see `rtol` and `atol`).
@@ -176,6 +150,7 @@ module Polars
176
150
  right,
177
151
  check_dtype: true,
178
152
  check_names: true,
153
+ check_order: true,
179
154
  check_exact: false,
180
155
  rtol: 1e-5,
181
156
  atol: 1e-8,
@@ -190,25 +165,16 @@ module Polars
190
165
  )
191
166
  end
192
167
 
193
- if left.len != right.len
194
- raise_assertion_error("Series", "length mismatch", left.len, right.len)
195
- end
196
-
197
- if check_names && left.name != right.name
198
- raise_assertion_error("Series", "name mismatch", left.name, right.name)
199
- end
200
-
201
- if check_dtype && left.dtype != right.dtype
202
- raise_assertion_error("Series", "dtype mismatch", left.dtype, right.dtype)
203
- end
204
-
205
- _assert_series_values_equal(
206
- left,
207
- right,
208
- check_exact: check_exact,
209
- rtol: rtol,
210
- atol: atol,
211
- categorical_as_str: categorical_as_str
168
+ Plr.assert_series_equal_rb(
169
+ left._s,
170
+ right._s,
171
+ check_dtype,
172
+ check_names,
173
+ check_order,
174
+ check_exact,
175
+ rtol,
176
+ atol,
177
+ categorical_as_str
212
178
  )
213
179
  end
214
180
 
@@ -284,221 +250,6 @@ module Polars
284
250
  end
285
251
  end
286
252
 
287
- def _assert_frame_schema_equal(
288
- left,
289
- right,
290
- check_dtype:,
291
- check_column_order:,
292
- objects:
293
- )
294
- left_schema, right_schema = left.schema, right.schema
295
-
296
- # Fast path for equal frames
297
- if left_schema == right_schema
298
- return
299
- end
300
-
301
- # Special error message for when column names do not match
302
- if left_schema.keys != right_schema.keys
303
- if (left_not_right = right_schema.keys - left_schema.keys).any?
304
- msg = "columns #{left_not_right.inspect} in left #{objects[..-1]}, but not in right"
305
- raise AssertionError, msg
306
- else
307
- right_not_left = right_schema.keys - left_schema.keys
308
- msg = "columns #{right_not_left.inspect} in right #{objects[..-1]}, but not in left"
309
- raise AssertionError, msg
310
- end
311
- end
312
-
313
- if check_column_order
314
- left_columns, right_columns = left_schema.keys, right_schema.keys
315
- if left_columns != right_columns
316
- detail = "columns are not in the same order"
317
- raise_assertion_error(objects, detail, left_columns, right_columns)
318
- end
319
- end
320
-
321
- if check_dtype
322
- left_schema_dict, right_schema_dict = left_schema.to_h, right_schema.to_h
323
- if check_column_order || left_schema_dict != right_schema_dict
324
- detail = "dtypes do not match"
325
- raise_assertion_error(objects, detail, left_schema_dict, right_schema_dict)
326
- end
327
- end
328
- end
329
-
330
- def _sort_dataframes(left, right)
331
- by = left.columns
332
- begin
333
- left = left.sort(by)
334
- right = right.sort(by)
335
- rescue
336
- msg = "cannot set `check_row_order: false` on frame with unsortable columns"
337
- raise InvalidAssert, msg
338
- end
339
- [left, right]
340
- end
341
-
342
- def _assert_series_values_equal(
343
- left,
344
- right,
345
- check_exact:,
346
- rtol:,
347
- atol:,
348
- categorical_as_str:
349
- )
350
- if categorical_as_str
351
- if left.dtype == Categorical
352
- left = left.cast(String)
353
- end
354
- if right.dtype == Categorical
355
- right = right.cast(String)
356
- end
357
- end
358
-
359
- # Determine unequal elements
360
- begin
361
- unequal = left.ne_missing(right)
362
- rescue
363
- raise_assertion_error(
364
- "Series",
365
- "incompatible data types",
366
- left.dtype,
367
- right.dtype
368
- )
369
- end
370
-
371
- # Check nested dtypes in separate function
372
- if _comparing_nested_floats(left.dtype, right.dtype)
373
- begin
374
- _assert_series_nested_values_equal(
375
- left: left.filter(unequal),
376
- right: right.filter(unequal),
377
- check_exact: check_exact,
378
- rtol: rtol,
379
- atol: atol,
380
- categorical_as_str: categorical_as_str
381
- )
382
- rescue AssertionError
383
- raise_assertion_error(
384
- "Series",
385
- "nested value mismatch",
386
- left.to_a,
387
- right.to_a
388
- )
389
- else
390
- return
391
- end
392
- end
393
-
394
- # If no differences found during exact checking, we're done
395
- if !unequal.any
396
- return
397
- end
398
-
399
- # Only do inexact checking for float types
400
- if check_exact || !left.dtype.float? || !right.dtype.float?
401
- raise_assertion_error(
402
- "Series", "exact value mismatch", left.to_a, right.to_a
403
- )
404
- end
405
-
406
- _assert_series_null_values_match(left, right)
407
- _assert_series_nan_values_match(left, right)
408
- _assert_series_values_within_tolerance(
409
- left,
410
- right,
411
- unequal,
412
- rtol: rtol,
413
- atol: atol
414
- )
415
- end
416
-
417
- def _assert_series_nested_values_equal(
418
- left,
419
- right,
420
- check_exact:,
421
- rtol:,
422
- atol:,
423
- categorical_as_str:
424
- )
425
- # compare nested lists element-wise
426
- if _comparing_lists(left.dtype, right.dtype)
427
- left.zip(right) do |s1, s2|
428
- if s1.nil? || s2.nil?
429
- raise_assertion_error("Series", "nested value mismatch", s1, s2)
430
- end
431
-
432
- _assert_series_values_equal(
433
- s1,
434
- s2,
435
- check_exact: check_exact,
436
- rtol: rtol,
437
- atol: atol,
438
- categorical_as_str: categorical_as_str
439
- )
440
- end
441
-
442
- # unnest structs as series and compare
443
- else
444
- ls, rs = left.struct.unnest, right.struct.unnest
445
- ls.zip(rs) do |s1, s2|
446
- _assert_series_values_equal(
447
- s1,
448
- s2,
449
- check_exact: check_exact,
450
- rtol: rtol,
451
- atol: atol,
452
- categorical_as_str: categorical_as_str
453
- )
454
- end
455
- end
456
- end
457
-
458
- def _assert_series_null_values_match(left, right)
459
- null_value_mismatch = left.is_null != right.is_null
460
- if null_value_mismatch.any
461
- raise_assertion_error(
462
- "Series", "null value mismatch", left.to_a, right.to_a
463
- )
464
- end
465
- end
466
-
467
- def _assert_series_nan_values_match(left, right)
468
- if !_comparing_floats(left.dtype, right.dtype)
469
- return
470
- end
471
- nan_value_mismatch = left.is_nan != right.is_nan
472
- if nan_value_mismatch.any
473
- raise_assertion_error(
474
- "Series",
475
- "nan value mismatch",
476
- left.to_a,
477
- right.to_a
478
- )
479
- end
480
- end
481
-
482
- def _comparing_floats(left, right)
483
- left.is_float && right.is_float
484
- end
485
-
486
- def _comparing_lists(left, right)
487
- [List, Array].include?(left) && [List, Array].include?(right)
488
- end
489
-
490
- def _comparing_structs(left, right)
491
- left == Struct && right == Struct
492
- end
493
-
494
- def _comparing_nested_floats(left, right)
495
- if !(_comparing_lists(left, right) || _comparing_structs(left, right))
496
- return false
497
- end
498
-
499
- left.float? && right.float?
500
- end
501
-
502
253
  def raise_assertion_error(objects, detail, left, right)
503
254
  msg = "#{objects} are different (#{detail})\n[left]: #{left}\n[right]: #{right}"
504
255
  raise AssertionError, msg
@@ -1,5 +1,7 @@
1
1
  module Polars
2
2
  module Utils
3
+ U32_MAX = 2**32 - 1
4
+
3
5
  SECONDS_PER_DAY = 86_400
4
6
  SECONDS_PER_HOUR = 3_600
5
7
  NS_PER_SECOND = 1_000_000_000