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