diff --git a/bigframes/display/html.py b/bigframes/display/html.py index 3f1667eb9c..912f1d7e3a 100644 --- a/bigframes/display/html.py +++ b/bigframes/display/html.py @@ -48,60 +48,62 @@ def render_html( orderable_columns: list[str] | None = None, ) -> str: """Render a pandas DataFrame to HTML with specific styling.""" - classes = "dataframe table table-striped table-hover" - table_html = [f''] - precision = options.display.precision orderable_columns = orderable_columns or [] + classes = "dataframe table table-striped table-hover" + table_html_parts = [f'
'] + table_html_parts.append(_render_table_header(dataframe, orderable_columns)) + table_html_parts.append(_render_table_body(dataframe)) + table_html_parts.append("
") + return "".join(table_html_parts) - # Render table head - table_html.append(" ") - table_html.append(' ') + +def _render_table_header(dataframe: pd.DataFrame, orderable_columns: list[str]) -> str: + """Render the header of the HTML table.""" + header_parts = [" ", " "] for col in dataframe.columns: th_classes = [] if col in orderable_columns: th_classes.append("sortable") class_str = f'class="{" ".join(th_classes)}"' if th_classes else "" - header_div = ( - '
' - f"{html.escape(str(col))}" - "
" - ) - table_html.append( - f' {header_div}' + header_parts.append( + f'
' + f"{html.escape(str(col))}
" ) - table_html.append(" ") - table_html.append(" ") + header_parts.extend([" ", " "]) + return "\n".join(header_parts) + + +def _render_table_body(dataframe: pd.DataFrame) -> str: + """Render the body of the HTML table.""" + body_parts = [" "] + precision = options.display.precision - # Render table body - table_html.append(" ") for i in range(len(dataframe)): - table_html.append(" ") + body_parts.append(" ") row = dataframe.iloc[i] for col_name, value in row.items(): dtype = dataframe.dtypes.loc[col_name] # type: ignore align = "right" if _is_dtype_numeric(dtype) else "left" - table_html.append( - ' '.format(align) - ) # TODO(b/438181139): Consider semi-exploding ARRAY/STRUCT columns # into multiple rows/columns like the BQ UI does. if pandas.api.types.is_scalar(value) and pd.isna(value): - table_html.append(' <NA>') + body_parts.append( + f' ' + '<NA>' + ) else: if isinstance(value, float): - formatted_value = f"{value:.{precision}f}" - table_html.append(f" {html.escape(formatted_value)}") + cell_content = f"{value:.{precision}f}" else: - table_html.append(f" {html.escape(str(value))}") - table_html.append(" ") - table_html.append(" ") - table_html.append(" ") - table_html.append("") - - return "\n".join(table_html) + cell_content = str(value) + body_parts.append( + f' ' + f"{html.escape(cell_content)}" + ) + body_parts.append(" ") + body_parts.append(" ") + return "\n".join(body_parts) def _obj_ref_rt_to_html(obj_ref_rt: str) -> str: diff --git a/tests/unit/display/test_html.py b/tests/unit/display/test_html.py index fcf1455362..0762a2fd8d 100644 --- a/tests/unit/display/test_html.py +++ b/tests/unit/display/test_html.py @@ -130,9 +130,8 @@ def test_render_html_alignment_and_precision( df = pd.DataFrame(data) html = bf_html.render_html(dataframe=df, table_id="test-table") - for _, align in expected_alignments.items(): - assert 'th style="text-align: left;"' in html - assert f'