Skip to content

Commit 1a65c2e

Browse files
committed
Enforce strict type checks in the example apps
1 parent 8fa250a commit 1a65c2e

File tree

14 files changed

+135
-78
lines changed

14 files changed

+135
-78
lines changed

apps/dash/1_display_only.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
)
1616

1717
if __name__ == "__main__":
18-
app.run(debug=True)
18+
app.run(debug=True) # pyright: ignore[reportUnknownMemberType]

apps/dash/2_selected_rows.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
from dash import Dash, Input, Output, callback, html
1+
from typing import Optional
2+
3+
from dash import callback # pyright: ignore[reportUnknownVariableType]
4+
from dash import Dash, Input, Output, html
25

36
from itables.dash import ITable
47
from itables.sample_dfs import get_countries
@@ -25,9 +28,9 @@
2528
Output("output", "children"),
2629
Input("my_dataframe", "selected_rows"),
2730
)
28-
def show_selection(selected_rows):
31+
def show_selection(selected_rows: Optional[list[int]]) -> str:
2932
return f"Selected rows: {selected_rows}"
3033

3134

3235
if __name__ == "__main__":
33-
app.run(debug=True)
36+
app.run(debug=True) # pyright: ignore[reportUnknownMemberType]

apps/dash/3_update_table.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55
"""
66

77
import logging
8+
from typing import Any, Optional
89

9-
from dash import Dash, Input, Output, State, callback, callback_context, dcc, html
10+
from dash import callback # pyright: ignore[reportUnknownVariableType]
11+
from dash import Dash, Input, Output, State, callback_context, dcc, html
1012

11-
from itables.dash import ITable, ITableOutputs, updated_itable_outputs
13+
from itables import DTForITablesOptions, ITableOptions
14+
from itables.dash import (
15+
ITable,
16+
ITableOutputs,
17+
updated_itable_outputs,
18+
)
1219
from itables.sample_dfs import get_countries
1320

1421
logging.basicConfig(level=logging.INFO)
@@ -69,32 +76,44 @@
6976
State("my_dataframe", "dt_args"),
7077
],
7178
)
72-
def update_table(checklist, caption, selected_rows, dt_args):
79+
def update_table(
80+
checklist: Optional[list[str]],
81+
caption: Optional[str],
82+
selected_rows: Optional[list[int]],
83+
dt_args: Optional[DTForITablesOptions],
84+
) -> list[Any]:
7385
if checklist is None:
7486
checklist = []
7587

76-
kwargs = {}
88+
kwargs: ITableOptions = {}
7789

7890
# When df=None and when the dt_args don't change, the table is not updated
79-
if callback_context.triggered_id in {None, "checklist"}:
80-
kwargs["df"] = get_countries(html="HTML" in checklist)
91+
df = None
92+
if callback_context.triggered_id in { # pyright: ignore[reportUnknownMemberType]
93+
None,
94+
"checklist",
95+
}:
96+
df = get_countries(html="HTML" in checklist)
8197

8298
kwargs["select"] = "Select" in checklist
8399
if "Buttons" in checklist:
84100
kwargs["buttons"] = ["copyHtml5", "csvHtml5", "excelHtml5"]
85101

102+
if selected_rows is not None:
103+
kwargs["selected_rows"] = selected_rows
104+
86105
return updated_itable_outputs(
87-
caption=caption, selected_rows=selected_rows, current_dt_args=dt_args, **kwargs
106+
df, caption=caption, current_dt_args=dt_args, **kwargs
88107
)
89108

90109

91110
@callback(
92111
Output("output", "children"),
93112
Input("my_dataframe", "selected_rows"),
94113
)
95-
def show_selection(selected_rows):
114+
def show_selection(selected_rows: list[int]):
96115
return f"Selected rows: {selected_rows}"
97116

98117

99118
if __name__ == "__main__":
100-
app.run(debug=True)
119+
app.run(debug=True) # pyright: ignore[reportUnknownMemberType]

apps/shiny/itable_widget/app-core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424

2525

26-
def server(input, output, session):
26+
def server(input, output, session): # type: ignore
2727
@render_widget
2828
def my_table():
2929
"""
@@ -40,7 +40,7 @@ def _():
4040
to update the widget with the new inputs.
4141
"""
4242
# Get the new inputs
43-
df = dfs[input.table_selector()]
43+
df = dfs[input.table_selector()] # pyright: ignore[reportUnknownMemberType]
4444
selected_rows = list(range(0, len(df), 3))
4545

4646
# Update the widget
@@ -52,7 +52,7 @@ def _():
5252
ui.markdown("Selected rows")
5353

5454
@render.code
55-
def selected_rows():
55+
def selected_rows(): # pyright: ignore[reportUnusedFunction]
5656
"""
5757
Here we read the "selected_rows" attribute of the ITable widget
5858
"""
@@ -62,4 +62,4 @@ def selected_rows():
6262
return str(reactive_read(my_table.widget, "selected_rows"))
6363

6464

65-
app = App(app_ui, server)
65+
app = App(app_ui, server) # type: ignore

apps/shiny/itables_DT/app-core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
)
2424

2525

26-
def server(input, output, session):
26+
def server(input, output, session): # type: ignore
2727
@render.ui
28-
def my_table():
28+
def my_table(): # pyright: ignore[reportUnusedFunction]
2929
"""
3030
This function renders the table using "DT".
3131
"""
32-
df = dfs[input.table_selector()]
32+
df = dfs[input.table_selector()] # pyright: ignore[reportUnknownMemberType]
3333

3434
return ui.HTML(DT(df))
3535

3636

37-
app = App(app_ui, server)
37+
app = App(app_ui, server) # pyright: ignore[reportUnknownArgumentType]

apps/streamlit/itables_app.py

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
"""Run this app with: streamlit run apps/streamlit/itables_app.py"""
22

3-
from typing import Sequence, cast
3+
from typing import Optional, Sequence, cast
44

5-
import pyarrow
5+
import pyarrow # type: ignore
66
import streamlit as st
7+
from typing_extensions import Unpack
78

89
try:
910
from st_aggrid import AgGrid # type: ignore
1011
except ImportError as e:
1112
import_error = e
1213

1314
class AgGrid:
14-
def __init__(self, *args, **kwargs):
15+
def __init__(self, *args, **kwargs): # type: ignore
1516
raise import_error
1617

1718

1819
from streamlit.components.v1.components import MarshallComponentException
1920

20-
import itables.options as it_opt
21-
from itables.javascript import get_compact_style, get_expanded_classes
22-
from itables.sample_dfs import get_countries, get_dict_of_test_dfs
21+
import itables
2322
from itables.streamlit import interactive_table
2423

2524
st.set_page_config(
@@ -45,51 +44,49 @@ def __init__(self, *args, **kwargs):
4544
classes = st.sidebar.multiselect(
4645
"Classes",
4746
options=["display", "nowrap", "compact", "cell-border", "stripe"],
48-
default=get_expanded_classes(it_opt.classes),
47+
default=itables.javascript.get_expanded_classes(itables.options.classes),
4948
)
5049
buttons = st.sidebar.multiselect(
5150
"Buttons",
5251
options=["pageLength", "copyHtml5", "csvHtml5", "excelHtml5", "colvis"],
5352
default=["copyHtml5", "csvHtml5", "excelHtml5", "colvis"],
5453
)
5554

56-
style = st.sidebar.text_input("Style", value=get_compact_style(it_opt.style))
55+
style = st.sidebar.text_input(
56+
"Style", value=itables.javascript.get_compact_style(itables.options.style)
57+
)
5758

5859
render_with = st.sidebar.selectbox(
5960
"Render with", ["st.dataframe", "streamlit-aggrid", "itables"], index=2
6061
)
6162

6263
include_html = st.sidebar.checkbox("Include HTML")
63-
df = get_countries(html=include_html)
64+
df = itables.sample_dfs.get_countries(html=include_html)
6465

65-
it_args = {}
66+
it_args: itables.ITableOptions = {}
6667
if select:
6768
it_args["select"] = True
6869
it_args["selected_rows"] = [0, 1, 2, 100, 207]
69-
if classes != get_expanded_classes(it_opt.classes):
70+
if classes != itables.javascript.get_expanded_classes(itables.options.classes):
7071
it_args["classes"] = classes
71-
if style != it_opt.style:
72+
if style != itables.options.style:
7273
it_args["style"] = style
7374

7475
if buttons:
7576
it_args["buttons"] = buttons
7677

77-
78-
if caption:
79-
it_args = {"caption": caption, **it_args}
80-
8178
if render_with == "st.dataframe":
8279

83-
def render_table(df, key: str, **not_used): # type: ignore
84-
return st.dataframe(df, key=key)
80+
def render_table(df, key: str, caption: Optional[str], **not_used): # type: ignore
81+
return st.dataframe(df, key=key) # type: ignore
8582

8683
snippet = """st.dataframe(df)
8784
"""
8885

8986
elif render_with == "streamlit-aggrid":
9087

91-
def render_table(df, key: str, **not_used): # type: ignore
92-
return AgGrid(df, key=key)
88+
def render_table(df, key: str, caption: Optional[str], **not_used): # type: ignore
89+
return AgGrid(df, key=key) # type: ignore
9390

9491
snippet = """from st_aggrid import AgGrid
9592
@@ -102,12 +99,17 @@ def render_table(df, key: str, **not_used): # type: ignore
10299
]
103100
formatted_args = ",\n ".join(formatted_args)
104101

105-
def render_table(df, key, **it_args):
106-
return interactive_table(df, key=key, **it_args)
102+
def render_table(
103+
df: itables.DataFrameOrSeries,
104+
key: str,
105+
caption: Optional[str],
106+
**it_args: Unpack[itables.ITableOptions],
107+
):
108+
return interactive_table(df, key=key, caption=caption, **it_args)
107109

108110
snippet = f"""from itables.streamlit import interactive_table
109111
110-
interactive_table({formatted_args})
112+
interactive_table(df, caption='{caption}', {formatted_args})
111113
"""
112114

113115
st.markdown(
@@ -117,17 +119,17 @@ def render_table(df, key, **it_args):
117119
"""
118120
)
119121

120-
t = render_table(df, "my_table", **it_args)
122+
t = render_table(df, caption=caption, key="my_table", **it_args)
121123

122124
st.header("Table state")
123125
st.markdown(
124126
"""The value returned by `interactive_table` is
125127
a dict that contains the index of the selected rows:"""
126128
)
127-
st.write(t)
129+
st.write(t) # type: ignore
128130

129131
st.header("More sample dataframes")
130-
test_dfs = get_dict_of_test_dfs()
132+
test_dfs = itables.sample_dfs.get_dict_of_test_dfs()
131133
tabs = st.tabs(cast(Sequence[str], test_dfs.keys()))
132134

133135
for (name, df), tab in zip(test_dfs.items(), tabs):
@@ -140,7 +142,7 @@ def render_table(df, key, **it_args):
140142
# st.dataframe
141143
ValueError,
142144
# streamlit-aggrid
143-
pyarrow.lib.ArrowInvalid, # type: ignore
145+
pyarrow.lib.ArrowInvalid, # pyright: ignore[reportUnknownMemberType,reportAttributeAccessIssue]
144146
MarshallComponentException,
145-
) as e:
146-
st.warning(e)
147+
) as e: # pyright: ignore[reportUnknownVariableType]
148+
st.warning(e) # pyright: ignore[reportUnknownArgumentType]

docs/changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ITables ChangeLog
55
----------------------
66

77
**Added**
8-
- We now enforce `pyright` on the ITables documentation ([#395](https://github.com/mwouts/itables/issues/395))
8+
- We enforce strict `pyright` on the ITables documentation ([#395](https://github.com/mwouts/itables/issues/395)) and on the example apps ([#401](https://github.com/mwouts/itables/pull/401))
99

1010
**Changed**
1111
- The `warn_on_undocumented_option` option now defaults to `True` and only check the option names

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,5 @@ artifacts = [
126126

127127
[tool.pyright]
128128
typeCheckingMode = "standard"
129-
strict = ["docs"]
129+
ignore = ["apps/marimo"]
130+
strict = ["docs", "apps"]

src/itables/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
from itables import downsample, options, sample_dfs
22

33
from .javascript import init_notebook_mode, show, to_html_datatable
4-
from .typing import DataFrameOrSeries, ITableOptions, JavascriptCode, JavascriptFunction
4+
from .typing import (
5+
DataFrameOrSeries,
6+
DTForITablesOptions,
7+
ITableOptions,
8+
JavascriptCode,
9+
JavascriptFunction,
10+
)
511
from .version import __version__
612

713
__all__ = [
@@ -13,6 +19,7 @@
1319
"JavascriptFunction",
1420
"DataFrameOrSeries",
1521
"ITableOptions",
22+
"DTForITablesOptions",
1623
"options",
1724
"downsample",
1825
"sample_dfs",

src/itables/javascript.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ def get_itables_extension_arguments(
527527
df: Optional[DataFrameOrSeries],
528528
caption: Optional[str] = None,
529529
**kwargs: Unpack[ITableOptions],
530-
):
530+
) -> tuple[DTForITablesOptions, dict[str, Any]]:
531531
"""
532532
This function returns two dictionaries that are JSON
533533
serializable and can be passed to the ITable extensions.

0 commit comments

Comments
 (0)