Skip to content

Commit 894bac0

Browse files
committed
Add backward compatibility tests for deprecated formatter attributes
1 parent 6f92b3d commit 894bac0

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

python/tests/test_dataframe.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,53 @@ def test_html_formatter_manual_format_html(clean_formatter_state):
31343134
assert "<style>" not in local_html_2
31353135

31363136

3137+
def test_html_formatter_backward_compatibility_repr_rows(df, clean_formatter_state):
3138+
"""Test backward compatibility with custom formatter using deprecated repr_rows attribute.
3139+
3140+
This test validates that the Rust code correctly handles custom formatter
3141+
implementations that only have the deprecated `repr_rows` attribute (no `max_rows`).
3142+
3143+
This is critical for supporting custom formatters created before the `max_rows`
3144+
attribute was added. Users should be able to pass their custom formatter objects
3145+
without breaking the rendering pipeline.
3146+
3147+
Deprecation Timeline:
3148+
- Release N (current): Added `max_rows`, kept `repr_rows` for backward compatibility
3149+
- Release N+1: Both `repr_rows` and `max_rows` supported (with fallback in Rust)
3150+
- Release N+2: Remove `repr_rows` fallback logic in Rust code
3151+
- Release N+3: Remove `repr_rows` property entirely from Python
3152+
"""
3153+
3154+
# Create a custom formatter class that ONLY has repr_rows (simulating old code)
3155+
class LegacyCustomFormatter:
3156+
"""Simulates a custom formatter implementation created before max_rows existed."""
3157+
3158+
def __init__(self):
3159+
# Only set repr_rows, not max_rows (as old formatters would)
3160+
self.repr_rows = 5
3161+
self.max_memory_bytes = 2 * MB
3162+
self.min_rows = 2
3163+
3164+
def format_html(self, batches, schema):
3165+
"""Minimal format_html implementation for testing."""
3166+
# Just return valid HTML to pass validation
3167+
return "<table><tr><td>test</td></tr></table>"
3168+
3169+
# Use the legacy formatter with DataFusion
3170+
legacy_formatter = LegacyCustomFormatter()
3171+
3172+
# This should not raise an error even though max_rows doesn't exist
3173+
# The Rust code should fall back to repr_rows
3174+
html_output = df._repr_html_()
3175+
3176+
# Verify that rendering succeeded
3177+
assert isinstance(html_output, str)
3178+
assert len(html_output) > 0
3179+
3180+
# Verify it's valid HTML (basic check)
3181+
assert "<table" in html_output.lower() or "data truncated" in html_output.lower()
3182+
3183+
31373184
def test_fill_null_basic(null_df):
31383185
"""Test basic fill_null functionality with a single value."""
31393186
# Fill all nulls with 0

src/dataframe.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,24 @@ fn build_formatter_config_from_python(formatter: &Bound<'_, PyAny>) -> PyResult<
153153
let default_config = FormatterConfig::default();
154154
let max_bytes = get_attr(formatter, "max_memory_bytes", default_config.max_bytes);
155155
let min_rows = get_attr(formatter, "min_rows", default_config.min_rows);
156-
let max_rows = get_attr(formatter, "max_rows", default_config.max_rows);
156+
157+
// Backward compatibility: Try max_rows first (new name), fall back to repr_rows (deprecated),
158+
// then use default. This ensures backward compatibility with custom formatter implementations
159+
// during the deprecation period.
160+
let max_rows = get_attr(formatter, "max_rows", 0usize);
161+
let max_rows = if max_rows > 0 {
162+
// max_rows attribute exists and has a value
163+
max_rows
164+
} else {
165+
// Try the deprecated repr_rows attribute
166+
let repr_rows = get_attr(formatter, "repr_rows", 0usize);
167+
if repr_rows > 0 {
168+
repr_rows
169+
} else {
170+
// Use default
171+
default_config.max_rows
172+
}
173+
};
157174

158175
let config = FormatterConfig {
159176
max_bytes,

0 commit comments

Comments
 (0)