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