Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on May 7, 2026. It is now read-only.

Commit e4e3ec8

Browse filesBrowse files
authored
revert: DataFrame display uses IPython's _repr_mimebundle_ (#2316)
revert "refactor: Migrate DataFrame display to use IPython's _repr_mimebundle_() protocol for anywidget mode (#2271)" This reverts commit 41630b5 for bug 466155761. Verified at Colab: screen/AjTEQC8SrSfMqhN Fixes #< 466155761 > 🦕
1 parent d993831 commit e4e3ec8
Copy full SHA for e4e3ec8

9 files changed

+128-796Lines changed: 128 additions & 796 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎bigframes/core/indexes/base.py‎

Copy file name to clipboardExpand all lines: bigframes/core/indexes/base.py
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ def __repr__(self) -> __builtins__.str:
376376
# metadata, like we do with DataFrame.
377377
opts = bigframes.options.display
378378
max_results = opts.max_rows
379-
if opts.repr_mode == "deferred":
379+
# anywdiget mode uses the same display logic as the "deferred" mode
380+
# for faster execution
381+
if opts.repr_mode in ("deferred", "anywidget"):
380382
_, dry_run_query_job = self._block._compute_dry_run()
381383
return formatter.repr_query_job(dry_run_query_job)
382384

Collapse file

‎bigframes/dataframe.py‎

Copy file name to clipboardExpand all lines: bigframes/dataframe.py
+48-113Lines changed: 48 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,9 @@ def __repr__(self) -> str:
789789

790790
opts = bigframes.options.display
791791
max_results = opts.max_rows
792-
if opts.repr_mode == "deferred":
792+
# anywdiget mode uses the same display logic as the "deferred" mode
793+
# for faster execution
794+
if opts.repr_mode in ("deferred", "anywidget"):
793795
return formatter.repr_query_job(self._compute_dry_run())
794796

795797
# TODO(swast): pass max_columns and get the true column count back. Maybe
@@ -827,138 +829,68 @@ def __repr__(self) -> str:
827829
lines.append(f"[{row_count} rows x {column_count} columns]")
828830
return "\n".join(lines)
829831

830-
def _get_display_df_and_blob_cols(self) -> tuple[DataFrame, list[str]]:
831-
"""Process blob columns for display."""
832-
df = self
833-
blob_cols = []
832+
def _repr_html_(self) -> str:
833+
"""
834+
Returns an html string primarily for use by notebooks for displaying
835+
a representation of the DataFrame. Displays 20 rows by default since
836+
many notebooks are not configured for large tables.
837+
"""
838+
opts = bigframes.options.display
839+
max_results = opts.max_rows
840+
if opts.repr_mode == "deferred":
841+
return formatter.repr_query_job(self._compute_dry_run())
842+
843+
# Process blob columns first, regardless of display mode
844+
self._cached()
845+
df = self.copy()
834846
if bigframes.options.display.blob_display:
835847
blob_cols = [
836848
series_name
837-
for series_name, series in self.items()
849+
for series_name, series in df.items()
838850
if series.dtype == bigframes.dtypes.OBJ_REF_DTYPE
839851
]
840-
if blob_cols:
841-
df = self.copy()
842-
for col in blob_cols:
843-
# TODO(garrettwu): Not necessary to get access urls for all the rows. Update when having a to get URLs from local data.
844-
df[col] = df[col].blob._get_runtime(mode="R", with_metadata=True)
845-
return df, blob_cols
846-
847-
def _get_anywidget_bundle(self, include=None, exclude=None):
848-
"""
849-
Helper method to create and return the anywidget mimebundle.
850-
This function encapsulates the logic for anywidget display.
851-
"""
852-
from bigframes import display
853-
854-
# TODO(shuowei): Keep blob_cols and pass them to TableWidget so that they can render properly.
855-
df, _ = self._get_display_df_and_blob_cols()
856-
857-
# Create and display the widget
858-
widget = display.TableWidget(df)
859-
widget_repr_result = widget._repr_mimebundle_(include=include, exclude=exclude)
860-
861-
# Handle both tuple (data, metadata) and dict returns
862-
if isinstance(widget_repr_result, tuple):
863-
widget_repr = dict(widget_repr_result[0]) # Extract data dict from tuple
852+
for col in blob_cols:
853+
# TODO(garrettwu): Not necessary to get access urls for all the rows. Update when having a to get URLs from local data.
854+
df[col] = df[col].blob._get_runtime(mode="R", with_metadata=True)
864855
else:
865-
widget_repr = dict(widget_repr_result)
866-
867-
# At this point, we have already executed the query as part of the
868-
# widget construction. Let's use the information available to render
869-
# the HTML and plain text versions.
870-
widget_repr["text/html"] = widget.table_html
871-
872-
widget_repr["text/plain"] = self._create_text_representation(
873-
widget._cached_data, widget.row_count
874-
)
875-
876-
return widget_repr
877-
878-
def _create_text_representation(
879-
self, pandas_df: pandas.DataFrame, total_rows: typing.Optional[int]
880-
) -> str:
881-
"""Create a text representation of the DataFrame."""
882-
opts = bigframes.options.display
883-
with display_options.pandas_repr(opts):
884-
import pandas.io.formats
885-
886-
# safe to mutate this, this dict is owned by this code, and does not affect global config
887-
to_string_kwargs = (
888-
pandas.io.formats.format.get_dataframe_repr_params() # type: ignore
889-
)
890-
if not self._has_index:
891-
to_string_kwargs.update({"index": False})
856+
blob_cols = []
892857

893-
# We add our own dimensions string, so don't want pandas to.
894-
to_string_kwargs.update({"show_dimensions": False})
895-
repr_string = pandas_df.to_string(**to_string_kwargs)
858+
if opts.repr_mode == "anywidget":
859+
try:
860+
from IPython.display import display as ipython_display
896861

897-
lines = repr_string.split("\n")
862+
from bigframes import display
898863

899-
if total_rows is not None and total_rows > len(pandas_df):
900-
lines.append("...")
864+
# Always create a new widget instance for each display call
865+
# This ensures that each cell gets its own widget and prevents
866+
# unintended sharing between cells
867+
widget = display.TableWidget(df.copy())
901868

902-
lines.append("")
903-
column_count = len(self.columns)
904-
lines.append(f"[{total_rows or '?'} rows x {column_count} columns]")
905-
return "\n".join(lines)
869+
ipython_display(widget)
870+
return "" # Return empty string since we used display()
906871

907-
def _repr_mimebundle_(self, include=None, exclude=None):
908-
"""
909-
Custom display method for IPython/Jupyter environments.
910-
This is called by IPython's display system when the object is displayed.
911-
"""
912-
opts = bigframes.options.display
913-
# Only handle widget display in anywidget mode
914-
if opts.repr_mode == "anywidget":
915-
try:
916-
return self._get_anywidget_bundle(include=include, exclude=exclude)
917-
918-
except ImportError:
919-
# Anywidget is an optional dependency, so warn rather than fail.
920-
# TODO(shuowei): When Anywidget becomes the default for all repr modes,
921-
# remove this warning.
872+
except (AttributeError, ValueError, ImportError):
873+
# Fallback if anywidget is not available
922874
warnings.warn(
923875
"Anywidget mode is not available. "
924876
"Please `pip install anywidget traitlets` or `pip install 'bigframes[anywidget]'` to use interactive tables. "
925-
f"Falling back to static HTML. Error: {traceback.format_exc()}"
877+
f"Falling back to deferred mode. Error: {traceback.format_exc()}"
926878
)
879+
return formatter.repr_query_job(self._compute_dry_run())
927880

928-
# In non-anywidget mode, fetch data once and use it for both HTML
929-
# and plain text representations to avoid multiple queries.
930-
opts = bigframes.options.display
931-
max_results = opts.max_rows
932-
933-
df, blob_cols = self._get_display_df_and_blob_cols()
934-
881+
# Continue with regular HTML rendering for non-anywidget modes
882+
# TODO(swast): pass max_columns and get the true column count back. Maybe
883+
# get 1 more column than we have requested so that pandas can add the
884+
# ... for us?
935885
pandas_df, row_count, query_job = df._block.retrieve_repr_request_results(
936886
max_results
937887
)
888+
938889
self._set_internal_query_job(query_job)
939890
column_count = len(pandas_df.columns)
940891

941-
html_string = self._create_html_representation(
942-
pandas_df, row_count, column_count, blob_cols
943-
)
944-
945-
text_representation = self._create_text_representation(pandas_df, row_count)
946-
947-
return {"text/html": html_string, "text/plain": text_representation}
948-
949-
def _create_html_representation(
950-
self,
951-
pandas_df: pandas.DataFrame,
952-
row_count: int,
953-
column_count: int,
954-
blob_cols: list[str],
955-
) -> str:
956-
"""Create an HTML representation of the DataFrame."""
957-
opts = bigframes.options.display
958892
with display_options.pandas_repr(opts):
959-
# TODO(shuowei, b/464053870): Escaping HTML would be useful, but
960-
# `escape=False` is needed to show images. We may need to implement
961-
# a full-fledged repr module to better support types not in pandas.
893+
# Allows to preview images in the DataFrame. The implementation changes the string repr as well, that it doesn't truncate strings or escape html charaters such as "<" and ">". We may need to implement a full-fledged repr module to better support types not in pandas.
962894
if bigframes.options.display.blob_display and blob_cols:
963895

964896
def obj_ref_rt_to_html(obj_ref_rt) -> str:
@@ -987,12 +919,15 @@ def obj_ref_rt_to_html(obj_ref_rt) -> str:
987919

988920
# set max_colwidth so not to truncate the image url
989921
with pandas.option_context("display.max_colwidth", None):
922+
max_rows = pandas.get_option("display.max_rows")
923+
max_cols = pandas.get_option("display.max_columns")
924+
show_dimensions = pandas.get_option("display.show_dimensions")
990925
html_string = pandas_df.to_html(
991926
escape=False,
992927
notebook=True,
993-
max_rows=pandas.get_option("display.max_rows"),
994-
max_cols=pandas.get_option("display.max_columns"),
995-
show_dimensions=pandas.get_option("display.show_dimensions"),
928+
max_rows=max_rows,
929+
max_cols=max_cols,
930+
show_dimensions=show_dimensions,
996931
formatters=formatters, # type: ignore
997932
)
998933
else:
Collapse file

‎bigframes/streaming/dataframe.py‎

Copy file name to clipboardExpand all lines: bigframes/streaming/dataframe.py
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,13 @@ def __repr__(self, *args, **kwargs):
291291

292292
__repr__.__doc__ = _curate_df_doc(inspect.getdoc(dataframe.DataFrame.__repr__))
293293

294-
def _repr_mimebundle_(self, *args, **kwargs):
295-
return _return_type_wrapper(self._df._repr_mimebundle_, StreamingDataFrame)(
294+
def _repr_html_(self, *args, **kwargs):
295+
return _return_type_wrapper(self._df._repr_html_, StreamingDataFrame)(
296296
*args, **kwargs
297297
)
298298

299-
_repr_mimebundle_.__doc__ = _curate_df_doc(
300-
inspect.getdoc(dataframe.DataFrame._repr_mimebundle_)
299+
_repr_html_.__doc__ = _curate_df_doc(
300+
inspect.getdoc(dataframe.DataFrame._repr_html_)
301301
)
302302

303303
@property

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.