8000 feat: enhance DataFrameHtmlFormatter with shared styles support and r… · kosiew/datafusion-python@0625b2f · GitHub
[go: up one dir, main page]

Skip to content

Commit 0625b2f

Browse files
committed
feat: enhance DataFrameHtmlFormatter with shared styles support and reset functionality
- Added `use_shared_styles` parameter to control loading of styles/scripts. - Implemented logic to conditionally include styles based on `use_shared_styles`. - Updated the constructor to validate `use_shared_styles` as a boolean. - Introduced `reset_styles_loaded_state` function to reset the styles loaded state. - Modified `reset_formatter` to reset the `_styles_loaded` flag.
1 parent 603302d commit 0625b2f

File tree

1 file changed

+43
-4
lines changed

1 file changed

+43
-4
lines changed

python/datafusion/html_formatter.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ class DataFrameHtmlFormatter:
7777
custom_css: Additional CSS to include in the HTML output
7878
show_truncation_message: Whether to display a message when data is truncated
7979
style_provider: Custom provider for cell and header styles
80+
use_shared_styles: Whether to load styles and scripts only once per notebook session
8081
"""
8182

83+
# Class variable to track if styles have been loaded in the notebook
84+
_styles_loaded = False
85+
8286
def __init__(
8387
self,
8488
max_cell_length: int = 25,
@@ -88,6 +92,7 @@ def __init__(
8892
custom_css: Optional[str] = None,
8993
show_truncation_message: bool = True,
9094
style_provider: Optional[StyleProvider] = None,
95+
use_shared_styles: bool = True,
9196
):
9297
# Validate numeric parameters
9398
if not isinstance(max_cell_length, int) or max_cell_length <= 0:
@@ -102,6 +107,8 @@ def __init__(
102107
raise TypeError("enable_cell_expansion must be a boolean")
103108
if not isinstance(show_truncation_message, bool):
104109
raise TypeError("show_truncation_message must be a boolean")
110+
if not isinstance(use_shared_styles, bool):
111+
raise TypeError("use_shared_styles must be a boolean")
105112

106113
# Validate custom_css
107114
if custom_css is not None and not isinstance(custom_css, str):
@@ -118,6 +125,7 @@ def __init__(
118125
self.custom_css = custom_css
119126
self.show_truncation_message = show_truncation_message
120127
self.style_provider = style_provider or DefaultStyleProvider()
128+
self.use_shared_styles = use_shared_styles
121129
# Registry for custom type formatters
122130
self._type_formatters: Dict[Type, CellFormatter] = {}
123131
# Custom cell builders
@@ -181,7 +189,20 @@ def format_html(
181189

182190
# Build HTML components
183191
html = []
184-
html.extend(self._build_html_header())
192+
193+
# Only include styles and scripts if:
194+
# 1. Not using shared styles, OR
195+
# 2. Using shared styles but they haven't been loaded yet
196+
include_styles = (
197+
not self.use_shared_styles or not DataFrameHtmlFormatter._styles_loaded
198+
)
199+
200+
if include_styles:
201+
html.extend(self._build_html_header())
202+
# If we're using shared styles, mark them as loaded
203+
if self.use_shared_styles:
204+
DataFrameHtmlFormatter._styles_loaded = True
205+
185206
html.extend(self._build_table_container_start())
186207

187208
# Add table header and body
@@ -191,8 +212,13 @@ def format_html(
191212
html.append("</table>")
192213
html.append("</div>")
193214

194-
# Add footer (JavaScript and messages)
195-
html.extend(self._build_html_footer(has_more))
215+
# Add footer with JavaScript only if needed
216+
if include_styles and self.enable_cell_expansion:
217+
html.append(self._get_javascript())
218+
219+
# Always add truncation message if needed (independent of styles)
220+
if has_more and self.show_truncation_message:
221+
html.append("<div>Data truncated due to size.</div>")
196222

197223
return "\n".join(html)
198224

@@ -353,7 +379,8 @@ def _build_html_footer(self, has_more: bool) -> List[str]:
353379
html = []
354380

355381
# Add JavaScript for interactivity only if cell expansion is enabled
356-
if self.enable_cell_expansion:
382+
# and we're not using the shared styles approach
383+
if self.enable_cell_expansion and not self.use_shared_styles:
357384
html.append(self._get_javascript())
358385

359386
# Add truncation message if needed
@@ -457,10 +484,22 @@ def reset_formatter() -> None:
457484
global _default_formatter
458485
_default_formatter = DataFrameHtmlFormatter()
459486

487+
# Reset the styles_loaded flag to ensure styles will be reloaded
488+
DataFrameHtmlFormatter._styles_loaded = False
489+
460490
# Ensure the changes are reflected in existing DataFrames
461491
_refresh_formatter_reference()
462492

463493

494+
def reset_styles_loaded_state() -> None:
495+
"""Reset the styles loaded state to force reloading of styles.
496+
497+
This can be useful when switching between notebook sessions or
498+
when styles need to be refreshed.
499+
"""
500+
DataFrameHtmlFormatter._styles_loaded = False
501+
502+
464503
def _refresh_formatter_reference() -> None:
465504
"""Refresh formatter reference in any modules using it.
466505

0 commit comments

Comments
 (0)
0