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