Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-python/src/lazyframe/visitor/expr_nodes.rs
8396 views
1
#[cfg(feature = "iejoin")]
2
use polars::prelude::InequalityOperator;
3
use polars::series::ops::NullBehavior;
4
use polars_core::chunked_array::ops::FillNullStrategy;
5
use polars_core::series::IsSorted;
6
#[cfg(feature = "string_normalize")]
7
use polars_ops::chunked_array::UnicodeForm;
8
use polars_ops::prelude::RankMethod;
9
use polars_ops::series::InterpolationMethod;
10
#[cfg(feature = "search_sorted")]
11
use polars_ops::series::SearchSortedSide;
12
use polars_plan::plans::{
13
DynLiteralValue, IRBooleanFunction, IRFunctionExpr, IRPowFunction, IRRollingFunctionBy,
14
IRStringFunction, IRStructFunction, IRTemporalFunction,
15
};
16
use polars_plan::prelude::{
17
AExpr, GroupbyOptions, IRAggExpr, LiteralValue, Operator, WindowMapping,
18
};
19
use polars_time::prelude::RollingGroupOptions;
20
use polars_time::{Duration, DynamicGroupOptions};
21
use pyo3::IntoPyObjectExt;
22
use pyo3::exceptions::PyNotImplementedError;
23
use pyo3::prelude::*;
24
use pyo3::types::{PyInt, PyTuple};
25
26
use crate::Wrap;
27
use crate::series::PySeries;
28
29
#[pyclass(frozen)]
30
pub struct Alias {
31
#[pyo3(get)]
32
expr: usize,
33
#[pyo3(get)]
34
name: Py<PyAny>,
35
}
36
37
#[pyclass(frozen)]
38
pub struct Column {
39
#[pyo3(get)]
40
name: Py<PyAny>,
41
}
42
43
#[pyclass(frozen)]
44
pub struct Literal {
45
#[pyo3(get)]
46
value: Py<PyAny>,
47
#[pyo3(get)]
48
dtype: Py<PyAny>,
49
}
50
51
#[pyclass(name = "Operator", eq, frozen)]
52
#[derive(Copy, Clone, PartialEq)]
53
pub enum PyOperator {
54
Eq,
55
EqValidity,
56
NotEq,
57
NotEqValidity,
58
Lt,
59
LtEq,
60
Gt,
61
GtEq,
62
Plus,
63
Minus,
64
Multiply,
65
Divide,
66
TrueDivide,
67
FloorDivide,
68
Modulus,
69
And,
70
Or,
71
Xor,
72
LogicalAnd,
73
LogicalOr,
74
}
75
76
#[pymethods]
77
impl PyOperator {
78
fn __hash__(&self) -> isize {
79
*self as isize
80
}
81
}
82
83
impl<'py> IntoPyObject<'py> for Wrap<Operator> {
84
type Target = PyOperator;
85
type Output = Bound<'py, Self::Target>;
86
type Error = PyErr;
87
88
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
89
match self.0 {
90
Operator::Eq => PyOperator::Eq,
91
Operator::EqValidity => PyOperator::EqValidity,
92
Operator::NotEq => PyOperator::NotEq,
93
Operator::NotEqValidity => PyOperator::NotEqValidity,
94
Operator::Lt => PyOperator::Lt,
95
Operator::LtEq => PyOperator::LtEq,
96
Operator::Gt => PyOperator::Gt,
97
Operator::GtEq => PyOperator::GtEq,
98
Operator::Plus => PyOperator::Plus,
99
Operator::Minus => PyOperator::Minus,
100
Operator::Multiply => PyOperator::Multiply,
101
Operator::RustDivide => PyOperator::Divide,
102
Operator::TrueDivide => PyOperator::TrueDivide,
103
Operator::FloorDivide => PyOperator::FloorDivide,
104
Operator::Modulus => PyOperator::Modulus,
105
Operator::And => PyOperator::And,
106
Operator::Or => PyOperator::Or,
107
Operator::Xor => PyOperator::Xor,
108
Operator::LogicalAnd => PyOperator::LogicalAnd,
109
Operator::LogicalOr => PyOperator::LogicalOr,
110
}
111
.into_pyobject(py)
112
}
113
}
114
115
#[cfg(feature = "iejoin")]
116
impl<'py> IntoPyObject<'py> for Wrap<InequalityOperator> {
117
type Target = PyOperator;
118
type Output = Bound<'py, Self::Target>;
119
type Error = PyErr;
120
121
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
122
match self.0 {
123
InequalityOperator::Lt => PyOperator::Lt,
124
InequalityOperator::LtEq => PyOperator::LtEq,
125
InequalityOperator::Gt => PyOperator::Gt,
126
InequalityOperator::GtEq => PyOperator::GtEq,
127
}
128
.into_pyobject(py)
129
}
130
}
131
132
#[pyclass(name = "StringFunction", eq, frozen)]
133
#[derive(Copy, Clone, PartialEq)]
134
pub enum PyStringFunction {
135
ConcatHorizontal,
136
ConcatVertical,
137
Contains,
138
CountMatches,
139
EndsWith,
140
Extract,
141
ExtractAll,
142
ExtractGroups,
143
Find,
144
ToInteger,
145
LenBytes,
146
LenChars,
147
Lowercase,
148
JsonDecode,
149
JsonPathMatch,
150
Replace,
151
Reverse,
152
PadStart,
153
PadEnd,
154
Slice,
155
Head,
156
Tail,
157
HexEncode,
158
HexDecode,
159
Base64Encode,
160
Base64Decode,
161
StartsWith,
162
StripChars,
163
StripCharsStart,
164
StripCharsEnd,
165
StripPrefix,
166
StripSuffix,
167
SplitExact,
168
SplitN,
169
Strptime,
170
Split,
171
SplitRegex,
172
ToDecimal,
173
Titlecase,
174
Uppercase,
175
ZFill,
176
ContainsAny,
177
ReplaceMany,
178
EscapeRegex,
179
Normalize,
180
}
181
182
#[pymethods]
183
impl PyStringFunction {
184
fn __hash__(&self) -> isize {
185
*self as isize
186
}
187
}
188
189
#[pyclass(name = "BooleanFunction", eq, frozen)]
190
#[derive(Copy, Clone, PartialEq)]
191
pub enum PyBooleanFunction {
192
Any,
193
All,
194
IsNull,
195
IsNotNull,
196
IsFinite,
197
IsInfinite,
198
IsNan,
199
IsNotNan,
200
IsFirstDistinct,
201
IsLastDistinct,
202
IsUnique,
203
IsDuplicated,
204
IsBetween,
205
IsIn,
206
IsClose,
207
AllHorizontal,
208
AnyHorizontal,
209
Not,
210
}
211
212
#[pymethods]
213
impl PyBooleanFunction {
214
fn __hash__(&self) -> isize {
215
*self as isize
216
}
217
}
218
219
#[pyclass(name = "TemporalFunction", eq, frozen)]
220
#[derive(Copy, Clone, PartialEq)]
221
pub enum PyTemporalFunction {
222
Millennium,
223
Century,
224
Year,
225
IsLeapYear,
226
IsoYear,
227
Quarter,
228
Month,
229
DaysInMonth,
230
Week,
231
WeekDay,
232
Day,
233
OrdinalDay,
234
Time,
235
Date,
236
Datetime,
237
Duration,
238
Hour,
239
Minute,
240
Second,
241
Millisecond,
242
Microsecond,
243
Nanosecond,
244
TotalDays,
245
TotalHours,
246
TotalMinutes,
247
TotalSeconds,
248
TotalMilliseconds,
249
TotalMicroseconds,
250
TotalNanoseconds,
251
ToString,
252
CastTimeUnit,
253
WithTimeUnit,
254
ConvertTimeZone,
255
TimeStamp,
256
Truncate,
257
OffsetBy,
258
MonthStart,
259
MonthEnd,
260
BaseUtcOffset,
261
DSTOffset,
262
Round,
263
Replace,
264
ReplaceTimeZone,
265
Combine,
266
DatetimeFunction,
267
}
268
269
#[pymethods]
270
impl PyTemporalFunction {
271
fn __hash__(&self) -> isize {
272
*self as isize
273
}
274
}
275
276
#[pyclass(name = "StructFunction", eq, frozen)]
277
#[derive(Copy, Clone, PartialEq)]
278
pub enum PyStructFunction {
279
FieldByName,
280
RenameFields,
281
PrefixFields,
282
SuffixFields,
283
JsonEncode,
284
WithFields,
285
MapFieldNames,
286
}
287
288
#[pymethods]
289
impl PyStructFunction {
290
fn __hash__(&self) -> isize {
291
*self as isize
292
}
293
}
294
295
#[pyclass(frozen)]
296
pub struct BinaryExpr {
297
#[pyo3(get)]
298
left: usize,
299
#[pyo3(get)]
300
op: Py<PyAny>,
301
#[pyo3(get)]
302
right: usize,
303
}
304
305
#[pyclass(frozen)]
306
pub struct Cast {
307
#[pyo3(get)]
308
expr: usize,
309
#[pyo3(get)]
310
dtype: Py<PyAny>,
311
// 0: strict
312
// 1: non-strict
313
// 2: overflow
314
#[pyo3(get)]
315
options: u8,
316
}
317
318
#[pyclass(frozen)]
319
pub struct Sort {
320
#[pyo3(get)]
321
expr: usize,
322
#[pyo3(get)]
323
/// maintain_order, nulls_last, descending
324
options: (bool, bool, bool),
325
}
326
327
#[pyclass(frozen)]
328
pub struct Gather {
329
#[pyo3(get)]
330
expr: usize,
331
#[pyo3(get)]
332
idx: usize,
333
#[pyo3(get)]
334
scalar: bool,
335
}
336
337
#[pyclass(frozen)]
338
pub struct Filter {
339
#[pyo3(get)]
340
input: usize,
341
#[pyo3(get)]
342
by: usize,
343
}
344
345
#[pyclass(frozen)]
346
pub struct SortBy {
347
#[pyo3(get)]
348
expr: usize,
349
#[pyo3(get)]
350
by: Vec<usize>,
351
#[pyo3(get)]
352
/// maintain_order, nulls_last, descending
353
sort_options: (bool, Vec<bool>, Vec<bool>),
354
}
355
356
#[pyclass(frozen)]
357
pub struct Agg {
358
#[pyo3(get)]
359
name: Py<PyAny>,
360
#[pyo3(get)]
361
arguments: Vec<usize>,
362
#[pyo3(get)]
363
// Arbitrary control options
364
options: Py<PyAny>,
365
}
366
367
#[pyclass(frozen)]
368
pub struct Ternary {
369
#[pyo3(get)]
370
predicate: usize,
371
#[pyo3(get)]
372
truthy: usize,
373
#[pyo3(get)]
374
falsy: usize,
375
}
376
377
#[pyclass(frozen)]
378
pub struct Function {
379
#[pyo3(get)]
380
input: Vec<usize>,
381
#[pyo3(get)]
382
function_data: Py<PyAny>,
383
#[pyo3(get)]
384
options: Py<PyAny>,
385
}
386
387
#[pyclass(frozen)]
388
pub struct Slice {
389
#[pyo3(get)]
390
input: usize,
391
#[pyo3(get)]
392
offset: usize,
393
#[pyo3(get)]
394
length: usize,
395
}
396
397
#[pyclass(frozen)]
398
pub struct Len {}
399
400
#[pyclass(frozen)]
401
pub struct Window {
402
#[pyo3(get)]
403
function: usize,
404
#[pyo3(get)]
405
partition_by: Vec<usize>,
406
#[pyo3(get)]
407
order_by: Option<usize>,
408
#[pyo3(get)]
409
order_by_descending: bool,
410
#[pyo3(get)]
411
order_by_nulls_last: bool,
412
#[pyo3(get)]
413
options: Py<PyAny>,
414
}
415
416
#[pyclass(name = "WindowMapping", frozen)]
417
pub struct PyWindowMapping {
418
inner: WindowMapping,
419
}
420
421
#[pymethods]
422
impl PyWindowMapping {
423
#[getter]
424
fn kind(&self) -> &str {
425
self.inner.into()
426
}
427
}
428
429
impl<'py> IntoPyObject<'py> for Wrap<Duration> {
430
type Target = PyTuple;
431
type Output = Bound<'py, Self::Target>;
432
type Error = PyErr;
433
434
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
435
(
436
self.0.months(),
437
self.0.weeks(),
438
self.0.days(),
439
self.0.nanoseconds(),
440
self.0.parsed_int,
441
self.0.negative(),
442
)
443
.into_pyobject(py)
444
}
445
}
446
447
#[pyclass(name = "RollingGroupOptions", frozen)]
448
pub struct PyRollingGroupOptions {
449
inner: RollingGroupOptions,
450
}
451
452
#[pymethods]
453
impl PyRollingGroupOptions {
454
#[getter]
455
fn index_column(&self) -> &str {
456
self.inner.index_column.as_str()
457
}
458
459
#[getter]
460
fn period(&self) -> Wrap<Duration> {
461
Wrap(self.inner.period)
462
}
463
464
#[getter]
465
fn offset(&self) -> Wrap<Duration> {
466
Wrap(self.inner.offset)
467
}
468
469
#[getter]
470
fn closed_window(&self) -> &str {
471
self.inner.closed_window.into()
472
}
473
}
474
475
#[pyclass(name = "DynamicGroupOptions", frozen)]
476
pub struct PyDynamicGroupOptions {
477
inner: DynamicGroupOptions,
478
}
479
480
#[pymethods]
481
impl PyDynamicGroupOptions {
482
#[getter]
483
fn index_column(&self) -> &str {
484
self.inner.index_column.as_str()
485
}
486
487
#[getter]
488
fn every(&self) -> Wrap<Duration> {
489
Wrap(self.inner.every)
490
}
491
492
#[getter]
493
fn period(&self) -> Wrap<Duration> {
494
Wrap(self.inner.period)
495
}
496
497
#[getter]
498
fn offset(&self) -> Wrap<Duration> {
499
Wrap(self.inner.offset)
500
}
501
502
#[getter]
503
fn label(&self) -> &str {
504
self.inner.label.into()
505
}
506
507
#[getter]
508
fn include_boundaries(&self) -> bool {
509
self.inner.include_boundaries
510
}
511
512
#[getter]
513
fn closed_window(&self) -> &str {
514
self.inner.closed_window.into()
515
}
516
#[getter]
517
fn start_by(&self) -> &str {
518
self.inner.start_by.into()
519
}
520
}
521
522
#[pyclass(name = "GroupbyOptions", frozen)]
523
pub struct PyGroupbyOptions {
524
inner: GroupbyOptions,
525
}
526
527
impl PyGroupbyOptions {
528
pub(crate) fn new(inner: GroupbyOptions) -> Self {
529
Self { inner }
530
}
531
}
532
533
#[pymethods]
534
impl PyGroupbyOptions {
535
#[getter]
536
fn slice(&self) -> Option<(i64, usize)> {
537
self.inner.slice
538
}
539
540
#[getter]
541
fn dynamic(&self) -> Option<PyDynamicGroupOptions> {
542
self.inner
543
.dynamic
544
.as_ref()
545
.map(|f| PyDynamicGroupOptions { inner: f.clone() })
546
}
547
548
#[getter]
549
fn rolling(&self) -> Option<PyRollingGroupOptions> {
550
self.inner
551
.rolling
552
.as_ref()
553
.map(|f| PyRollingGroupOptions { inner: f.clone() })
554
}
555
}
556
557
pub(crate) fn into_py(py: Python<'_>, expr: &AExpr) -> PyResult<Py<PyAny>> {
558
match expr {
559
AExpr::Element => Err(PyNotImplementedError::new_err("element")),
560
AExpr::Explode { .. } => Err(PyNotImplementedError::new_err("explode")),
561
AExpr::Column(name) => Column {
562
name: name.into_py_any(py)?,
563
}
564
.into_py_any(py),
565
AExpr::StructField(_) => Err(PyNotImplementedError::new_err("field")),
566
AExpr::Literal(lit) => {
567
use polars_core::prelude::AnyValue;
568
let dtype: Py<PyAny> = Wrap(lit.get_datatype()).into_py_any(py)?;
569
let py_value = match lit {
570
LiteralValue::Dyn(d) => match d {
571
DynLiteralValue::Int(v) => v.into_py_any(py)?,
572
DynLiteralValue::Float(v) => v.into_py_any(py)?,
573
DynLiteralValue::Str(v) => v.into_py_any(py)?,
574
DynLiteralValue::List(_) => todo!(),
575
},
576
LiteralValue::Scalar(sc) => {
577
match sc.as_any_value() {
578
// AnyValue conversion of duration to python's
579
// datetime.timedelta drops nanoseconds because
580
// there is no support for them. See
581
// https://github.com/python/cpython/issues/59648
582
AnyValue::Duration(delta, _) => delta.into_py_any(py)?,
583
any => Wrap(any).into_py_any(py)?,
584
}
585
},
586
LiteralValue::Range(_) => {
587
return Err(PyNotImplementedError::new_err("range literal"));
588
},
589
LiteralValue::Series(s) => PySeries::new((**s).clone()).into_py_any(py)?,
590
};
591
592
Literal {
593
value: py_value,
594
dtype,
595
}
596
}
597
.into_py_any(py),
598
AExpr::BinaryExpr { left, op, right } => BinaryExpr {
599
left: left.0,
600
op: Wrap(*op).into_py_any(py)?,
601
right: right.0,
602
}
603
.into_py_any(py),
604
AExpr::Cast {
605
expr,
606
dtype,
607
options,
608
} => Cast {
609
expr: expr.0,
610
dtype: Wrap(dtype.clone()).into_py_any(py)?,
611
options: *options as u8,
612
}
613
.into_py_any(py),
614
AExpr::Sort { expr, options } => Sort {
615
expr: expr.0,
616
options: (
617
options.maintain_order,
618
options.nulls_last,
619
options.descending,
620
),
621
}
622
.into_py_any(py),
623
AExpr::Gather {
624
expr,
625
idx,
626
returns_scalar,
627
null_on_oob: _,
628
} => Gather {
629
expr: expr.0,
630
idx: idx.0,
631
scalar: *returns_scalar,
632
}
633
.into_py_any(py),
634
AExpr::Filter { input, by } => Filter {
635
input: input.0,
636
by: by.0,
637
}
638
.into_py_any(py),
639
AExpr::SortBy {
640
expr,
641
by,
642
sort_options,
643
} => SortBy {
644
expr: expr.0,
645
by: by.iter().map(|n| n.0).collect(),
646
sort_options: (
647
sort_options.maintain_order,
648
sort_options.nulls_last.clone(),
649
sort_options.descending.clone(),
650
),
651
}
652
.into_py_any(py),
653
AExpr::Agg(aggexpr) => match aggexpr {
654
IRAggExpr::Min {
655
input,
656
propagate_nans,
657
} => Agg {
658
name: "min".into_py_any(py)?,
659
arguments: vec![input.0],
660
options: propagate_nans.into_py_any(py)?,
661
},
662
IRAggExpr::Max {
663
input,
664
propagate_nans,
665
} => Agg {
666
name: "max".into_py_any(py)?,
667
arguments: vec![input.0],
668
options: propagate_nans.into_py_any(py)?,
669
},
670
IRAggExpr::Median(n) => Agg {
671
name: "median".into_py_any(py)?,
672
arguments: vec![n.0],
673
options: py.None(),
674
},
675
IRAggExpr::NUnique(n) => Agg {
676
name: "n_unique".into_py_any(py)?,
677
arguments: vec![n.0],
678
options: py.None(),
679
},
680
IRAggExpr::First(n) => Agg {
681
name: "first".into_py_any(py)?,
682
arguments: vec![n.0],
683
options: py.None(),
684
},
685
IRAggExpr::FirstNonNull(n) => Agg {
686
name: "first_non_null".into_py_any(py)?,
687
arguments: vec![n.0],
688
options: py.None(),
689
},
690
IRAggExpr::Last(n) => Agg {
691
name: "last".into_py_any(py)?,
692
arguments: vec![n.0],
693
options: py.None(),
694
},
695
IRAggExpr::LastNonNull(n) => Agg {
696
name: "last_non_null".into_py_any(py)?,
697
arguments: vec![n.0],
698
options: py.None(),
699
},
700
IRAggExpr::Item {
701
input: n,
702
allow_empty,
703
} => Agg {
704
name: "item".into_py_any(py)?,
705
arguments: vec![n.0],
706
options: allow_empty.into_py_any(py)?,
707
},
708
IRAggExpr::Mean(n) => Agg {
709
name: "mean".into_py_any(py)?,
710
arguments: vec![n.0],
711
options: py.None(),
712
},
713
IRAggExpr::Implode(n) => Agg {
714
name: "implode".into_py_any(py)?,
715
arguments: vec![n.0],
716
options: py.None(),
717
},
718
IRAggExpr::Quantile {
719
expr,
720
quantile,
721
method: interpol,
722
} => Agg {
723
name: "quantile".into_py_any(py)?,
724
arguments: vec![expr.0, quantile.0],
725
options: Into::<&str>::into(interpol).into_py_any(py)?,
726
},
727
IRAggExpr::Sum(n) => Agg {
728
name: "sum".into_py_any(py)?,
729
arguments: vec![n.0],
730
options: py.None(),
731
},
732
IRAggExpr::Count {
733
input: n,
734
include_nulls,
735
} => Agg {
736
name: "count".into_py_any(py)?,
737
arguments: vec![n.0],
738
options: include_nulls.into_py_any(py)?,
739
},
740
IRAggExpr::Std(n, ddof) => Agg {
741
name: "std".into_py_any(py)?,
742
arguments: vec![n.0],
743
options: ddof.into_py_any(py)?,
744
},
745
IRAggExpr::Var(n, ddof) => Agg {
746
name: "var".into_py_any(py)?,
747
arguments: vec![n.0],
748
options: ddof.into_py_any(py)?,
749
},
750
IRAggExpr::AggGroups(n) => Agg {
751
name: "agg_groups".into_py_any(py)?,
752
arguments: vec![n.0],
753
options: py.None(),
754
},
755
}
756
.into_py_any(py),
757
AExpr::Ternary {
758
predicate,
759
truthy,
760
falsy,
761
} => Ternary {
762
predicate: predicate.0,
763
truthy: truthy.0,
764
falsy: falsy.0,
765
}
766
.into_py_any(py),
767
AExpr::AnonymousFunction { .. } => Err(PyNotImplementedError::new_err("anonymousfunction")),
768
AExpr::AnonymousAgg { .. } => {
769
Err(PyNotImplementedError::new_err("anonymous_streaming_agg"))
770
},
771
AExpr::Function {
772
input,
773
function,
774
// TODO: expose options
775
options: _,
776
} => Function {
777
input: input.iter().map(|n| n.node().0).collect(),
778
function_data: match function {
779
IRFunctionExpr::ArrayExpr(_) => {
780
return Err(PyNotImplementedError::new_err("array expr"));
781
},
782
IRFunctionExpr::BinaryExpr(_) => {
783
return Err(PyNotImplementedError::new_err("binary expr"));
784
},
785
IRFunctionExpr::Categorical(_) => {
786
return Err(PyNotImplementedError::new_err("categorical expr"));
787
},
788
IRFunctionExpr::Extension(_) => {
789
return Err(PyNotImplementedError::new_err("extension expr"));
790
},
791
IRFunctionExpr::ListExpr(_) => {
792
return Err(PyNotImplementedError::new_err("list expr"));
793
},
794
IRFunctionExpr::Bitwise(_) => {
795
return Err(PyNotImplementedError::new_err("bitwise expr"));
796
},
797
IRFunctionExpr::StringExpr(strfun) => match strfun {
798
IRStringFunction::Format { .. } => {
799
return Err(PyNotImplementedError::new_err("bitwise expr"));
800
},
801
IRStringFunction::ConcatHorizontal {
802
delimiter,
803
ignore_nulls,
804
} => (
805
PyStringFunction::ConcatHorizontal,
806
delimiter.as_str(),
807
ignore_nulls,
808
)
809
.into_py_any(py),
810
IRStringFunction::ConcatVertical {
811
delimiter,
812
ignore_nulls,
813
} => (
814
PyStringFunction::ConcatVertical,
815
delimiter.as_str(),
816
ignore_nulls,
817
)
818
.into_py_any(py),
819
#[cfg(feature = "regex")]
820
IRStringFunction::Contains { literal, strict } => {
821
(PyStringFunction::Contains, literal, strict).into_py_any(py)
822
},
823
IRStringFunction::CountMatches(literal) => {
824
(PyStringFunction::CountMatches, literal).into_py_any(py)
825
},
826
IRStringFunction::EndsWith => (PyStringFunction::EndsWith,).into_py_any(py),
827
IRStringFunction::Extract(group_index) => {
828
(PyStringFunction::Extract, group_index).into_py_any(py)
829
},
830
IRStringFunction::ExtractAll => (PyStringFunction::ExtractAll,).into_py_any(py),
831
#[cfg(feature = "extract_groups")]
832
IRStringFunction::ExtractGroups { dtype, pat } => (
833
PyStringFunction::ExtractGroups,
834
&Wrap(dtype.clone()),
835
pat.as_str(),
836
)
837
.into_py_any(py),
838
#[cfg(feature = "regex")]
839
IRStringFunction::Find { literal, strict } => {
840
(PyStringFunction::Find, literal, strict).into_py_any(py)
841
},
842
IRStringFunction::ToInteger { dtype: _, strict } => {
843
(PyStringFunction::ToInteger, strict).into_py_any(py)
844
},
845
IRStringFunction::LenBytes => (PyStringFunction::LenBytes,).into_py_any(py),
846
IRStringFunction::LenChars => (PyStringFunction::LenChars,).into_py_any(py),
847
IRStringFunction::Lowercase => (PyStringFunction::Lowercase,).into_py_any(py),
848
#[cfg(feature = "extract_jsonpath")]
849
IRStringFunction::JsonDecode(_) => {
850
(PyStringFunction::JsonDecode, <Option<usize>>::None).into_py_any(py)
851
},
852
#[cfg(feature = "extract_jsonpath")]
853
IRStringFunction::JsonPathMatch => {
854
(PyStringFunction::JsonPathMatch,).into_py_any(py)
855
},
856
#[cfg(feature = "regex")]
857
IRStringFunction::Replace { n, literal } => {
858
(PyStringFunction::Replace, n, literal).into_py_any(py)
859
},
860
#[cfg(feature = "string_normalize")]
861
IRStringFunction::Normalize { form } => (
862
PyStringFunction::Normalize,
863
match form {
864
UnicodeForm::NFC => "nfc",
865
UnicodeForm::NFKC => "nfkc",
866
UnicodeForm::NFD => "nfd",
867
UnicodeForm::NFKD => "nfkd",
868
},
869
)
870
.into_py_any(py),
871
IRStringFunction::Reverse => (PyStringFunction::Reverse,).into_py_any(py),
872
IRStringFunction::PadStart { fill_char } => {
873
(PyStringFunction::PadStart, fill_char).into_py_any(py)
874
},
875
IRStringFunction::PadEnd { fill_char } => {
876
(PyStringFunction::PadEnd, fill_char).into_py_any(py)
877
},
878
IRStringFunction::Slice => (PyStringFunction::Slice,).into_py_any(py),
879
IRStringFunction::Head => (PyStringFunction::Head,).into_py_any(py),
880
IRStringFunction::Tail => (PyStringFunction::Tail,).into_py_any(py),
881
IRStringFunction::HexEncode => (PyStringFunction::HexEncode,).into_py_any(py),
882
#[cfg(feature = "binary_encoding")]
883
IRStringFunction::HexDecode(strict) => {
884
(PyStringFunction::HexDecode, strict).into_py_any(py)
885
},
886
IRStringFunction::Base64Encode => {
887
(PyStringFunction::Base64Encode,).into_py_any(py)
888
},
889
#[cfg(feature = "binary_encoding")]
890
IRStringFunction::Base64Decode(strict) => {
891
(PyStringFunction::Base64Decode, strict).into_py_any(py)
892
},
893
IRStringFunction::StartsWith => (PyStringFunction::StartsWith,).into_py_any(py),
894
IRStringFunction::StripChars => (PyStringFunction::StripChars,).into_py_any(py),
895
IRStringFunction::StripCharsStart => {
896
(PyStringFunction::StripCharsStart,).into_py_any(py)
897
},
898
IRStringFunction::StripCharsEnd => {
899
(PyStringFunction::StripCharsEnd,).into_py_any(py)
900
},
901
IRStringFunction::StripPrefix => {
902
(PyStringFunction::StripPrefix,).into_py_any(py)
903
},
904
IRStringFunction::StripSuffix => {
905
(PyStringFunction::StripSuffix,).into_py_any(py)
906
},
907
IRStringFunction::SplitExact { n, inclusive } => {
908
(PyStringFunction::SplitExact, n, inclusive).into_py_any(py)
909
},
910
IRStringFunction::SplitN(n) => (PyStringFunction::SplitN, n).into_py_any(py),
911
IRStringFunction::Strptime(_, options) => (
912
PyStringFunction::Strptime,
913
options.format.as_ref().map(|s| s.as_str()),
914
options.strict,
915
options.exact,
916
options.cache,
917
)
918
.into_py_any(py),
919
IRStringFunction::Split(inclusive) => {
920
(PyStringFunction::Split, inclusive).into_py_any(py)
921
},
922
IRStringFunction::SplitRegex { inclusive, strict } => {
923
(PyStringFunction::SplitRegex, inclusive, strict).into_py_any(py)
924
},
925
IRStringFunction::ToDecimal { scale } => {
926
(PyStringFunction::ToDecimal, scale).into_py_any(py)
927
},
928
#[cfg(feature = "nightly")]
929
IRStringFunction::Titlecase => (PyStringFunction::Titlecase,).into_py_any(py),
930
IRStringFunction::Uppercase => (PyStringFunction::Uppercase,).into_py_any(py),
931
IRStringFunction::ZFill => (PyStringFunction::ZFill,).into_py_any(py),
932
#[cfg(feature = "find_many")]
933
IRStringFunction::ContainsAny {
934
ascii_case_insensitive,
935
} => (PyStringFunction::ContainsAny, ascii_case_insensitive).into_py_any(py),
936
#[cfg(feature = "find_many")]
937
IRStringFunction::ReplaceMany {
938
ascii_case_insensitive,
939
leftmost,
940
} => (
941
PyStringFunction::ReplaceMany,
942
ascii_case_insensitive,
943
leftmost,
944
)
945
.into_py_any(py),
946
#[cfg(feature = "find_many")]
947
IRStringFunction::ExtractMany { .. } => {
948
return Err(PyNotImplementedError::new_err("extract_many"));
949
},
950
#[cfg(feature = "find_many")]
951
IRStringFunction::FindMany { .. } => {
952
return Err(PyNotImplementedError::new_err("find_many"));
953
},
954
#[cfg(feature = "regex")]
955
IRStringFunction::EscapeRegex => {
956
(PyStringFunction::EscapeRegex,).into_py_any(py)
957
},
958
},
959
IRFunctionExpr::StructExpr(fun) => match fun {
960
IRStructFunction::FieldByName(name) => {
961
(PyStructFunction::FieldByName, name.as_str()).into_py_any(py)
962
},
963
IRStructFunction::RenameFields(names) => {
964
(PyStructFunction::RenameFields, names[0].as_str()).into_py_any(py)
965
},
966
IRStructFunction::PrefixFields(prefix) => {
967
(PyStructFunction::PrefixFields, prefix.as_str()).into_py_any(py)
968
},
969
IRStructFunction::SuffixFields(prefix) => {
970
(PyStructFunction::SuffixFields, prefix.as_str()).into_py_any(py)
971
},
972
#[cfg(feature = "json")]
973
IRStructFunction::JsonEncode => (PyStructFunction::JsonEncode,).into_py_any(py),
974
IRStructFunction::MapFieldNames(_) => {
975
return Err(PyNotImplementedError::new_err("map_field_names"));
976
},
977
},
978
IRFunctionExpr::TemporalExpr(fun) => match fun {
979
IRTemporalFunction::Millennium => {
980
(PyTemporalFunction::Millennium,).into_py_any(py)
981
},
982
IRTemporalFunction::Century => (PyTemporalFunction::Century,).into_py_any(py),
983
IRTemporalFunction::Year => (PyTemporalFunction::Year,).into_py_any(py),
984
IRTemporalFunction::IsLeapYear => {
985
(PyTemporalFunction::IsLeapYear,).into_py_any(py)
986
},
987
IRTemporalFunction::IsoYear => (PyTemporalFunction::IsoYear,).into_py_any(py),
988
IRTemporalFunction::Quarter => (PyTemporalFunction::Quarter,).into_py_any(py),
989
IRTemporalFunction::Month => (PyTemporalFunction::Month,).into_py_any(py),
990
IRTemporalFunction::Week => (PyTemporalFunction::Week,).into_py_any(py),
991
IRTemporalFunction::WeekDay => (PyTemporalFunction::WeekDay,).into_py_any(py),
992
IRTemporalFunction::Day => (PyTemporalFunction::Day,).into_py_any(py),
993
IRTemporalFunction::OrdinalDay => {
994
(PyTemporalFunction::OrdinalDay,).into_py_any(py)
995
},
996
IRTemporalFunction::Time => (PyTemporalFunction::Time,).into_py_any(py),
997
IRTemporalFunction::Date => (PyTemporalFunction::Date,).into_py_any(py),
998
IRTemporalFunction::Datetime => (PyTemporalFunction::Datetime,).into_py_any(py),
999
IRTemporalFunction::Duration(time_unit) => {
1000
(PyTemporalFunction::Duration, Wrap(*time_unit)).into_py_any(py)
1001
},
1002
IRTemporalFunction::Hour => (PyTemporalFunction::Hour,).into_py_any(py),
1003
IRTemporalFunction::Minute => (PyTemporalFunction::Minute,).into_py_any(py),
1004
IRTemporalFunction::Second => (PyTemporalFunction::Second,).into_py_any(py),
1005
IRTemporalFunction::Millisecond => {
1006
(PyTemporalFunction::Millisecond,).into_py_any(py)
1007
},
1008
IRTemporalFunction::Microsecond => {
1009
(PyTemporalFunction::Microsecond,).into_py_any(py)
1010
},
1011
IRTemporalFunction::Nanosecond => {
1012
(PyTemporalFunction::Nanosecond,).into_py_any(py)
1013
},
1014
IRTemporalFunction::DaysInMonth => {
1015
(PyTemporalFunction::DaysInMonth,).into_py_any(py)
1016
},
1017
IRTemporalFunction::TotalDays { fractional } => {
1018
(PyTemporalFunction::TotalDays, fractional).into_py_any(py)
1019
},
1020
IRTemporalFunction::TotalHours { fractional } => {
1021
(PyTemporalFunction::TotalHours, fractional).into_py_any(py)
1022
},
1023
IRTemporalFunction::TotalMinutes { fractional } => {
1024
(PyTemporalFunction::TotalMinutes, fractional).into_py_any(py)
1025
},
1026
IRTemporalFunction::TotalSeconds { fractional } => {
1027
(PyTemporalFunction::TotalSeconds, fractional).into_py_any(py)
1028
},
1029
IRTemporalFunction::TotalMilliseconds { fractional } => {
1030
(PyTemporalFunction::TotalMilliseconds, fractional).into_py_any(py)
1031
},
1032
IRTemporalFunction::TotalMicroseconds { fractional } => {
1033
(PyTemporalFunction::TotalMicroseconds, fractional).into_py_any(py)
1034
},
1035
IRTemporalFunction::TotalNanoseconds { fractional } => {
1036
(PyTemporalFunction::TotalNanoseconds, fractional).into_py_any(py)
1037
},
1038
IRTemporalFunction::ToString(format) => {
1039
(PyTemporalFunction::ToString, format).into_py_any(py)
1040
},
1041
IRTemporalFunction::CastTimeUnit(time_unit) => {
1042
(PyTemporalFunction::CastTimeUnit, Wrap(*time_unit)).into_py_any(py)
1043
},
1044
IRTemporalFunction::WithTimeUnit(time_unit) => {
1045
(PyTemporalFunction::WithTimeUnit, Wrap(*time_unit)).into_py_any(py)
1046
},
1047
#[cfg(feature = "timezones")]
1048
IRTemporalFunction::ConvertTimeZone(time_zone) => {
1049
(PyTemporalFunction::ConvertTimeZone, time_zone.as_str()).into_py_any(py)
1050
},
1051
IRTemporalFunction::TimeStamp(time_unit) => {
1052
(PyTemporalFunction::TimeStamp, Wrap(*time_unit)).into_py_any(py)
1053
},
1054
IRTemporalFunction::Truncate => (PyTemporalFunction::Truncate,).into_py_any(py),
1055
IRTemporalFunction::OffsetBy => (PyTemporalFunction::OffsetBy,).into_py_any(py),
1056
IRTemporalFunction::MonthStart => {
1057
(PyTemporalFunction::MonthStart,).into_py_any(py)
1058
},
1059
IRTemporalFunction::MonthEnd => (PyTemporalFunction::MonthEnd,).into_py_any(py),
1060
#[cfg(feature = "timezones")]
1061
IRTemporalFunction::BaseUtcOffset => {
1062
(PyTemporalFunction::BaseUtcOffset,).into_py_any(py)
1063
},
1064
#[cfg(feature = "timezones")]
1065
IRTemporalFunction::DSTOffset => {
1066
(PyTemporalFunction::DSTOffset,).into_py_any(py)
1067
},
1068
IRTemporalFunction::Round => (PyTemporalFunction::Round,).into_py_any(py),
1069
IRTemporalFunction::Replace => (PyTemporalFunction::Replace).into_py_any(py),
1070
#[cfg(feature = "timezones")]
1071
IRTemporalFunction::ReplaceTimeZone(time_zone, non_existent) => (
1072
PyTemporalFunction::ReplaceTimeZone,
1073
time_zone.as_ref().map(|s| s.as_str()),
1074
Into::<&str>::into(non_existent),
1075
)
1076
.into_py_any(py),
1077
IRTemporalFunction::Combine(time_unit) => {
1078
(PyTemporalFunction::Combine, Wrap(*time_unit)).into_py_any(py)
1079
},
1080
IRTemporalFunction::DatetimeFunction {
1081
time_unit,
1082
time_zone,
1083
} => (
1084
PyTemporalFunction::DatetimeFunction,
1085
Wrap(*time_unit),
1086
time_zone.as_ref().map(|s| s.as_str()),
1087
)
1088
.into_py_any(py),
1089
},
1090
IRFunctionExpr::Boolean(boolfun) => match boolfun {
1091
IRBooleanFunction::Any { ignore_nulls } => {
1092
(PyBooleanFunction::Any, *ignore_nulls).into_py_any(py)
1093
},
1094
IRBooleanFunction::All { ignore_nulls } => {
1095
(PyBooleanFunction::All, *ignore_nulls).into_py_any(py)
1096
},
1097
IRBooleanFunction::IsNull => (PyBooleanFunction::IsNull,).into_py_any(py),
1098
IRBooleanFunction::IsNotNull => (PyBooleanFunction::IsNotNull,).into_py_any(py),
1099
IRBooleanFunction::IsFinite => (PyBooleanFunction::IsFinite,).into_py_any(py),
1100
IRBooleanFunction::IsInfinite => {
1101
(PyBooleanFunction::IsInfinite,).into_py_any(py)
1102
},
1103
IRBooleanFunction::IsNan => (PyBooleanFunction::IsNan,).into_py_any(py),
1104
IRBooleanFunction::IsNotNan => (PyBooleanFunction::IsNotNan,).into_py_any(py),
1105
IRBooleanFunction::IsFirstDistinct => {
1106
(PyBooleanFunction::IsFirstDistinct,).into_py_any(py)
1107
},
1108
IRBooleanFunction::IsLastDistinct => {
1109
(PyBooleanFunction::IsLastDistinct,).into_py_any(py)
1110
},
1111
IRBooleanFunction::IsUnique => (PyBooleanFunction::IsUnique,).into_py_any(py),
1112
IRBooleanFunction::IsDuplicated => {
1113
(PyBooleanFunction::IsDuplicated,).into_py_any(py)
1114
},
1115
IRBooleanFunction::IsBetween { closed } => {
1116
(PyBooleanFunction::IsBetween, Into::<&str>::into(closed)).into_py_any(py)
1117
},
1118
#[cfg(feature = "is_in")]
1119
IRBooleanFunction::IsIn { nulls_equal } => {
1120
(PyBooleanFunction::IsIn, nulls_equal).into_py_any(py)
1121
},
1122
IRBooleanFunction::IsClose {
1123
abs_tol,
1124
rel_tol,
1125
nans_equal,
1126
} => (PyBooleanFunction::IsClose, abs_tol.0, rel_tol.0, nans_equal)
1127
.into_py_any(py),
1128
IRBooleanFunction::AllHorizontal => {
1129
(PyBooleanFunction::AllHorizontal,).into_py_any(py)
1130
},
1131
IRBooleanFunction::AnyHorizontal => {
1132
(PyBooleanFunction::AnyHorizontal,).into_py_any(py)
1133
},
1134
IRBooleanFunction::Not => (PyBooleanFunction::Not,).into_py_any(py),
1135
},
1136
IRFunctionExpr::Abs => ("abs",).into_py_any(py),
1137
#[cfg(feature = "hist")]
1138
IRFunctionExpr::Hist {
1139
bin_count,
1140
include_category,
1141
include_breakpoint,
1142
} => ("hist", bin_count, include_category, include_breakpoint).into_py_any(py),
1143
IRFunctionExpr::NullCount => ("null_count",).into_py_any(py),
1144
IRFunctionExpr::Pow(f) => match f {
1145
IRPowFunction::Generic => ("pow",).into_py_any(py),
1146
IRPowFunction::Sqrt => ("sqrt",).into_py_any(py),
1147
IRPowFunction::Cbrt => ("cbrt",).into_py_any(py),
1148
},
1149
IRFunctionExpr::Hash(seed, seed_1, seed_2, seed_3) => {
1150
("hash", seed, seed_1, seed_2, seed_3).into_py_any(py)
1151
},
1152
IRFunctionExpr::ArgWhere => ("argwhere",).into_py_any(py),
1153
#[cfg(feature = "index_of")]
1154
IRFunctionExpr::IndexOf => ("index_of",).into_py_any(py),
1155
#[cfg(feature = "search_sorted")]
1156
IRFunctionExpr::SearchSorted { side, descending } => (
1157
"search_sorted",
1158
match side {
1159
SearchSortedSide::Any => "any",
1160
SearchSortedSide::Left => "left",
1161
SearchSortedSide::Right => "right",
1162
},
1163
descending,
1164
)
1165
.into_py_any(py),
1166
IRFunctionExpr::Range(_) => return Err(PyNotImplementedError::new_err("range")),
1167
#[cfg(feature = "trigonometry")]
1168
IRFunctionExpr::Trigonometry(trigfun) => {
1169
use polars_plan::plans::IRTrigonometricFunction;
1170
1171
match trigfun {
1172
IRTrigonometricFunction::Cos => ("cos",),
1173
IRTrigonometricFunction::Cot => ("cot",),
1174
IRTrigonometricFunction::Sin => ("sin",),
1175
IRTrigonometricFunction::Tan => ("tan",),
1176
IRTrigonometricFunction::ArcCos => ("arccos",),
1177
IRTrigonometricFunction::ArcSin => ("arcsin",),
1178
IRTrigonometricFunction::ArcTan => ("arctan",),
1179
IRTrigonometricFunction::Cosh => ("cosh",),
1180
IRTrigonometricFunction::Sinh => ("sinh",),
1181
IRTrigonometricFunction::Tanh => ("tanh",),
1182
IRTrigonometricFunction::ArcCosh => ("arccosh",),
1183
IRTrigonometricFunction::ArcSinh => ("arcsinh",),
1184
IRTrigonometricFunction::ArcTanh => ("arctanh",),
1185
IRTrigonometricFunction::Degrees => ("degrees",),
1186
IRTrigonometricFunction::Radians => ("radians",),
1187
}
1188
.into_py_any(py)
1189
},
1190
#[cfg(feature = "trigonometry")]
1191
IRFunctionExpr::Atan2 => ("atan2",).into_py_any(py),
1192
#[cfg(feature = "sign")]
1193
IRFunctionExpr::Sign => ("sign",).into_py_any(py),
1194
IRFunctionExpr::FillNull => ("fill_null",).into_py_any(py),
1195
IRFunctionExpr::RollingExpr { function, .. } => {
1196
return Err(PyNotImplementedError::new_err(format!("{function}")));
1197
},
1198
IRFunctionExpr::RollingExprBy { function_by, .. } => match function_by {
1199
IRRollingFunctionBy::MinBy => {
1200
return Err(PyNotImplementedError::new_err("rolling min by"));
1201
},
1202
IRRollingFunctionBy::MaxBy => {
1203
return Err(PyNotImplementedError::new_err("rolling max by"));
1204
},
1205
IRRollingFunctionBy::MeanBy => {
1206
return Err(PyNotImplementedError::new_err("rolling mean by"));
1207
},
1208
IRRollingFunctionBy::SumBy => {
1209
return Err(PyNotImplementedError::new_err("rolling sum by"));
1210
},
1211
IRRollingFunctionBy::QuantileBy => {
1212
return Err(PyNotImplementedError::new_err("rolling quantile by"));
1213
},
1214
IRRollingFunctionBy::VarBy => {
1215
return Err(PyNotImplementedError::new_err("rolling var by"));
1216
},
1217
IRRollingFunctionBy::StdBy => {
1218
return Err(PyNotImplementedError::new_err("rolling std by"));
1219
},
1220
IRRollingFunctionBy::RankBy => {
1221
return Err(PyNotImplementedError::new_err("rolling rank by"));
1222
},
1223
},
1224
IRFunctionExpr::Rechunk => ("rechunk",).into_py_any(py),
1225
IRFunctionExpr::Append { upcast } => ("append", upcast).into_py_any(py),
1226
IRFunctionExpr::ShiftAndFill => ("shift_and_fill",).into_py_any(py),
1227
IRFunctionExpr::Shift => ("shift",).into_py_any(py),
1228
IRFunctionExpr::DropNans => ("drop_nans",).into_py_any(py),
1229
IRFunctionExpr::DropNulls => ("drop_nulls",).into_py_any(py),
1230
IRFunctionExpr::Mode { maintain_order } => {
1231
("mode", *maintain_order).into_py_any(py)
1232
},
1233
IRFunctionExpr::Skew(bias) => ("skew", bias).into_py_any(py),
1234
IRFunctionExpr::Kurtosis(fisher, bias) => {
1235
("kurtosis", fisher, bias).into_py_any(py)
1236
},
1237
IRFunctionExpr::Reshape(_) => {
1238
return Err(PyNotImplementedError::new_err("reshape"));
1239
},
1240
#[cfg(feature = "repeat_by")]
1241
IRFunctionExpr::RepeatBy => ("repeat_by",).into_py_any(py),
1242
IRFunctionExpr::ArgUnique => ("arg_unique",).into_py_any(py),
1243
IRFunctionExpr::ArgMin => ("arg_min",).into_py_any(py),
1244
IRFunctionExpr::ArgMax => ("arg_max",).into_py_any(py),
1245
IRFunctionExpr::MinBy => ("min_by",).into_py_any(py),
1246
IRFunctionExpr::MaxBy => ("max_by",).into_py_any(py),
1247
IRFunctionExpr::ArgSort {
1248
descending,
1249
nulls_last,
1250
} => ("arg_max", descending, nulls_last).into_py_any(py),
1251
IRFunctionExpr::Product => ("product",).into_py_any(py),
1252
IRFunctionExpr::Repeat => ("repeat",).into_py_any(py),
1253
IRFunctionExpr::Rank { options, seed } => {
1254
let method = match options.method {
1255
RankMethod::Average => "average",
1256
RankMethod::Min => "min",
1257
RankMethod::Max => "max",
1258
RankMethod::Dense => "dense",
1259
RankMethod::Ordinal => "ordinal",
1260
RankMethod::Random => "random",
1261
};
1262
("rank", method, options.descending, seed.map(|s| s as i64)).into_py_any(py)
1263
},
1264
IRFunctionExpr::Clip { has_min, has_max } => {
1265
("clip", has_min, has_max).into_py_any(py)
1266
},
1267
IRFunctionExpr::AsStruct => ("as_struct",).into_py_any(py),
1268
#[cfg(feature = "top_k")]
1269
IRFunctionExpr::TopK { descending } => ("top_k", descending).into_py_any(py),
1270
IRFunctionExpr::CumCount { reverse } => ("cum_count", reverse).into_py_any(py),
1271
IRFunctionExpr::CumSum { reverse } => ("cum_sum", reverse).into_py_any(py),
1272
IRFunctionExpr::CumProd { reverse } => ("cum_prod", reverse).into_py_any(py),
1273
IRFunctionExpr::CumMin { reverse } => ("cum_min", reverse).into_py_any(py),
1274
IRFunctionExpr::CumMax { reverse } => ("cum_max", reverse).into_py_any(py),
1275
IRFunctionExpr::Reverse => ("reverse",).into_py_any(py),
1276
IRFunctionExpr::ValueCounts {
1277
sort,
1278
parallel,
1279
name,
1280
normalize,
1281
} => ("value_counts", sort, parallel, name.as_str(), normalize).into_py_any(py),
1282
IRFunctionExpr::UniqueCounts => ("unique_counts",).into_py_any(py),
1283
IRFunctionExpr::ApproxNUnique => ("approx_n_unique",).into_py_any(py),
1284
IRFunctionExpr::Coalesce => ("coalesce",).into_py_any(py),
1285
IRFunctionExpr::Diff(null_behaviour) => (
1286
"diff",
1287
match null_behaviour {
1288
NullBehavior::Drop => "drop",
1289
NullBehavior::Ignore => "ignore",
1290
},
1291
)
1292
.into_py_any(py),
1293
#[cfg(feature = "pct_change")]
1294
IRFunctionExpr::PctChange => ("pct_change",).into_py_any(py),
1295
IRFunctionExpr::Interpolate(method) => (
1296
"interpolate",
1297
match method {
1298
InterpolationMethod::Linear => "linear",
1299
InterpolationMethod::Nearest => "nearest",
1300
},
1301
)
1302
.into_py_any(py),
1303
IRFunctionExpr::InterpolateBy => ("interpolate_by",).into_py_any(py),
1304
IRFunctionExpr::Entropy { base, normalize } => {
1305
("entropy", base, normalize).into_py_any(py)
1306
},
1307
IRFunctionExpr::Log => ("log",).into_py_any(py),
1308
IRFunctionExpr::Log1p => ("log1p",).into_py_any(py),
1309
IRFunctionExpr::Exp => ("exp",).into_py_any(py),
1310
IRFunctionExpr::Unique(maintain_order) => {
1311
("unique", maintain_order).into_py_any(py)
1312
},
1313
IRFunctionExpr::Round { decimals, mode } => {
1314
("round", decimals, Into::<&str>::into(mode)).into_py_any(py)
1315
},
1316
IRFunctionExpr::RoundSF { digits } => ("round_sig_figs", digits).into_py_any(py),
1317
IRFunctionExpr::Floor => ("floor",).into_py_any(py),
1318
IRFunctionExpr::Ceil => ("ceil",).into_py_any(py),
1319
IRFunctionExpr::Fused(_) => return Err(PyNotImplementedError::new_err("fused")),
1320
IRFunctionExpr::ConcatExpr(_) => {
1321
return Err(PyNotImplementedError::new_err("concat expr"));
1322
},
1323
IRFunctionExpr::Correlation { .. } => {
1324
return Err(PyNotImplementedError::new_err("corr"));
1325
},
1326
#[cfg(feature = "peaks")]
1327
IRFunctionExpr::PeakMin => ("peak_max",).into_py_any(py),
1328
#[cfg(feature = "peaks")]
1329
IRFunctionExpr::PeakMax => ("peak_min",).into_py_any(py),
1330
#[cfg(feature = "cutqcut")]
1331
IRFunctionExpr::Cut { .. } => return Err(PyNotImplementedError::new_err("cut")),
1332
#[cfg(feature = "cutqcut")]
1333
IRFunctionExpr::QCut { .. } => return Err(PyNotImplementedError::new_err("qcut")),
1334
#[cfg(feature = "rle")]
1335
IRFunctionExpr::RLE => ("rle",).into_py_any(py),
1336
#[cfg(feature = "rle")]
1337
IRFunctionExpr::RLEID => ("rle_id",).into_py_any(py),
1338
IRFunctionExpr::ToPhysical => ("to_physical",).into_py_any(py),
1339
IRFunctionExpr::Random { .. } => {
1340
return Err(PyNotImplementedError::new_err("random"));
1341
},
1342
IRFunctionExpr::SetSortedFlag(sorted) => (
1343
"set_sorted",
1344
match sorted {
1345
IsSorted::Ascending => "ascending",
1346
IsSorted::Descending => "descending",
1347
IsSorted::Not => "not",
1348
},
1349
)
1350
.into_py_any(py),
1351
#[cfg(feature = "ffi_plugin")]
1352
IRFunctionExpr::FfiPlugin { .. } => {
1353
return Err(PyNotImplementedError::new_err("ffi plugin"));
1354
},
1355
IRFunctionExpr::FoldHorizontal { .. } => {
1356
Err(PyNotImplementedError::new_err("fold"))
1357
},
1358
IRFunctionExpr::ReduceHorizontal { .. } => {
1359
Err(PyNotImplementedError::new_err("reduce"))
1360
},
1361
IRFunctionExpr::CumReduceHorizontal { .. } => {
1362
Err(PyNotImplementedError::new_err("cum_reduce"))
1363
},
1364
IRFunctionExpr::CumFoldHorizontal { .. } => {
1365
Err(PyNotImplementedError::new_err("cum_fold"))
1366
},
1367
IRFunctionExpr::SumHorizontal { ignore_nulls } => {
1368
("sum_horizontal", ignore_nulls).into_py_any(py)
1369
},
1370
IRFunctionExpr::MaxHorizontal => ("max_horizontal",).into_py_any(py),
1371
IRFunctionExpr::MeanHorizontal { ignore_nulls } => {
1372
("mean_horizontal", ignore_nulls).into_py_any(py)
1373
},
1374
IRFunctionExpr::MinHorizontal => ("min_horizontal",).into_py_any(py),
1375
IRFunctionExpr::EwmMean { options: _ } => {
1376
return Err(PyNotImplementedError::new_err("ewm mean"));
1377
},
1378
IRFunctionExpr::EwmStd { options: _ } => {
1379
return Err(PyNotImplementedError::new_err("ewm std"));
1380
},
1381
IRFunctionExpr::EwmVar { options: _ } => {
1382
return Err(PyNotImplementedError::new_err("ewm var"));
1383
},
1384
IRFunctionExpr::Replace => ("replace",).into_py_any(py),
1385
IRFunctionExpr::ReplaceStrict { return_dtype: _ } => {
1386
// Can ignore the return dtype because it is encoded in the schema.
1387
("replace_strict",).into_py_any(py)
1388
},
1389
IRFunctionExpr::Negate => ("negate",).into_py_any(py),
1390
IRFunctionExpr::FillNullWithStrategy(strategy) => {
1391
let (strategy_str, py_limit): (&str, Py<PyAny>) = match strategy {
1392
FillNullStrategy::Forward(limit) => {
1393
let py_limit = limit
1394
.map(|v| PyInt::new(py, v).into())
1395
.unwrap_or_else(|| py.None());
1396
("forward", py_limit)
1397
},
1398
FillNullStrategy::Backward(limit) => {
1399
let py_limit = limit
1400
.map(|v| PyInt::new(py, v).into())
1401
.unwrap_or_else(|| py.None());
1402
("backward", py_limit)
1403
},
1404
FillNullStrategy::Min => ("min", py.None()),
1405
FillNullStrategy::Max => ("max", py.None()),
1406
FillNullStrategy::Mean => ("mean", py.None()),
1407
FillNullStrategy::Zero => ("zero", py.None()),
1408
FillNullStrategy::One => ("one", py.None()),
1409
};
1410
1411
("fill_null_with_strategy", strategy_str, py_limit).into_py_any(py)
1412
},
1413
IRFunctionExpr::GatherEvery { n, offset } => {
1414
("gather_every", offset, n).into_py_any(py)
1415
},
1416
IRFunctionExpr::Reinterpret(signed) => ("reinterpret", signed).into_py_any(py),
1417
IRFunctionExpr::ExtendConstant => ("extend_constant",).into_py_any(py),
1418
IRFunctionExpr::Business(_) => {
1419
return Err(PyNotImplementedError::new_err("business"));
1420
},
1421
#[cfg(feature = "top_k")]
1422
IRFunctionExpr::TopKBy { descending } => ("top_k_by", descending).into_py_any(py),
1423
IRFunctionExpr::EwmMeanBy { half_life: _ } => {
1424
return Err(PyNotImplementedError::new_err("ewm_mean_by"));
1425
},
1426
IRFunctionExpr::RowEncode(..) => {
1427
return Err(PyNotImplementedError::new_err("row_encode"));
1428
},
1429
IRFunctionExpr::RowDecode(..) => {
1430
return Err(PyNotImplementedError::new_err("row_decode"));
1431
},
1432
}?,
1433
options: py.None(),
1434
}
1435
.into_py_any(py),
1436
AExpr::Rolling { .. } => Err(PyNotImplementedError::new_err("rolling")),
1437
AExpr::Over {
1438
function,
1439
partition_by,
1440
order_by,
1441
mapping,
1442
} => {
1443
let function = function.0;
1444
let partition_by = partition_by.iter().map(|n| n.0).collect();
1445
let order_by_descending = order_by
1446
.map(|(_, options)| options.descending)
1447
.unwrap_or(false);
1448
let order_by_nulls_last = order_by
1449
.map(|(_, options)| options.nulls_last)
1450
.unwrap_or(false);
1451
let order_by = order_by.map(|(n, _)| n.0);
1452
1453
let options = PyWindowMapping { inner: *mapping }.into_py_any(py)?;
1454
Window {
1455
function,
1456
partition_by,
1457
order_by,
1458
order_by_descending,
1459
order_by_nulls_last,
1460
options,
1461
}
1462
.into_py_any(py)
1463
},
1464
AExpr::Slice {
1465
input,
1466
offset,
1467
length,
1468
} => Slice {
1469
input: input.0,
1470
offset: offset.0,
1471
length: length.0,
1472
}
1473
.into_py_any(py),
1474
AExpr::Len => Len {}.into_py_any(py),
1475
AExpr::Eval { .. } => Err(PyNotImplementedError::new_err("list.eval")),
1476
AExpr::StructEval { .. } => Err(PyNotImplementedError::new_err("struct.with_fields")),
1477
}
1478
}
1479
1480