Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various typing fixes/improvements; setup pyright to run on CI #168

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"ignore": ["examples", "sandbox", "build", "dist", "typings"],
"typeCheckingMode": "strict",
"typeCheckingMode": "basic",
"reportPrivateUsage": "none",
"reportUnknownMemberType": "none",
"reportMissingTypeStubs": "none"
}
7 changes: 7 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down
18 changes: 9 additions & 9 deletions shinywidgets/_as_widget.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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?)"
Expand All @@ -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."
Expand All @@ -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."
)
Expand All @@ -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 = {
Expand Down
5 changes: 1 addition & 4 deletions shinywidgets/_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
10 changes: 4 additions & 6 deletions shinywidgets/_render_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
20 changes: 5 additions & 15 deletions shinywidgets/_render_widget_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
}

Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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):
Expand Down
10 changes: 5 additions & 5 deletions shinywidgets/_shinywidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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. "
Expand Down Expand Up @@ -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:
Expand Down
Loading