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