From 5212f72f6747720ab95d51f57ba78950802b66ad Mon Sep 17 00:00:00 2001 From: Tim Swena Date: Mon, 3 Feb 2025 08:52:26 -0600 Subject: [PATCH 1/2] fix: add feedback link to `DataFrame` and `Series` `__call__` error --- bigframes/dataframe.py | 8 ++++++++ bigframes/series.py | 8 ++++++++ tests/unit/test_dataframe.py | 9 +++++++++ tests/unit/test_series.py | 13 +++++++++++++ 4 files changed, 38 insertions(+) diff --git a/bigframes/dataframe.py b/bigframes/dataframe.py index d9d3d431fd..34eba727b6 100644 --- a/bigframes/dataframe.py +++ b/bigframes/dataframe.py @@ -200,6 +200,14 @@ def __init__( self._query_job: Optional[bigquery.QueryJob] = None self._block.session._register_object(self) + def __call__(self, *args, **kwargs): + """Placeholder implementation to raise a more helpful error.""" + raise TypeError( + "DataFrame is not callable. " + + "Did you mean to use square brackets (e.g. df[col]), instead? " + + constants.FEEDBACK_LINK + ) + def __dir__(self): return dir(type(self)) + [ label diff --git a/bigframes/series.py b/bigframes/series.py index 706c0f4f09..dad3260a73 100644 --- a/bigframes/series.py +++ b/bigframes/series.py @@ -224,6 +224,14 @@ def transpose(self) -> Series: def _set_internal_query_job(self, query_job: Optional[bigquery.QueryJob]): self._query_job = query_job + def __call__(self, *args, **kwargs): + """Placeholder implementation to raise a more helpful error.""" + raise TypeError( + "Series is not callable. " + + "Did you mean to use square brackets (e.g. series[row_label]), instead? " + + constants.FEEDBACK_LINK + ) + def __len__(self): return self.shape[0] diff --git a/tests/unit/test_dataframe.py b/tests/unit/test_dataframe.py index 560c0cf0f4..bb370b7471 100644 --- a/tests/unit/test_dataframe.py +++ b/tests/unit/test_dataframe.py @@ -20,6 +20,15 @@ from . import resources +def test_dataframe_call_typeerror( + monkeypatch: pytest.MonkeyPatch, +): + dataframe = resources.create_dataframe(monkeypatch) + + with pytest.raises(TypeError, match="not callable"): + dataframe("arg", test="kwarg") + + def test_dataframe_dropna_axis_1_subset_not_implememented( monkeypatch: pytest.MonkeyPatch, ): diff --git a/tests/unit/test_series.py b/tests/unit/test_series.py index 1409209c6c..9d19a3f07d 100644 --- a/tests/unit/test_series.py +++ b/tests/unit/test_series.py @@ -12,8 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + import bigframes.series +from . import resources + + +def test_series_call_typeerror( + monkeypatch: pytest.MonkeyPatch, +): + series = resources.create_dataframe(monkeypatch)["col"] + + with pytest.raises(TypeError, match="not callable"): + series("arg", test="kwarg") + def test_series_repr_with_uninitialized_object(): """Ensures Series.__init__ can be paused in a visual debugger without crashing. From 5daf77f9e19cf214941427af6ad4509a8be924f9 Mon Sep 17 00:00:00 2001 From: Tim Swena Date: Mon, 3 Feb 2025 09:51:50 -0600 Subject: [PATCH 2/2] revert __call__ add to unimplemented tracking --- bigframes/core/log_adapter.py | 4 +++- bigframes/dataframe.py | 8 -------- bigframes/series.py | 8 -------- tests/unit/core/test_log_adapter.py | 26 +++++++++++++++++++++++--- tests/unit/test_dataframe.py | 9 --------- tests/unit/test_series.py | 13 ------------- 6 files changed, 26 insertions(+), 42 deletions(-) diff --git a/bigframes/core/log_adapter.py b/bigframes/core/log_adapter.py index d234d9be28..714a522183 100644 --- a/bigframes/core/log_adapter.py +++ b/bigframes/core/log_adapter.py @@ -78,7 +78,9 @@ def submit_pandas_labels( else: return - if hasattr(cls, method_name): + # Omit __call__, because its not implemented on the actual instances of + # DataFrame/Series, only as the constructor. + if method_name != "__call__" and hasattr(cls, method_name): method = getattr(cls, method_name) else: return diff --git a/bigframes/dataframe.py b/bigframes/dataframe.py index 34eba727b6..d9d3d431fd 100644 --- a/bigframes/dataframe.py +++ b/bigframes/dataframe.py @@ -200,14 +200,6 @@ def __init__( self._query_job: Optional[bigquery.QueryJob] = None self._block.session._register_object(self) - def __call__(self, *args, **kwargs): - """Placeholder implementation to raise a more helpful error.""" - raise TypeError( - "DataFrame is not callable. " - + "Did you mean to use square brackets (e.g. df[col]), instead? " - + constants.FEEDBACK_LINK - ) - def __dir__(self): return dir(type(self)) + [ label diff --git a/bigframes/series.py b/bigframes/series.py index dad3260a73..706c0f4f09 100644 --- a/bigframes/series.py +++ b/bigframes/series.py @@ -224,14 +224,6 @@ def transpose(self) -> Series: def _set_internal_query_job(self, query_job: Optional[bigquery.QueryJob]): self._query_job = query_job - def __call__(self, *args, **kwargs): - """Placeholder implementation to raise a more helpful error.""" - raise TypeError( - "Series is not callable. " - + "Did you mean to use square brackets (e.g. series[row_label]), instead? " - + constants.FEEDBACK_LINK - ) - def __len__(self): return self.shape[0] diff --git a/tests/unit/core/test_log_adapter.py b/tests/unit/core/test_log_adapter.py index d183f4479e..6bc9c91f3a 100644 --- a/tests/unit/core/test_log_adapter.py +++ b/tests/unit/core/test_log_adapter.py @@ -157,11 +157,31 @@ def test_submit_pandas_labels_without_valid_params_for_param_logging(mock_bqclie mock_bqclient.query.assert_not_called() -def test_submit_pandas_labels_with_internal_method(mock_bqclient): +@pytest.mark.parametrize( + ("class_name", "method_name"), + ( + ("Series", "_repr_latex_"), + ( + "DataFrame", + # __call__ should be excluded. + # It's implemented on the pd.DataFrame class but not pd.DataFrame instances. + "__call__", + ), + ( + "Series", + # __call__ should be excluded. + # It's implemented on the pd.Series class but not pd.Series instances. + "__call__", + ), + ), +) +def test_submit_pandas_labels_with_internal_method( + mock_bqclient, class_name, method_name +): log_adapter.submit_pandas_labels( mock_bqclient, - "Series", - "_repr_latex_", + class_name, + method_name, task=log_adapter.PANDAS_API_TRACKING_TASK, ) mock_bqclient.query.assert_not_called() diff --git a/tests/unit/test_dataframe.py b/tests/unit/test_dataframe.py index bb370b7471..560c0cf0f4 100644 --- a/tests/unit/test_dataframe.py +++ b/tests/unit/test_dataframe.py @@ -20,15 +20,6 @@ from . import resources -def test_dataframe_call_typeerror( - monkeypatch: pytest.MonkeyPatch, -): - dataframe = resources.create_dataframe(monkeypatch) - - with pytest.raises(TypeError, match="not callable"): - dataframe("arg", test="kwarg") - - def test_dataframe_dropna_axis_1_subset_not_implememented( monkeypatch: pytest.MonkeyPatch, ): diff --git a/tests/unit/test_series.py b/tests/unit/test_series.py index 9d19a3f07d..1409209c6c 100644 --- a/tests/unit/test_series.py +++ b/tests/unit/test_series.py @@ -12,21 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pytest - import bigframes.series -from . import resources - - -def test_series_call_typeerror( - monkeypatch: pytest.MonkeyPatch, -): - series = resources.create_dataframe(monkeypatch)["col"] - - with pytest.raises(TypeError, match="not callable"): - series("arg", test="kwarg") - def test_series_repr_with_uninitialized_object(): """Ensures Series.__init__ can be paused in a visual debugger without crashing.