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