From f508cad974c11119fc3d7e65bacd0c1d0c817caf Mon Sep 17 00:00:00 2001 From: Masahiro Wada Date: Thu, 28 Apr 2022 14:39:02 +0000 Subject: [PATCH] chore: Improve type hints --- alfort_dom/app.py | 6 ++-- examples/simple_counter/__init__.py | 2 +- examples/todomvc/__init__.py | 2 +- examples/todomvc/main.py | 2 +- pyproject.toml | 2 +- stubs/js/__init__.pyi | 44 +++++++++++++++++++++-- stubs/pyodide/__init__.pyi | 54 ++++++++++++++++++++++++++--- 7 files changed, 99 insertions(+), 13 deletions(-) diff --git a/alfort_dom/app.py b/alfort_dom/app.py index bbf36dc..70d84c1 100755 --- a/alfort_dom/app.py +++ b/alfort_dom/app.py @@ -10,7 +10,7 @@ PatchText, Props, ) -from js import document # type: ignore +from js import HTMLElement, document # type: ignore from pyodide import JsProxy, create_proxy, to_js # type: ignore S = TypeVar("S") @@ -18,12 +18,12 @@ class DomNode(Node, Generic[M]): - dom: JsProxy + dom: HTMLElement dispatch: Dispatch[M] handlers: dict[str, Callable[[Any], None]] listener: JsProxy - def __init__(self, dom: JsProxy, dispatch: Dispatch[M]) -> None: + def __init__(self, dom: HTMLElement, dispatch: Dispatch[M]) -> None: self.dom = dom self.dispatch = dispatch self.handlers = {} diff --git a/examples/simple_counter/__init__.py b/examples/simple_counter/__init__.py index a702e6b..be6f0ae 100755 --- a/examples/simple_counter/__init__.py +++ b/examples/simple_counter/__init__.py @@ -1,4 +1,4 @@ -import micropip +import micropip # type: ignore micropip.install("alfort") micropip.install("../dist/alfort_dom-0.0.0dev0-py3-none-any.whl") diff --git a/examples/todomvc/__init__.py b/examples/todomvc/__init__.py index a702e6b..be6f0ae 100755 --- a/examples/todomvc/__init__.py +++ b/examples/todomvc/__init__.py @@ -1,4 +1,4 @@ -import micropip +import micropip # type: ignore micropip.install("alfort") micropip.install("../dist/alfort_dom-0.0.0dev0-py3-none-any.whl") diff --git a/examples/todomvc/main.py b/examples/todomvc/main.py index 70efe32..5d31ba7 100755 --- a/examples/todomvc/main.py +++ b/examples/todomvc/main.py @@ -5,7 +5,7 @@ from alfort import Effect, Update from alfort.vdom import VDom, el -from js import document, localStorage +from js import document, localStorage # type: ignore from alfort_dom import AlfortDom diff --git a/pyproject.toml b/pyproject.toml index 1cd19a6..d8117d1 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ build-backend = "poetry.core.masonry.api" profile = "black" [tool.pyright] -include = ["alfort_dom"] +include = ["alfort_dom", "examples", "tests"] stubPath ="stubs" typeCheckingMode = "strict" reportMissingImports = false diff --git a/stubs/js/__init__.pyi b/stubs/js/__init__.pyi index dc1409c..fc3031a 100755 --- a/stubs/js/__init__.pyi +++ b/stubs/js/__init__.pyi @@ -1,3 +1,43 @@ -from typing import Any, TypeAlias +from typing import Protocol -document: TypeAlias = Any +from pyodide import JsProxy + +class Storage(Protocol): + def setItem(self, key: str, value: str) -> None: ... + def getItem(self, key: str) -> str: ... + +class CSSSTyleDeclaratin(Protocol): ... + +class HTMLElement(Protocol): + def appendChild(self, child: HTMLElement) -> None: ... + def insertBefore( + self, child: HTMLElement, reference: HTMLElement | None = ... + ) -> None: ... + def removeChild(self, child: HTMLElement) -> None: ... + def addEventListener(self, event_type: str, listener: JsProxy) -> None: ... + def removeEventListener(self, event_type: str, listener: JsProxy) -> None: ... + def setAttribute(self, name: str, value: str) -> None: ... + def removeAttribute(self, name: str) -> None: ... + def focus(self) -> None: ... + @property + def style(self) -> CSSSTyleDeclaratin: ... + @property + def nodeValue(self) -> str: ... + @nodeValue.setter + def nodeValue(self, text: str) -> None: ... + +class Text(HTMLElement): ... + +class Location(Protocol): + @property + def hash(self) -> str: ... + +class HTMLDocument(Protocol): + def createTextNode(self, text: str) -> Text: ... + def createElement(self, tag: str, props: JsProxy) -> HTMLElement: ... + def getElementById(self, id: str) -> HTMLElement: ... + @property + def location(self) -> Location: ... + +document: HTMLDocument +localStorage: Storage diff --git a/stubs/pyodide/__init__.pyi b/stubs/pyodide/__init__.pyi index b11b8ed..6ad32a8 100755 --- a/stubs/pyodide/__init__.pyi +++ b/stubs/pyodide/__init__.pyi @@ -1,6 +1,52 @@ -from typing import Any, TypeAlias +# derived from https://github.com/pyodide/pyodide/blob/main/src/py/_pyodide/_core_docs.py -JsProxy: TypeAlias = Any +from io import IOBase +from typing import Any, Callable, Iterable -def to_js(x: Any) -> Any: ... -def create_proxy(f: Any) -> Any: ... +class JsProxy(Any): + def object_entries(self) -> "JsProxy": ... + def object_keys(self) -> "JsProxy": ... + def object_values(self) -> "JsProxy": ... + def new(self, *args: Any, **kwargs: Any) -> "JsProxy": ... + def to_py( + self, + *, + depth: int = ..., + default_converter: Callable[ + ["JsProxy", Callable[["JsProxy"], Any], Callable[["JsProxy", Any], None]], + Any, + ] + | None = ..., + ) -> Any: ... + def then( + self, onfulfilled: Callable[[Any], Any], onrejected: Callable[[Any], Any] + ) -> "Promise": ... + def catch(self, onrejected: Callable[[Any], Any]) -> "Promise": ... + def finally_(self, onfinally: Callable[[Any], Any]) -> "Promise": ... + def assign(self, rhs: Any) -> None: ... + def assign_to(self, to: Any) -> None: ... + def to_memoryview(self) -> memoryview: ... + def to_bytes(self) -> bytes: ... + def to_file(self, file: IOBase) -> None: ... + def from_file(self, file: IOBase) -> None: ... + def _into_file(self, file: IOBase) -> None: ... + def to_string(self, encoding: str | None = ...) -> str: ... + +def create_once_callable(obj: Callable[[Any], Any]) -> JsProxy: ... +def create_proxy(obj: Any) -> JsProxy: ... +def to_js( + obj: Any, + *, + depth: int = ..., + pyproxies: JsProxy | None = ..., + create_pyproxies: bool = ..., + dict_converter: Callable[[Iterable[JsProxy]], JsProxy] | None = ..., + default_converter: Callable[ + [Any, Callable[[Any], JsProxy], Callable[[Any, JsProxy], None]], JsProxy + ] + | None = ..., +) -> JsProxy: ... + +class Promise(JsProxy): ... + +def destroy_proxies(pyproxies: JsProxy) -> None: ...