|
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | 15 |
|
| 16 | +from typing import Any |
| 17 | +from unittest import mock |
| 18 | + |
16 | 19 | import pandas as pd |
17 | 20 | import pytest |
18 | 21 |
|
@@ -98,6 +101,33 @@ def small_widget(small_bf_df): |
98 | 101 | yield TableWidget(small_bf_df) |
99 | 102 |
|
100 | 103 |
|
| 104 | +@pytest.fixture |
| 105 | +def unknown_row_count_widget(session): |
| 106 | + """Fixture to create a TableWidget with an unknown row count.""" |
| 107 | + from bigframes.core import blocks |
| 108 | + from bigframes.display import TableWidget |
| 109 | + |
| 110 | + # Create a small DataFrame with known content |
| 111 | + test_data = pd.DataFrame( |
| 112 | + { |
| 113 | + "id": [0, 1, 2, 3, 4], |
| 114 | + "value": ["row_0", "row_1", "row_2", "row_3", "row_4"], |
| 115 | + } |
| 116 | + ) |
| 117 | + bf_df = session.read_pandas(test_data) |
| 118 | + |
| 119 | + # Simulate a scenario where total_rows is not available from the iterator |
| 120 | + with mock.patch.object(bf_df, "_to_pandas_batches") as mock_batches: |
| 121 | + # We need to provide an iterator of DataFrames, not Series |
| 122 | + batches_iterator = iter([test_data]) |
| 123 | + mock_batches.return_value = blocks.PandasBatches( |
| 124 | + batches_iterator, total_rows=None |
| 125 | + ) |
| 126 | + with bf.option_context("display.repr_mode", "anywidget", "display.max_rows", 2): |
| 127 | + widget = TableWidget(bf_df) |
| 128 | + yield widget |
| 129 | + |
| 130 | + |
101 | 131 | @pytest.fixture(scope="module") |
102 | 132 | def empty_pandas_df() -> pd.DataFrame: |
103 | 133 | """Create an empty DataFrame for edge case testing.""" |
@@ -129,7 +159,7 @@ def execution_metadata(self) -> ExecutionMetadata: |
129 | 159 | return ExecutionMetadata() |
130 | 160 |
|
131 | 161 | @property |
132 | | - def schema(self): |
| 162 | + def schema(self) -> Any: |
133 | 163 | return schema |
134 | 164 |
|
135 | 165 | def batches(self) -> ResultsIterator: |
@@ -180,7 +210,9 @@ def test_widget_initialization_should_calculate_total_row_count( |
180 | 210 | def test_widget_initialization_should_set_default_pagination( |
181 | 211 | table_widget, |
182 | 212 | ): |
183 | | - """A TableWidget should initialize with page 0 and the correct page size.""" |
| 213 | + """ |
| 214 | + A TableWidget should initialize with page 0 and the correct page size. |
| 215 | + """ |
184 | 216 | # The `table_widget` fixture already creates the widget. |
185 | 217 | # Assert its state. |
186 | 218 | assert table_widget.page == 0 |
@@ -304,15 +336,20 @@ def test_widget_with_few_rows_should_display_all_rows(small_widget, small_pandas |
304 | 336 |
|
305 | 337 | def test_widget_with_few_rows_should_have_only_one_page(small_widget): |
306 | 338 | """ |
307 | | - Given a DataFrame smaller than the page size, the widget should |
308 | | - clamp page navigation, effectively having only one page. |
| 339 | + Given a DataFrame with a small number of rows, the widget should |
| 340 | + report the correct total row count and prevent navigation beyond |
| 341 | + the first page, ensuring the frontend correctly displays "Page 1 of 1". |
309 | 342 | """ |
| 343 | + # For a DataFrame with 2 rows and page_size 5 (from small_widget fixture), |
| 344 | + # the frontend should calculate 1 total page. |
| 345 | + assert small_widget.row_count == 2 |
| 346 | + |
| 347 | + # The widget should always be on page 0 for a single-page dataset. |
310 | 348 | assert small_widget.page == 0 |
311 | 349 |
|
312 | | - # Attempt to navigate past the end |
| 350 | + # Attempting to navigate to page 1 should be clamped back to page 0, |
| 351 | + # confirming that only one page is recognized by the backend. |
313 | 352 | small_widget.page = 1 |
314 | | - |
315 | | - # Should be clamped back to the only valid page |
316 | 353 | assert small_widget.page == 0 |
317 | 354 |
|
318 | 355 |
|
@@ -420,8 +457,10 @@ def test_navigation_after_page_size_change_should_use_new_size( |
420 | 457 |
|
421 | 458 | @pytest.mark.parametrize("invalid_size", [0, -5], ids=["zero", "negative"]) |
422 | 459 | def test_setting_invalid_page_size_should_be_ignored(table_widget, invalid_size: int): |
423 | | - """When the page size is set to an invalid number (<=0), the change should |
424 | | - be ignored.""" |
| 460 | + """ |
| 461 | + When the page size is set to an invalid number (<=0), the change should |
| 462 | + be ignored. |
| 463 | + """ |
425 | 464 | # Set the initial page to 2. |
426 | 465 | initial_size = table_widget.page_size |
427 | 466 | assert initial_size == 2 |
|
0 commit comments