Skip to content

Commit b7a66df

Browse files
Merge branch 'main' into fix_solo_if_else
2 parents 65efa9b + 8fc098a commit b7a66df

File tree

15 files changed

+217
-24
lines changed

15 files changed

+217
-24
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@
44

55
[1]: https://pypi.org/project/bigframes/#history
66

7+
## [2.22.0](https://github.com/googleapis/python-bigquery-dataframes/compare/v2.21.0...v2.22.0) (2025-09-25)
8+
9+
10+
### Features
11+
12+
* Add `GroupBy.__iter__` ([#1394](https://github.com/googleapis/python-bigquery-dataframes/issues/1394)) ([c56a78c](https://github.com/googleapis/python-bigquery-dataframes/commit/c56a78cd509a535d4998d5b9a99ec3ecd334b883))
13+
* Add ai.generate_int to bigframes.bigquery package ([#2109](https://github.com/googleapis/python-bigquery-dataframes/issues/2109)) ([af6b862](https://github.com/googleapis/python-bigquery-dataframes/commit/af6b862de5c3921684210ec169338815f45b19dd))
14+
* Add Groupby.describe() ([#2088](https://github.com/googleapis/python-bigquery-dataframes/issues/2088)) ([328a765](https://github.com/googleapis/python-bigquery-dataframes/commit/328a765e746138806a021bea22475e8c03512aeb))
15+
* Implement `Index.to_list()` ([#2106](https://github.com/googleapis/python-bigquery-dataframes/issues/2106)) ([60056ca](https://github.com/googleapis/python-bigquery-dataframes/commit/60056ca06511f99092647fe55fc02eeab486b4ca))
16+
* Implement inplace parameter for `DataFrame.drop` ([#2105](https://github.com/googleapis/python-bigquery-dataframes/issues/2105)) ([3487f13](https://github.com/googleapis/python-bigquery-dataframes/commit/3487f13d12e34999b385c2e11551b5e27bfbf4ff))
17+
* Support callable for series map method ([#2100](https://github.com/googleapis/python-bigquery-dataframes/issues/2100)) ([ac25618](https://github.com/googleapis/python-bigquery-dataframes/commit/ac25618feed2da11fe4fb85058d498d262c085c0))
18+
* Support df.info() with null index ([#2094](https://github.com/googleapis/python-bigquery-dataframes/issues/2094)) ([fb81eea](https://github.com/googleapis/python-bigquery-dataframes/commit/fb81eeaf13af059f32cb38e7f117fb3504243d51))
19+
20+
21+
### Bug Fixes
22+
23+
* Avoid ibis fillna warning in compiler ([#2113](https://github.com/googleapis/python-bigquery-dataframes/issues/2113)) ([7ef667b](https://github.com/googleapis/python-bigquery-dataframes/commit/7ef667b0f46f13bcc8ad4f2ed8f81278132b5aec))
24+
* Negative start and stop parameter values in Series.str.slice() ([#2104](https://github.com/googleapis/python-bigquery-dataframes/issues/2104)) ([f57a348](https://github.com/googleapis/python-bigquery-dataframes/commit/f57a348f1935a4e2bb14c501bb4c47cd552d102a))
25+
* Throw type error for incomparable join keys ([#2098](https://github.com/googleapis/python-bigquery-dataframes/issues/2098)) ([9dc9695](https://github.com/googleapis/python-bigquery-dataframes/commit/9dc96959a84b751d18b290129c2926df6e50b3f5))
26+
* Transformers with non-standard column names throw errors ([#2089](https://github.com/googleapis/python-bigquery-dataframes/issues/2089)) ([a2daa3f](https://github.com/googleapis/python-bigquery-dataframes/commit/a2daa3fffe6743327edb9f4c74db93198bd12f8e))
27+
728
## [2.21.0](https://github.com/googleapis/python-bigquery-dataframes/compare/v2.20.0...v2.21.0) (2025-09-17)
829

930

bigframes/core/compile/default_ordering.py renamed to bigframes/core/compile/ibis_compiler/default_ordering.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ def _convert_to_nonnull_string(column: ibis_types.Value) -> ibis_types.StringVal
4747
result = ibis_ops.ToJsonString(column).to_expr() # type: ignore
4848
# Escape backslashes and use backslash as delineator
4949
escaped = cast(
50-
ibis_types.StringColumn,
51-
result.fill_null(ibis_types.literal(""))
52-
if hasattr(result, "fill_null")
53-
else result.fillna(""),
50+
ibis_types.StringColumn, result.fill_null(ibis_types.literal(""))
5451
).replace(
5552
"\\", # type: ignore
5653
"\\\\", # type: ignore

bigframes/core/compile/ibis_compiler/scalar_op_registry.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import pandas as pd
2929

3030
from bigframes.core.compile.constants import UNIT_TO_US_CONVERSION_FACTORS
31-
import bigframes.core.compile.default_ordering
31+
import bigframes.core.compile.ibis_compiler.default_ordering
3232
from bigframes.core.compile.ibis_compiler.scalar_op_compiler import (
3333
scalar_op_compiler, # TODO(tswast): avoid import of variables
3434
)
@@ -1064,7 +1064,7 @@ def isin_op_impl(x: ibis_types.Value, op: ops.IsInOp):
10641064
if op.match_nulls and contains_nulls:
10651065
return x.isnull() | x.isin(matchable_ibis_values)
10661066
else:
1067-
return x.isin(matchable_ibis_values).fillna(False)
1067+
return x.isin(matchable_ibis_values).fill_null(ibis.literal(False))
10681068

10691069

10701070
@scalar_op_compiler.register_unary_op(ops.ToDatetimeOp, pass_op=True)
@@ -1387,8 +1387,8 @@ def eq_nulls_match_op(
13871387
left = x.cast(ibis_dtypes.str).fill_null(literal)
13881388
right = y.cast(ibis_dtypes.str).fill_null(literal)
13891389
else:
1390-
left = x.cast(ibis_dtypes.str).fillna(literal)
1391-
right = y.cast(ibis_dtypes.str).fillna(literal)
1390+
left = x.cast(ibis_dtypes.str).fill_null(literal)
1391+
right = y.cast(ibis_dtypes.str).fill_null(literal)
13921392

13931393
return left == right
13941394

@@ -1817,7 +1817,7 @@ def fillna_op(
18171817
if hasattr(x, "fill_null"):
18181818
return x.fill_null(typing.cast(ibis_types.Scalar, y))
18191819
else:
1820-
return x.fillna(typing.cast(ibis_types.Scalar, y))
1820+
return x.fill_null(typing.cast(ibis_types.Scalar, y))
18211821

18221822

18231823
@scalar_op_compiler.register_binary_op(ops.round_op)
@@ -2020,7 +2020,7 @@ def _construct_prompt(
20202020

20212021
@scalar_op_compiler.register_nary_op(ops.RowKey, pass_op=True)
20222022
def rowkey_op_impl(*values: ibis_types.Value, op: ops.RowKey) -> ibis_types.Value:
2023-
return bigframes.core.compile.default_ordering.gen_row_key(values)
2023+
return bigframes.core.compile.ibis_compiler.default_ordering.gen_row_key(values)
20242024

20252025

20262026
# Helpers

bigframes/core/compile/sqlglot/aggregations/unary_compiler.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ def _(
4747
return apply_window_if_present(sge.func("COUNT", column.expr), window)
4848

4949

50+
@UNARY_OP_REGISTRATION.register(agg_ops.DenseRankOp)
51+
def _(
52+
op: agg_ops.DenseRankOp,
53+
column: typed_expr.TypedExpr,
54+
window: typing.Optional[window_spec.WindowSpec] = None,
55+
) -> sge.Expression:
56+
# Ranking functions do not support window framing clauses.
57+
return apply_window_if_present(
58+
sge.func("DENSE_RANK"), window, include_framing_clauses=False
59+
)
60+
61+
5062
@UNARY_OP_REGISTRATION.register(agg_ops.MaxOp)
5163
def _(
5264
op: agg_ops.MaxOp,
@@ -56,6 +68,26 @@ def _(
5668
return apply_window_if_present(sge.func("MAX", column.expr), window)
5769

5870

71+
@UNARY_OP_REGISTRATION.register(agg_ops.MeanOp)
72+
def _(
73+
op: agg_ops.MeanOp,
74+
column: typed_expr.TypedExpr,
75+
window: typing.Optional[window_spec.WindowSpec] = None,
76+
) -> sge.Expression:
77+
expr = column.expr
78+
if column.dtype == dtypes.BOOL_DTYPE:
79+
expr = sge.Cast(this=expr, to="INT64")
80+
81+
expr = sge.func("AVG", expr)
82+
83+
should_floor_result = (
84+
op.should_floor_result or column.dtype == dtypes.TIMEDELTA_DTYPE
85+
)
86+
if should_floor_result:
87+
expr = sge.Cast(this=sge.func("FLOOR", expr), to="INT64")
88+
return apply_window_if_present(expr, window)
89+
90+
5991
@UNARY_OP_REGISTRATION.register(agg_ops.MedianOp)
6092
def _(
6193
op: agg_ops.MedianOp,
@@ -86,6 +118,18 @@ def _(
86118
return apply_window_if_present(sge.func("COUNT", sge.convert(1)), window)
87119

88120

121+
@UNARY_OP_REGISTRATION.register(agg_ops.RankOp)
122+
def _(
123+
op: agg_ops.RankOp,
124+
column: typed_expr.TypedExpr,
125+
window: typing.Optional[window_spec.WindowSpec] = None,
126+
) -> sge.Expression:
127+
# Ranking functions do not support window framing clauses.
128+
return apply_window_if_present(
129+
sge.func("RANK"), window, include_framing_clauses=False
130+
)
131+
132+
89133
@UNARY_OP_REGISTRATION.register(agg_ops.SumOp)
90134
def _(
91135
op: agg_ops.SumOp,

bigframes/core/compile/sqlglot/aggregations/windows.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
def apply_window_if_present(
2626
value: sge.Expression,
2727
window: typing.Optional[window_spec.WindowSpec] = None,
28+
include_framing_clauses: bool = True,
2829
) -> sge.Expression:
2930
if window is None:
3031
return value
@@ -64,6 +65,9 @@ def apply_window_if_present(
6465
if not window.bounds and not order:
6566
return sge.Window(this=value, partition_by=group_by)
6667

68+
if not window.bounds and not include_framing_clauses:
69+
return sge.Window(this=value, partition_by=group_by, order=order)
70+
6771
kind = (
6872
"ROWS" if isinstance(window.bounds, window_spec.RowsWindowBounds) else "RANGE"
6973
)

bigframes/operations/aggregations.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ def implicitly_inherits_order(self):
519519

520520
@dataclasses.dataclass(frozen=True)
521521
class DenseRankOp(UnaryWindowOp):
522+
name: ClassVar[str] = "dense_rank"
523+
522524
@property
523525
def skips_nulls(self):
524526
return False

bigframes/session/_io/bigquery/read_gbq_table.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,9 @@
2727
import google.api_core.exceptions
2828
import google.cloud.bigquery as bigquery
2929

30-
import bigframes.clients
31-
import bigframes.core.compile
32-
import bigframes.core.compile.default_ordering
3330
import bigframes.core.sql
34-
import bigframes.dtypes
3531
import bigframes.exceptions as bfe
3632
import bigframes.session._io.bigquery
37-
import bigframes.session.clients
38-
import bigframes.version
3933

4034
# Avoid circular imports.
4135
if typing.TYPE_CHECKING:

bigframes/version.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "2.21.0"
15+
__version__ = "2.22.0"
1616

1717
# {x-release-please-start-date}
18-
__release_date__ = "2025-09-17"
18+
__release_date__ = "2025-09-25"
1919
# {x-release-please-end}

tests/system/small/engines/test_aggregation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_engines_aggregate_size(
7171
assert_equivalence_execution(node, REFERENCE_ENGINE, engine)
7272

7373

74-
@pytest.mark.parametrize("engine", ["polars", "bq"], indirect=True)
74+
@pytest.mark.parametrize("engine", ["polars", "bq", "bq-sqlglot"], indirect=True)
7575
@pytest.mark.parametrize(
7676
"op",
7777
[agg_ops.min_op, agg_ops.max_op, agg_ops.mean_op, agg_ops.sum_op, agg_ops.count_op],
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
WITH `bfcte_0` AS (
2+
SELECT
3+
`int64_col` AS `bfcol_0`
4+
FROM `bigframes-dev`.`sqlglot_test`.`scalar_types`
5+
), `bfcte_1` AS (
6+
SELECT
7+
*,
8+
DENSE_RANK() OVER (ORDER BY `bfcol_0` IS NULL ASC NULLS LAST, `bfcol_0` ASC NULLS LAST) AS `bfcol_1`
9+
FROM `bfcte_0`
10+
)
11+
SELECT
12+
`bfcol_1` AS `agg_int64`
13+
FROM `bfcte_1`

0 commit comments

Comments
 (0)