diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index d9e54bc..94611a8 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -43,12 +43,14 @@ jobs: - name: Install run: | make install + + - name: pyright + run: | + make pyright + #- name: Run unit tests # run: | # make test - # - name: pyright, flake8, black and isort - # run: | - # make check deploy: name: "Deploy to PyPI" diff --git a/Makefile b/Makefile index 5f7b657..82bfc31 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,6 @@ install: dist ## install the package to the active Python's site-packages python3 -m pip install dist/shinywidgets*.whl pyright: ## type check with pyright - pyright --pythonversion=3.7 pyright --pythonversion=3.11 check: pyright lint ## check code quality with pyright, flake8, black and isort diff --git a/pyrightconfig.json b/pyrightconfig.json index 662f0b7..d9393d1 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -1,5 +1,7 @@ { "ignore": ["examples", "sandbox", "build", "dist", "typings"], - "typeCheckingMode": "strict", + "typeCheckingMode": "basic", "reportPrivateUsage": "none", + "reportUnknownMemberType": "none", + "reportMissingTypeStubs": "none" } diff --git a/setup.cfg b/setup.cfg index 09bab71..fcaa3d5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,13 @@ dev = isort>=5.11.2 pyright>=1.1.284 wheel + altair + bokeh + jupyter_bokeh + plotly + pydeck + + [options.packages.find] include = shinywidgets, shinywidgets.* diff --git a/shinywidgets/_as_widget.py b/shinywidgets/_as_widget.py index de073c4..54b35c7 100644 --- a/shinywidgets/_as_widget.py +++ b/shinywidgets/_as_widget.py @@ -1,6 +1,6 @@ from typing import Optional -from ipywidgets.widgets.widget import Widget # pyright: ignore[reportMissingTypeStubs] +from ipywidgets.widgets.widget import Widget from ._dependencies import widget_pkg @@ -35,7 +35,7 @@ def as_widget(x: object) -> Widget: def as_widget_altair(x: object) -> Optional[Widget]: try: - from altair import JupyterChart # pyright: ignore[reportMissingTypeStubs] + from altair import JupyterChart except ImportError: raise RuntimeError( "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]: def as_widget_bokeh(x: object) -> Optional[Widget]: try: - from jupyter_bokeh import BokehModel # pyright: ignore[reportMissingTypeStubs] + from jupyter_bokeh import BokehModel except ImportError: raise ImportError( "Install the jupyter_bokeh package to use bokeh with shinywidgets." @@ -55,19 +55,19 @@ def as_widget_bokeh(x: object) -> Optional[Widget]: # TODO: ideally we'd do this in set_layout_defaults() but doing # `BokehModel(x)._model.sizing_mode = "stretch_both"` # there, but that doesn't seem to work?? - from bokeh.plotting import figure # pyright: ignore[reportMissingTypeStubs] + from bokeh.plotting import figure - if isinstance(x, figure): # type: ignore - x.sizing_mode = "stretch_both" # pyright: ignore[reportGeneralTypeIssues] + if isinstance(x, figure): + x.sizing_mode = "stretch_both" # type: ignore return BokehModel(x) # type: ignore def as_widget_plotly(x: object) -> Optional[Widget]: # Don't need a try import here since this won't be called unless x is a plotly object - import plotly.graph_objects as go # pyright: ignore[reportMissingTypeStubs] + import plotly.graph_objects as go - if not isinstance(x, go.Figure): # type: ignore + if not isinstance(x, go.Figure): raise TypeError( f"Don't know how to coerce {x} into a plotly.graph_objects.FigureWidget object." ) @@ -93,7 +93,7 @@ def as_widget_pydeck(x: object) -> Optional[Widget]: "For more, see https://github.com/visgl/deck.gl/pull/8854" ) - return res # type: ignore + return res AS_WIDGET_MAP = { diff --git a/shinywidgets/_dependencies.py b/shinywidgets/_dependencies.py index e2fc054..b35aea7 100644 --- a/shinywidgets/_dependencies.py +++ b/shinywidgets/_dependencies.py @@ -10,12 +10,9 @@ import packaging.version from htmltools import HTMLDependency, tags from htmltools._core import HTMLDependencySource -from ipywidgets._version import ( - __html_manager_version__, # pyright: ignore[reportUnknownVariableType] -) from ipywidgets.widgets.domwidget import DOMWidget from ipywidgets.widgets.widget import Widget -from jupyter_core.paths import jupyter_path # type: ignore +from jupyter_core.paths import jupyter_path from shiny import Session, ui from . import __version__ diff --git a/shinywidgets/_render_widget.py b/shinywidgets/_render_widget.py index 8522038..41e177d 100644 --- a/shinywidgets/_render_widget.py +++ b/shinywidgets/_render_widget.py @@ -5,12 +5,10 @@ from htmltools import Tag if TYPE_CHECKING: - from altair import JupyterChart # pyright: ignore[reportMissingTypeStubs] - from jupyter_bokeh import BokehModel # pyright: ignore[reportMissingTypeStubs] - from plotly.graph_objects import ( # pyright: ignore[reportMissingTypeStubs] - FigureWidget, - ) - from pydeck.widget import DeckGLWidget # pyright: ignore[reportMissingTypeStubs] + from altair import JupyterChart + from jupyter_bokeh import BokehModel + from plotly.graph_objects import FigureWidget + from pydeck.widget import DeckGLWidget else: JupyterChart = BokehModel = FigureWidget = DeckGLWidget = object diff --git a/shinywidgets/_render_widget_base.py b/shinywidgets/_render_widget_base.py index 1977547..bb5a345 100644 --- a/shinywidgets/_render_widget_base.py +++ b/shinywidgets/_render_widget_base.py @@ -4,15 +4,10 @@ from typing import Generic, Optional, Tuple, TypeVar, cast from htmltools import Tag -from ipywidgets.widgets import ( # pyright: ignore[reportMissingTypeStubs] - DOMWidget, - Layout, - Widget, -) +from ipywidgets.widgets import DOMWidget, Layout, Widget from shiny import req from shiny.reactive._core import Context, get_current_context from shiny.render.renderer import Jsonifiable, Renderer, ValueFn -from traitlets import Unicode from ._as_widget import as_widget from ._dependencies import widget_pkg @@ -94,12 +89,7 @@ async def render(self) -> Jsonifiable | None: return None return { - "model_id": str( - cast( - Unicode, - widget.model_id, # pyright: ignore[reportUnknownMemberType] - ) - ), + "model_id": str(widget.model_id), "fill": fill, } @@ -168,7 +158,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]: # If the ipywidget Layout() height is set to something other than "auto", then # don't do filling layout https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Layout.html if isinstance(layout, Layout): - if layout.height is not None and layout.height != "auto": # type: ignore + if layout.height is not None and layout.height != "auto": fill = False pkg = widget_pkg(widget) @@ -178,7 +168,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]: from plotly.graph_objs import Layout as PlotlyLayout # pyright: ignore if isinstance(layout, PlotlyLayout): - if layout.height is not None: # pyright: ignore[reportUnknownMemberType] + if layout.height is not None: fill = False # Default margins are also way too big layout.template.layout.margin = dict( # pyright: ignore @@ -196,7 +186,7 @@ def set_layout_defaults(widget: Widget) -> Tuple[Widget, bool]: # container since it'll be contained within the Layout() container, which has a # full-fledged sizing API. if pkg == "altair": - import altair as alt # pyright: ignore[reportMissingTypeStubs] + import altair as alt # Since as_widget() has already happened, we only need to handle JupyterChart if isinstance(widget, alt.JupyterChart): diff --git a/shinywidgets/_shinywidgets.py b/shinywidgets/_shinywidgets.py index 1e711ce..021881e 100644 --- a/shinywidgets/_shinywidgets.py +++ b/shinywidgets/_shinywidgets.py @@ -8,7 +8,7 @@ from uuid import uuid4 from weakref import WeakSet -import ipywidgets # pyright: ignore[reportMissingTypeStubs] +import ipywidgets from ._render_widget import render_widget @@ -110,7 +110,7 @@ def _cleanup_session_state(): if getattr(w, "_model_id", None) is None: w._model_id = uuid4().hex - id = cast(str, w._model_id) # pyright: ignore[reportUnknownMemberType] + id = cast(str, w._model_id) # Initialize the comm...this will also send the initial state of the widget with widget_comm_patch(): @@ -162,7 +162,7 @@ def _cleanup_session_state(): # Dictionary of all "active" widgets (ipywidgets automatically adds to this dictionary as # new widgets are created, but they won't get removed until the widget is explictly closed) -WIDGET_INSTANCE_MAP = cast(dict[str, Widget], Widget.widgets) # pyright: ignore[reportUnknownMemberType] +WIDGET_INSTANCE_MAP = cast(dict[str, Widget], Widget.widgets) # -------------------------------------- # Reactivity @@ -197,7 +197,7 @@ def reactive_depend( names = [names] for name in names: - if not widget.has_trait(name): # pyright: ignore[reportUnknownMemberType] + if not widget.has_trait(name): raise ValueError( f"The '{name}' attribute of {widget.__class__.__name__} is not a " "widget trait, and so it's not possible to reactively read it. " @@ -253,7 +253,7 @@ def widget_comm_patch(): Widget.comm.klass = comm_klass -def is_traitlet_instance(x: object) -> "TypeGuard[Instance]": +def is_traitlet_instance(x: object) -> "TypeGuard[Instance[Any]]": try: from traitlets.traitlets import Instance except ImportError: