Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
30e1eb6
Refactor IsNullOp and NotNullOp logic
google-labs-jules[bot] Jun 13, 2025
92870fd
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Jul 8, 2025
1b711aa
fix circular imports
tswast Jul 8, 2025
7ede976
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Jul 8, 2025
9c17725
bad merge
tswast Jul 8, 2025
78e4585
fix local pytest
tswast Jul 8, 2025
333f9e2
Merge branch 'main' into refactor-isnull-op
tswast Jul 8, 2025
53e0a3e
dont construct polars compiler if no polars
tswast Jul 8, 2025
65e9fd4
Merge remote-tracking branch 'origin/refactor-isnull-op' into refacto…
tswast Jul 8, 2025
360edb3
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Jul 14, 2025
9cd1fde
limit scope to just splitting large files
tswast Jul 14, 2025
ec47c37
Update bigframes/core/compile/compiled.py
tswast Jul 15, 2025
a475b72
Merge branch 'main' into refactor-isnull-op
tswast Jul 15, 2025
5990732
Merge branch 'main' into refactor-isnull-op
tswast Jul 16, 2025
8adafdd
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Aug 5, 2025
b1cf81c
revert unneeded circular import workaround
tswast Aug 5, 2025
57c1c98
Merge branch 'main' into refactor-isnull-op
tswast Aug 5, 2025
de5a12c
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Aug 6, 2025
87fd788
combine null ops into generic_ops files
tswast Aug 6, 2025
6372a23
revert expression change
tswast Aug 6, 2025
ef06d65
Update bigframes/core/compile/polars/operations/__init__.py
tswast Aug 6, 2025
7c19d8b
skip polars test for old polars
tswast Aug 6, 2025
3d50dae
Merge remote-tracking branch 'origin/refactor-isnull-op' into refacto…
tswast Aug 6, 2025
7babc87
Update bigframes/core/compile/ibis_compiler/operations/__init__.py
tswast Aug 6, 2025
aa5c47d
add minversion to skips
tswast Aug 6, 2025
b56cbbd
Merge remote-tracking branch 'origin/refactor-isnull-op' into refacto…
tswast Aug 6, 2025
0c9802d
more skips
tswast Aug 6, 2025
a9152ba
Merge remote-tracking branch 'origin/main' into refactor-isnull-op
tswast Aug 6, 2025
c2f1ca8
fix minimum polars version detection
tswast Aug 6, 2025
863b8ed
update colab constraints
tswast Aug 6, 2025
f42800e
skip polars on 3.10
tswast Aug 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions bigframes/core/compile/polars/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,6 @@ def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
else:
return input.is_in(op.values) or input.is_null()

@compile_op.register(gen_ops.IsNullOp)
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
return input.is_null()

@compile_op.register(gen_ops.NotNullOp)
def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
return input.is_not_null()

@compile_op.register(gen_ops.FillNaOp)
@compile_op.register(gen_ops.CoalesceOp)
def _(self, op: ops.ScalarOp, l_input: pl.Expr, r_input: pl.Expr) -> pl.Expr:
Expand Down Expand Up @@ -268,6 +260,16 @@ def _(self, op: ops.ScalarOp, input: pl.Expr) -> pl.Expr:
# eg. We want "True" instead of "true" for bool to strin
return input.cast(_DTYPE_MAPPING[op.to_type], strict=not op.safe)

# Register ops from other modules
from bigframes.operations import IsNullOp, NotNullOp
from bigframes.operations.isnull_op import (
_polars_isnull_op_impl,
_polars_notnull_op_impl,
)

PolarsExpressionCompiler.compile_op.register(IsNullOp, _polars_isnull_op_impl)
PolarsExpressionCompiler.compile_op.register(NotNullOp, _polars_notnull_op_impl)

Comment thread
tswast marked this conversation as resolved.
Outdated
@dataclasses.dataclass(frozen=True)
class PolarsAggregateCompiler:
scalar_compiler = PolarsExpressionCompiler()
Expand Down
21 changes: 13 additions & 8 deletions bigframes/core/compile/scalar_op_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,18 +228,23 @@ def _register(
# Singleton compiler
scalar_op_compiler = ScalarOpCompiler()

# Registrations for operations defined in isnull_op.py
from bigframes.operations import isnull_op, notnull_op
from bigframes.operations.isnull_op import (
_ibis_isnull_op_impl,
_ibis_notnull_op_impl,
)

### Unary Ops
@scalar_op_compiler.register_unary_op(ops.isnull_op)
def isnull_op_impl(x: ibis_types.Value):
return x.isnull()

@scalar_op_compiler.register_unary_op(isnull_op)
def _scalar_isnull_op_impl_wrapper(x: ibis_types.Value):
return _ibis_isnull_op_impl(x)

@scalar_op_compiler.register_unary_op(ops.notnull_op)
def notnull_op_impl(x: ibis_types.Value):
return x.notnull()
@scalar_op_compiler.register_unary_op(notnull_op)
def _scalar_notnull_op_impl_wrapper(x: ibis_types.Value):
return _ibis_notnull_op_impl(x)
Comment thread
tswast marked this conversation as resolved.
Outdated


### Unary Ops
@scalar_op_compiler.register_unary_op(ops.hash_op)
def hash_op_impl(x: ibis_types.Value):
return typing.cast(ibis_types.IntegerValue, x).hash()
Expand Down
1 change: 1 addition & 0 deletions bigframes/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2521,6 +2521,7 @@ def _filter_rows(
elif items is not None:
# Behavior matches pandas 2.1+, older pandas versions would reindex
block = self._block
block = self._block
Comment thread
tswast marked this conversation as resolved.
Outdated
block, mask_id = block.apply_unary_op(
self._block.index_columns[0], ops.IsInOp(values=tuple(items))
)
Expand Down
3 changes: 1 addition & 2 deletions bigframes/operations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,9 @@
hash_op,
invert_op,
IsInOp,
isnull_op,
MapOp,
maximum_op,
minimum_op,
notnull_op,
RowKey,
SqlScalarOp,
where_op,
Expand All @@ -104,6 +102,7 @@
GeoStDistanceOp,
GeoStLengthOp,
)
from bigframes.operations.isnull_op import isnull_op, notnull_op
from bigframes.operations.json_ops import (
JSONExtract,
JSONExtractArray,
Expand Down
16 changes: 0 additions & 16 deletions bigframes/operations/generic_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,6 @@
)
invert_op = InvertOp()

IsNullOp = base_ops.create_unary_op(
name="isnull",
type_signature=op_typing.FixedOutputType(
lambda x: True, dtypes.BOOL_DTYPE, description="nullable"
),
)
isnull_op = IsNullOp()

NotNullOp = base_ops.create_unary_op(
name="notnull",
type_signature=op_typing.FixedOutputType(
lambda x: True, dtypes.BOOL_DTYPE, description="nullable"
),
)
notnull_op = NotNullOp()

HashOp = base_ops.create_unary_op(
name="hash",
type_signature=op_typing.FixedOutputType(
Expand Down
76 changes: 76 additions & 0 deletions bigframes/operations/isnull_op.py
Comment thread
tswast marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

import typing

# Direct imports from bigframes
from bigframes import dtypes
from bigframes.operations import base_ops
import bigframes.operations.type as op_typing

# Imports for Ibis compilation
from bigframes_vendored.ibis.expr import types as ibis_types

# Imports for Polars compilation
try:
import polars as pl
except ImportError:
# Polars is optional, error will be raised elsewhere if user tries to use it.
pass


# Definitions of IsNullOp and NotNullOp operations
IsNullOp = base_ops.create_unary_op(
name="isnull",
type_signature=op_typing.FixedOutputType(
lambda x: True, dtypes.BOOL_DTYPE, description="nullable"
),
)
isnull_op = IsNullOp()

NotNullOp = base_ops.create_unary_op(
name="notnull",
type_signature=op_typing.FixedOutputType(
lambda x: True, dtypes.BOOL_DTYPE, description="nullable"
),
)
notnull_op = NotNullOp()

# Ibis Scalar Op Implementations
def _ibis_isnull_op_impl(x: ibis_types.Value):
return x.isnull()

def _ibis_notnull_op_impl(x: ibis_types.Value):
return x.notnull()


# Polars Expression Implementations
def _polars_isnull_op_impl(op: IsNullOp, input: pl.Expr) -> pl.Expr:
return input.is_null()

def _polars_notnull_op_impl(op: NotNullOp, input: pl.Expr) -> pl.Expr:
return input.is_not_null()

__all__ = [
"IsNullOp",
"isnull_op",
"NotNullOp",
"notnull_op",
"_ibis_isnull_op_impl",
"_ibis_notnull_op_impl",
"_polars_isnull_op_impl",
"_polars_notnull_op_impl",
]
Loading