From 1cf64324b628e7659d743ff3e8ff652a9f97f70f Mon Sep 17 00:00:00 2001 From: Trevor Bergeron Date: Mon, 29 Sep 2025 20:39:40 +0000 Subject: [PATCH 1/3] fix: Fix internal type errors with temporal accessors --- tests/system/small/operations/test_dates.py | 11 +++++++++++ tests/system/small/operations/test_datetimes.py | 11 +++++++++++ .../ibis/expr/operations/strings.py | 4 ++-- .../ibis/expr/operations/temporal.py | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/system/small/operations/test_dates.py b/tests/system/small/operations/test_dates.py index e183bbfe43..1e64b6eb8b 100644 --- a/tests/system/small/operations/test_dates.py +++ b/tests/system/small/operations/test_dates.py @@ -71,3 +71,14 @@ def test_date_series_diff_agg(scalars_dfs): pandas.testing.assert_series_equal( actual_result, expected_result, check_index_type=False ) + + +def test_date_can_cast_after_accessor(scalars_dfs): + bf_df, pd_df = scalars_dfs + + actual_result = bf_df.date_col.dt.isocalendar().week.astype("Int64").to_pandas() + expected_result = pd_df.date_col.dt.isocalendar().week.astype("Int64") + + pandas.testing.assert_series_equal( + actual_result, expected_result, check_dtype=False, check_index_type=False + ) diff --git a/tests/system/small/operations/test_datetimes.py b/tests/system/small/operations/test_datetimes.py index 1462a68b49..3345a910be 100644 --- a/tests/system/small/operations/test_datetimes.py +++ b/tests/system/small/operations/test_datetimes.py @@ -603,3 +603,14 @@ def test_to_datetime(scalars_dfs, col): testing.assert_series_equal( actual_result, expected_result, check_dtype=False, check_index_type=False ) + + +def test_timedelta_can_cast_after_dt_accessor(timedelta_series): + bf_s, pd_s = timedelta_series + + actual_result = bf_s.dt.isocalendar().week.astype("Int64").to_pandas() + expected_result = pd_s.dt.isocalendar().week.astype("Int64") + + assert_series_equal( + actual_result, expected_result, check_dtype=False, check_index_type=False + ) diff --git a/third_party/bigframes_vendored/ibis/expr/operations/strings.py b/third_party/bigframes_vendored/ibis/expr/operations/strings.py index ffd93e6fdd..050c079b6b 100644 --- a/third_party/bigframes_vendored/ibis/expr/operations/strings.py +++ b/third_party/bigframes_vendored/ibis/expr/operations/strings.py @@ -364,14 +364,14 @@ class ExtractFragment(ExtractURLField): class StringLength(StringUnary): """Compute the length of a string.""" - dtype = dt.int32 + dtype = dt.int64 @public class StringAscii(StringUnary): """Compute the ASCII code of the first character of a string.""" - dtype = dt.int32 + dtype = dt.int64 @public diff --git a/third_party/bigframes_vendored/ibis/expr/operations/temporal.py b/third_party/bigframes_vendored/ibis/expr/operations/temporal.py index 75a0ef9efc..b527e14f04 100644 --- a/third_party/bigframes_vendored/ibis/expr/operations/temporal.py +++ b/third_party/bigframes_vendored/ibis/expr/operations/temporal.py @@ -105,7 +105,7 @@ class ExtractTemporalField(Unary): """Extract a field from a temporal value.""" arg: Value[dt.Temporal] - dtype = dt.int32 + dtype = dt.int64 @public From b102b1a017e8b1ee74a21cf2182ce035d51cec4e Mon Sep 17 00:00:00 2001 From: Trevor Bergeron Date: Wed, 1 Oct 2025 20:33:45 +0000 Subject: [PATCH 2/3] fix tests --- bigframes/operations/datetimes.py | 14 ++++++-------- tests/system/small/operations/test_dates.py | 7 +++++-- tests/system/small/operations/test_datetimes.py | 11 ----------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/bigframes/operations/datetimes.py b/bigframes/operations/datetimes.py index 95896ddc97..c80379cc2b 100644 --- a/bigframes/operations/datetimes.py +++ b/bigframes/operations/datetimes.py @@ -23,7 +23,6 @@ from bigframes import dataframe, dtypes, series from bigframes.core import log_adapter -from bigframes.core.reshape import concat import bigframes.operations as ops import bigframes.operations.base @@ -79,13 +78,12 @@ def month(self) -> series.Series: return self._apply_unary_op(ops.month_op) def isocalendar(self) -> dataframe.DataFrame: - years = self._apply_unary_op(ops.iso_year_op) - weeks = self._apply_unary_op(ops.iso_week_op) - days = self._apply_unary_op(ops.iso_day_op) - - result = concat.concat([years, weeks, days], axis=1) - result.columns = pandas.Index(["year", "week", "day"]) - return result + iso_ops = [ops.iso_year_op, ops.iso_week_op, ops.iso_day_op] + labels = pandas.Index(["year", "week", "day"]) + block = self._block.project_exprs( + [op.as_expr(self._value_column) for op in iso_ops], labels, drop=True + ) + return dataframe.DataFrame(block) # Time accessors @property diff --git a/tests/system/small/operations/test_dates.py b/tests/system/small/operations/test_dates.py index 1e64b6eb8b..5828a105fb 100644 --- a/tests/system/small/operations/test_dates.py +++ b/tests/system/small/operations/test_dates.py @@ -76,8 +76,11 @@ def test_date_series_diff_agg(scalars_dfs): def test_date_can_cast_after_accessor(scalars_dfs): bf_df, pd_df = scalars_dfs - actual_result = bf_df.date_col.dt.isocalendar().week.astype("Int64").to_pandas() - expected_result = pd_df.date_col.dt.isocalendar().week.astype("Int64") + actual_result = bf_df["date_col"].dt.isocalendar().week.astype("Int64").to_pandas() + # convert to pd date type rather than arrow, as pandas doesn't handle arrow date well here + expected_result = ( + pd.to_datetime(pd_df["date_col"]).dt.isocalendar().week.astype("Int64") + ) pandas.testing.assert_series_equal( actual_result, expected_result, check_dtype=False, check_index_type=False diff --git a/tests/system/small/operations/test_datetimes.py b/tests/system/small/operations/test_datetimes.py index 3345a910be..1462a68b49 100644 --- a/tests/system/small/operations/test_datetimes.py +++ b/tests/system/small/operations/test_datetimes.py @@ -603,14 +603,3 @@ def test_to_datetime(scalars_dfs, col): testing.assert_series_equal( actual_result, expected_result, check_dtype=False, check_index_type=False ) - - -def test_timedelta_can_cast_after_dt_accessor(timedelta_series): - bf_s, pd_s = timedelta_series - - actual_result = bf_s.dt.isocalendar().week.astype("Int64").to_pandas() - expected_result = pd_s.dt.isocalendar().week.astype("Int64") - - assert_series_equal( - actual_result, expected_result, check_dtype=False, check_index_type=False - ) From f423edeb6ecd07b37131c7b098007b7bbd84cc8a Mon Sep 17 00:00:00 2001 From: Trevor Bergeron Date: Wed, 1 Oct 2025 21:07:23 +0000 Subject: [PATCH 3/3] block test for old pandas --- tests/system/small/operations/test_dates.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/system/small/operations/test_dates.py b/tests/system/small/operations/test_dates.py index 5828a105fb..9e8da64209 100644 --- a/tests/system/small/operations/test_dates.py +++ b/tests/system/small/operations/test_dates.py @@ -15,8 +15,10 @@ import datetime +from packaging import version import pandas as pd import pandas.testing +import pytest from bigframes import dtypes @@ -74,6 +76,8 @@ def test_date_series_diff_agg(scalars_dfs): def test_date_can_cast_after_accessor(scalars_dfs): + if version.Version(pd.__version__) <= version.Version("2.1.0"): + pytest.skip("pd timezone conversion bug") bf_df, pd_df = scalars_dfs actual_result = bf_df["date_col"].dt.isocalendar().week.astype("Int64").to_pandas()