Repository: pola-rs/polars
File: crates/polars-mem-engine/src/planner/lp.rs (Rust)

Code before:
    })
}

#[cfg(feature = "python")]
#[allow(clippy::type_complexity)]
pub fn python_scan_predicate(
    options: &mut PythonOptions,
    expr_arena: &mut Arena<AExpr>,
    state: &mut ExpressionConversionState,
) -> PolarsResult<(
    Option<Arc<dyn polars_expr::prelude::PhysicalExpr>>,
    Option<Vec<u8>>,
)> {
    let mut predicate_serialized = None;
    let predicate = if let PythonPredicate::Polars(e) = &options.predicate {
        // Clone the expression so we can release the borrow on `options`
        // before mutating `options.predicate` below.
        let e = e.clone();

        // Convert to a pyarrow eval string.
        if matches!(options.python_source, PythonScanSource::Pyarrow) {
            use polars_core::config::verbose_print_sensitive;
            use polars_plan::plans::MintermIter;

            // Split into AND-minterms and convert each independently.
            let n_minterms = MintermIter::new(e.node(), expr_arena).count();
            let parts: Vec<String> = MintermIter::new(e.node(), expr_arena)
                .filter_map(|node| {
                    polars_plan::plans::python::pyarrow::predicate_to_pa(
                        node,
                        expr_arena,
                        Default::default(),
                    )
                })
                .collect();
            let fully_converted = parts.len() == n_minterms;

            let predicate_pa = match parts.len() {
                0 => None,
                1 => Some(parts.into_iter().next().unwrap()),
                _ => Some(format!("({})", parts.join(" & "))),
            };

            verbose_print_sensitive(|| {
                format!(
                    "python_scan_predicate: \
                    predicate node: {}, \
                    converted pyarrow predicate: {}",
                    ExprIRDisplay::display_node(e.node(), expr_arena),
                    predicate_pa.as_deref().unwrap_or("<conversion failed>")
                )

Review comment (bug):
Rather than an additional traversal, just have a `mut fully_converted: bool` flag and set it to `false` if we see a predicate conversion failure


Code after:
    })
}

#[cfg(feature = "python")]
#[allow(clippy::type_complexity)]
pub fn python_scan_predicate(
    options: &mut PythonOptions,
    expr_arena: &mut Arena<AExpr>,
    state: &mut ExpressionConversionState,
) -> PolarsResult<(
    Option<Arc<dyn polars_expr::prelude::PhysicalExpr>>,
    Option<Vec<u8>>,
)> {
    let mut predicate_serialized = None;
    let predicate = if let PythonPredicate::Polars(e) = &options.predicate {
        // Clone the expression so we can release the borrow on `options`
        // before mutating `options.predicate` below.
        let e = e.clone();

        // Convert to a pyarrow eval string.
        if matches!(options.python_source, PythonScanSource::Pyarrow) {
            use polars_core::config::verbose_print_sensitive;
            use polars_plan::plans::MintermIter;

            // Split into AND-minterms and convert each independently.
            let mut residual_predicate_nodes: Vec<Node> = vec![];
            let parts: Vec<String> = MintermIter::new(e.node(), expr_arena)
                .filter_map(|node| {
                    let result = polars_plan::plans::python::pyarrow::predicate_to_pa(
                        node,
                        expr_arena,
                        Default::default(),
                    );
                    if result.is_none() {
                        residual_predicate_nodes.push(node);
                    }
                    result
                })
                .collect();

            let predicate_pa = match parts.len() {
                0 => None,
                1 => Some(parts.into_iter().next().unwrap()),
                _ => Some(format!("({})", parts.join(" & "))),
            };

            let residual_predicate_expr_ir = if let Some(eval_str) = predicate_pa {
                options.predicate = PythonPredicate::PyArrow(eval_str);

                residual_predicate_nodes
                    .into_iter()