|
18 | 18 | import pandas as pd |
19 | 19 | import pytest |
20 | 20 |
|
21 | | -import bigframes.dataframe |
| 21 | +import bigframes |
22 | 22 |
|
23 | 23 | # Skip if anywidget/traitlets not installed, though they should be in the dev env |
24 | 24 | pytest.importorskip("anywidget") |
25 | 25 | pytest.importorskip("traitlets") |
26 | 26 |
|
27 | 27 |
|
28 | | -class TestTableWidget: |
29 | | - def test_navigation_to_invalid_page_resets_to_valid_page_without_deadlock(self): |
30 | | - """ |
31 | | - Verifies that navigating to an invalid page resets to a valid page without deadlock. |
| 28 | +def test_navigation_to_invalid_page_resets_to_valid_page_without_deadlock(): |
| 29 | + """ |
| 30 | + Given a widget on a page beyond available data, when navigating, |
| 31 | + then it should reset to the last valid page without deadlock. |
| 32 | + """ |
| 33 | + from bigframes.display.anywidget import TableWidget |
32 | 34 |
|
33 | | - This behavior relies on _set_table_html releasing the lock before updating self.page, |
34 | | - preventing re-entrancy issues where the observer triggers a new update on the same thread. |
35 | | - """ |
36 | | - from bigframes.display import TableWidget |
| 35 | + mock_df = mock.create_autospec(bigframes.dataframe.DataFrame, instance=True) |
| 36 | + mock_df.columns = ["col1"] |
| 37 | + mock_df.dtypes = {"col1": "object"} |
37 | 38 |
|
38 | | - mock_df = mock.create_autospec(bigframes.dataframe.DataFrame, instance=True) |
39 | | - mock_df.columns = ["col1"] |
40 | | - mock_df.dtypes = {"col1": "object"} |
| 39 | + mock_block = mock.Mock() |
| 40 | + mock_block.has_index = False |
| 41 | + mock_df._block = mock_block |
41 | 42 |
|
42 | | - mock_block = mock.Mock() |
43 | | - mock_block.has_index = False |
44 | | - mock_df._block = mock_block |
45 | | - |
46 | | - # We mock _initial_load to avoid complex setup |
47 | | - with mock.patch.object(TableWidget, "_initial_load"): |
| 43 | + # We mock _initial_load to avoid complex setup |
| 44 | + with mock.patch.object(TableWidget, "_initial_load"): |
| 45 | + with bigframes.option_context( |
| 46 | + "display.repr_mode", "anywidget", "display.max_rows", 10 |
| 47 | + ): |
48 | 48 | widget = TableWidget(mock_df) |
49 | 49 |
|
50 | | - # Simulate "loaded data but unknown total rows" state |
51 | | - widget.page_size = 10 |
52 | | - widget.row_count = None |
53 | | - widget._all_data_loaded = True |
| 50 | + # Simulate "loaded data but unknown total rows" state |
| 51 | + widget.page_size = 10 |
| 52 | + widget.row_count = None |
| 53 | + widget._all_data_loaded = True |
54 | 54 |
|
55 | | - # Populate cache with 1 page of data (10 rows). Page 0 is valid, page 1+ are invalid. |
56 | | - widget._cached_batches = [pd.DataFrame({"col1": range(10)})] |
| 55 | + # Populate cache with 1 page of data (10 rows). Page 0 is valid, page 1+ are invalid. |
| 56 | + widget._cached_batches = [pd.DataFrame({"col1": range(10)})] |
57 | 57 |
|
58 | | - # Mark initial load as complete so observers fire |
59 | | - widget._initial_load_complete = True |
| 58 | + # Mark initial load as complete so observers fire |
| 59 | + widget._initial_load_complete = True |
60 | 60 |
|
61 | | - # Setup timeout to fail fast if deadlock occurs |
62 | | - def handler(signum, frame): |
63 | | - raise TimeoutError("Deadlock detected!") |
| 61 | + # Setup timeout to fail fast if deadlock occurs |
| 62 | + def handler(signum, frame): |
| 63 | + raise TimeoutError("Deadlock detected!") |
64 | 64 |
|
65 | | - signal.signal(signal.SIGALRM, handler) |
66 | | - signal.alarm(2) # 2 seconds timeout |
| 65 | + signal.signal(signal.SIGALRM, handler) |
| 66 | + signal.alarm(2) # 2 seconds timeout |
67 | 67 |
|
68 | | - try: |
69 | | - # Trigger navigation to page 5 (invalid), which should reset to page 0 |
70 | | - widget.page = 5 |
| 68 | + try: |
| 69 | + # Trigger navigation to page 5 (invalid), which should reset to page 0 |
| 70 | + widget.page = 5 |
71 | 71 |
|
72 | | - assert widget.page == 0 |
| 72 | + assert widget.page == 0 |
73 | 73 |
|
74 | | - finally: |
75 | | - signal.alarm(0) |
| 74 | + finally: |
| 75 | + signal.alarm(0) |
0 commit comments