Skip to content

Commit fb077be

Browse files
authored
Various typing fixes/improvements; setup pyright to run on CI (#168)
1 parent 72d16f5 commit fb077be

9 files changed

+39
-44
lines changed

.github/workflows/pytest.yaml

+5-3
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ jobs:
4343
- name: Install
4444
run: |
4545
make install
46+
47+
- name: pyright
48+
run: |
49+
make pyright
50+
4651
#- name: Run unit tests
4752
# run: |
4853
# make test
49-
# - name: pyright, flake8, black and isort
50-
# run: |
51-
# make check
5254

5355
deploy:
5456
name: "Deploy to PyPI"

Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ install: dist ## install the package to the active Python's site-packages
9090
python3 -m pip install dist/shinywidgets*.whl
9191

9292
pyright: ## type check with pyright
93-
pyright --pythonversion=3.7
9493
pyright --pythonversion=3.11
9594

9695
check: pyright lint ## check code quality with pyright, flake8, black and isort

pyrightconfig.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"ignore": ["examples", "sandbox", "build", "dist", "typings"],
3-
"typeCheckingMode": "strict",
3+
"typeCheckingMode": "basic",
44
"reportPrivateUsage": "none",
5+
"reportUnknownMemberType": "none",
6+
"reportMissingTypeStubs": "none"
57
}

setup.cfg

+7
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ dev =
5050
isort>=5.11.2
5151
pyright>=1.1.284
5252
wheel
53+
altair
54+
bokeh
55+
jupyter_bokeh
56+
plotly
57+
pydeck
58+
59+
5360

5461
[options.packages.find]
5562
include = shinywidgets, shinywidgets.*

shinywidgets/_as_widget.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Optional
22

3-
from ipywidgets.widgets.widget import Widget # pyright: ignore[reportMissingTypeStubs]
3+
from ipywidgets.widgets.widget import Widget
44

55
from ._dependencies import widget_pkg
66

@@ -35,7 +35,7 @@ def as_widget(x: object) -> Widget:
3535

3636
def as_widget_altair(x: object) -> Optional[Widget]:
3737
try:
38-
from altair import JupyterChart # pyright: ignore[reportMissingTypeStubs]
38+
from altair import JupyterChart
3939
except ImportError:
4040
raise RuntimeError(
4141
"Failed to import altair.JupyterChart (do you need to pip install -U altair?)"
@@ -46,7 +46,7 @@ def as_widget_altair(x: object) -> Optional[Widget]:
4646

4747
def as_widget_bokeh(x: object) -> Optional[Widget]:
4848
try:
49-
from jupyter_bokeh import BokehModel # pyright: ignore[reportMissingTypeStubs]
49+
from jupyter_bokeh import BokehModel
5050
except ImportError:
5151
raise ImportError(
5252
"Install the jupyter_bokeh package to use bokeh with shinywidgets."
@@ -55,19 +55,19 @@ def as_widget_bokeh(x: object) -> Optional[Widget]:
5555
# TODO: ideally we'd do this in set_layout_defaults() but doing
5656
# `BokehModel(x)._model.sizing_mode = "stretch_both"`
5757
# there, but that doesn't seem to work??
58-
from bokeh.plotting import figure # pyright: ignore[reportMissingTypeStubs]
58+
from bokeh.plotting import figure
5959

60-
if isinstance(x, figure): # type: ignore
61-
x.sizing_mode = "stretch_both" # pyright: ignore[reportGeneralTypeIssues]
60+
if isinstance(x, figure):
61+
x.sizing_mode = "stretch_both" # type: ignore
6262

6363
return BokehModel(x) # type: ignore
6464

6565

6666
def as_widget_plotly(x: object) -> Optional[Widget]:
6767
# Don't need a try import here since this won't be called unless x is a plotly object
68-
import plotly.graph_objects as go # pyright: ignore[reportMissingTypeStubs]
68+
import plotly.graph_objects as go
6969

70-
if not isinstance(x, go.Figure): # type: ignore
70+
if not isinstance(x, go.Figure):
7171
raise TypeError(
7272
f"Don't know how to coerce {x} into a plotly.graph_objects.FigureWidget object."
7373
)
@@ -93,7 +93,7 @@ def as_widget_pydeck(x: object) -> Optional[Widget]:
9393
"For more, see https://github.com/visgl/deck.gl/pull/8854"
9494
)
9595

96-
return res # type: ignore
96+
return res
9797

9898

9999
AS_WIDGET_MAP = {

shinywidgets/_dependencies.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
import packaging.version
1111
from htmltools import HTMLDependency, tags
1212
from htmltools._core import HTMLDependencySource
13-
from ipywidgets._version import (
14-
__html_manager_version__, # pyright: ignore[reportUnknownVariableType]
15-
)
1613
from ipywidgets.widgets.domwidget import DOMWidget
1714
from ipywidgets.widgets.widget import Widget
18-
from jupyter_core.paths import jupyter_path # type: ignore
15+
from jupyter_core.paths import jupyter_path
1916
from shiny import Session, ui
2017

2118
from . import __version__

shinywidgets/_render_widget.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
from htmltools import Tag
66

77
if TYPE_CHECKING:
8-
from altair import JupyterChart # pyright: ignore[reportMissingTypeStubs]
9-
from jupyter_bokeh import BokehModel # pyright: ignore[reportMissingTypeStubs]
10-
from plotly.graph_objects import ( # pyright: ignore[reportMissingTypeStubs]
11-
FigureWidget,
12-
)
13-
from pydeck.widget import DeckGLWidget # pyright: ignore[reportMissingTypeStubs]
8+
from altair import JupyterChart
9+
from jupyter_bokeh import BokehModel
10+
from plotly.graph_objects import FigureWidget
11+
from pydeck.widget import DeckGLWidget
1412
else:
1513
JupyterChart = BokehModel = FigureWidget = DeckGLWidget = object
1614

shinywidgets/_render_widget_base.py

+5-15
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,10 @@
44
from typing import Generic, Optional, Tuple, TypeVar, cast
55

66
from htmltools import Tag
7-
from ipywidgets.widgets import ( # pyright: ignore[reportMissingTypeStubs]
8-
DOMWidget,
9-
Layout,
10-
Widget,
11-
)
7+
from ipywidgets.widgets import DOMWidget, Layout, Widget
128
from shiny import req
139
from shiny.reactive._core import Context, get_current_context
1410
from shiny.render.renderer import Jsonifiable, Renderer, ValueFn
15-
from traitlets import Unicode
1611

1712
from ._as_widget import as_widget
1813
from ._dependencies import widget_pkg
@@ -94,12 +89,7 @@ async def render(self) -> Jsonifiable | None:
9489
return None
9590

9691
return {
97-
"model_id": str(
98-
cast(
99-
Unicode,
100-
widget.model_id, # pyright: ignore[reportUnknownMemberType]
101-
)
102-
),
92+
"model_id": str(widget.model_id),
10393
"fill": fill,
10494
}
10595

@@ -168,7 +158,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]:
168158
# If the ipywidget Layout() height is set to something other than "auto", then
169159
# don't do filling layout https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Layout.html
170160
if isinstance(layout, Layout):
171-
if layout.height is not None and layout.height != "auto": # type: ignore
161+
if layout.height is not None and layout.height != "auto":
172162
fill = False
173163

174164
pkg = widget_pkg(widget)
@@ -178,7 +168,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]:
178168
from plotly.graph_objs import Layout as PlotlyLayout # pyright: ignore
179169

180170
if isinstance(layout, PlotlyLayout):
181-
if layout.height is not None: # pyright: ignore[reportUnknownMemberType]
171+
if layout.height is not None:
182172
fill = False
183173
# Default margins are also way too big
184174
layout.template.layout.margin = dict( # pyright: ignore
@@ -196,7 +186,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]:
196186
# container since it'll be contained within the Layout() container, which has a
197187
# full-fledged sizing API.
198188
if pkg == "altair":
199-
import altair as alt # pyright: ignore[reportMissingTypeStubs]
189+
import altair as alt
200190

201191
# Since as_widget() has already happened, we only need to handle JupyterChart
202192
if isinstance(widget, alt.JupyterChart):

shinywidgets/_shinywidgets.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from uuid import uuid4
99
from weakref import WeakSet
1010

11-
import ipywidgets # pyright: ignore[reportMissingTypeStubs]
11+
import ipywidgets
1212

1313
from ._render_widget import render_widget
1414

@@ -110,7 +110,7 @@ def _cleanup_session_state():
110110
if getattr(w, "_model_id", None) is None:
111111
w._model_id = uuid4().hex
112112

113-
id = cast(str, w._model_id) # pyright: ignore[reportUnknownMemberType]
113+
id = cast(str, w._model_id)
114114

115115
# Initialize the comm...this will also send the initial state of the widget
116116
with widget_comm_patch():
@@ -162,7 +162,7 @@ def _cleanup_session_state():
162162

163163
# Dictionary of all "active" widgets (ipywidgets automatically adds to this dictionary as
164164
# new widgets are created, but they won't get removed until the widget is explictly closed)
165-
WIDGET_INSTANCE_MAP = cast(dict[str, Widget], Widget.widgets) # pyright: ignore[reportUnknownMemberType]
165+
WIDGET_INSTANCE_MAP = cast(dict[str, Widget], Widget.widgets)
166166

167167
# --------------------------------------
168168
# Reactivity
@@ -197,7 +197,7 @@ def reactive_depend(
197197
names = [names]
198198

199199
for name in names:
200-
if not widget.has_trait(name): # pyright: ignore[reportUnknownMemberType]
200+
if not widget.has_trait(name):
201201
raise ValueError(
202202
f"The '{name}' attribute of {widget.__class__.__name__} is not a "
203203
"widget trait, and so it's not possible to reactively read it. "
@@ -253,7 +253,7 @@ def widget_comm_patch():
253253
Widget.comm.klass = comm_klass
254254

255255

256-
def is_traitlet_instance(x: object) -> "TypeGuard[Instance]":
256+
def is_traitlet_instance(x: object) -> "TypeGuard[Instance[Any]]":
257257
try:
258258
from traitlets.traitlets import Instance
259259
except ImportError:

0 commit comments

Comments
 (0)