Skip to content

Commit 1b3d2a8

Browse files
committed
Only subset the selected data if the index row exists!
Fixes #1351
1 parent 8abf8eb commit 1b3d2a8

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

shiny/render/_data_frame.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,11 +494,13 @@ def _subset_data_view(selected: bool) -> pd.DataFrame:
494494
# Use a `set` for faster lookups
495495
selected_row_indices_set = set(cell_selection["rows"])
496496

497-
# Subset the data view indices to only include the selected rows
497+
# Subset the data view indices to only include the selected rows that are in the data
498498
data_view_indices = [
499499
index
500500
for index in data_view_indices
501501
if index in selected_row_indices_set
502+
and index
503+
in data.index # pyright: ignore[reportUnknownMemberType]
502504
]
503505

504506
return data.iloc[data_view_indices]
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import pandas as pd
2+
3+
from shiny import App, Inputs, reactive, render, ui
4+
5+
app_ui = ui.page_fluid(
6+
ui.markdown(
7+
"""
8+
## Description
9+
10+
When you add a row, click on it and click the clear button you get:
11+
12+
13+
"""
14+
),
15+
ui.input_action_button("add_row", "Add row"),
16+
ui.input_action_button("clear_table", "Clear table"),
17+
ui.output_text_verbatim("number_of_selected_rows"),
18+
ui.output_data_frame("df1"),
19+
)
20+
21+
22+
def server(input: Inputs):
23+
df = reactive.Value(pd.DataFrame(columns=["A", "B"]))
24+
25+
@render.data_frame
26+
def df1():
27+
return render.DataGrid(df(), selection_mode="rows")
28+
29+
@reactive.effect
30+
@reactive.event(input.add_row)
31+
def _():
32+
old_df = df()
33+
new_df = pd.concat( # pyright: ignore[reportUnknownMemberType]
34+
[old_df, pd.DataFrame([[1, 2]], columns=["A", "B"])]
35+
)
36+
df.set(new_df)
37+
38+
@render.text
39+
def number_of_selected_rows():
40+
df_selected = df1.data_view(selected=True)
41+
return f"Selected rows: {len(df_selected)}"
42+
43+
@reactive.effect
44+
@reactive.event(input.clear_table)
45+
def _():
46+
df.set(pd.DataFrame(columns=["A", "B"]))
47+
48+
49+
app = App(app_ui, server)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from __future__ import annotations
2+
3+
from conftest import ShinyAppProc
4+
from controls import InputActionButton, OutputDataFrame, OutputTextVerbatim
5+
from playwright.sync_api import Page
6+
7+
8+
def test_row_selection(page: Page, local_app: ShinyAppProc) -> None:
9+
page.goto(local_app.url)
10+
11+
df = OutputDataFrame(page, "df1")
12+
add_row = InputActionButton(page, "add_row")
13+
clear_table = InputActionButton(page, "clear_table")
14+
selected_rows = OutputTextVerbatim(page, "number_of_selected_rows")
15+
16+
df.expect_n_row(0)
17+
selected_rows.expect_value("Selected rows: 0")
18+
19+
add_row.click()
20+
21+
df.expect_n_row(1)
22+
selected_rows.expect_value("Selected rows: 0")
23+
24+
df.cell_locator(0, 0).click()
25+
df.select_rows([0])
26+
27+
df.expect_n_row(1)
28+
selected_rows.expect_value("Selected rows: 1")
29+
30+
clear_table.click()
31+
selected_rows.expect_value("Selected rows: 0")
32+
33+
bad_error_lines = [line for line in local_app.stderr._lines if "INFO:" not in line]
34+
assert len(bad_error_lines) == 0, bad_error_lines

0 commit comments

Comments
 (0)