Skip to content

Commit

Permalink
feat: use alfort v0.1.9
Browse files Browse the repository at this point in the history
  • Loading branch information
ar90n committed Oct 11, 2022
1 parent e24f8fc commit 828c88a
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 3 deletions.
2 changes: 1 addition & 1 deletion alfort_dom/dom.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def dom_effect(
) -> Callable[[Callable[[HTMLElement, Dispatch[M]], None]], Effect[M]]:
def _wrapper(fun: Callable[[HTMLElement, Dispatch[M]], None]) -> Effect[M]:
@functools.wraps(fun)
def _wrapped(dispatch: Dispatch[M]) -> None:
async def _wrapped(dispatch: Dispatch[M]) -> None:
def _f(_: Any) -> None:
dom = document.getElementById(dom_id)
fun(dom, dispatch)
Expand Down
1 change: 1 addition & 0 deletions docs/examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<div>
<ul>
<li> <a href="./simple_counter/"> simple_counter </a></li>
<li> <a href="./simple_api/"> simple_api </a></li>
<li><a href="./todomvc/"> todomvc </a></li>
<li><a href="./key_and_mouse_events/"> key_and_mouse_events </a></li>
</ul>
Expand Down
29 changes: 29 additions & 0 deletions docs/examples/simple_api/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Alfort-Dom • Simple Counter</title>
</head>
<body>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
></script>
<script type="text/javascript">
async function main() {
let pyodide = await loadPyodide();
await pyodide.loadPackage("micropip");

const initScript = await fetch("./pkg_install.py");
const initScriptText = await initScript.text();
await pyodide.runPythonAsync(initScriptText);

const script = await fetch("./main.py");
const scriptText = await script.text();
await pyodide.runPythonAsync(scriptText);
}
main();
</script>
<div id="root"></div>
</body>
</html>
157 changes: 157 additions & 0 deletions docs/examples/simple_api/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
from dataclasses import dataclass
from typing import Any, Callable, Coroutine, TypeAlias
from urllib.parse import ParseResult as URL
from urllib.parse import urlparse

import pyodide.http
from alfort import Dispatch, Effect
from alfort.vdom import VDom, el

from alfort_dom import AlfortDom


@dataclass(frozen=True)
class Photo:
album_id: int
id: int
title: str
url: URL
thumbnail_url: URL


@dataclass(frozen=True)
class State:
album_id: int
is_fetching: bool
photos: list[Photo]


@dataclass(frozen=True)
class SelectAlbum:
alumb_id: int


@dataclass(frozen=True)
class ReceivePhotos:
photos: list[Photo]


Msg: TypeAlias = SelectAlbum | ReceivePhotos


async def fetch_photos(album_id: int) -> list[Photo]:
url = f"https://jsonplaceholder.typicode.com/albums/{album_id}/photos"
res = await pyodide.http.pyfetch(url)
return [
Photo(
album_id=obj["albumId"],
id=obj["id"],
title=obj["title"],
url=urlparse(obj["url"]),
thumbnail_url=urlparse(obj["thumbnailUrl"]),
)
for obj in await res.json()
]


def title(text: str) -> VDom:
return el("h1", {}, [text])


def album_selector(album_id: int) -> VDom:
def _on_change(e: Any) -> Msg:
return SelectAlbum(e.target.value)

return el(
"div",
{"style": {"margin": "15px"}},
[
el("label", {"style": {"margin-right": "8px"}}, ["Album ID"]),
el(
"select",
{
"onchange": _on_change,
},
[
el(
"option",
{
"value": i,
"selected": album_id == i,
},
[str(i)],
)
for i in range(15)
],
),
],
)


def album_photos(photos: list[Photo]) -> VDom:
photo_elms: list[VDom] = []
for photo in photos:
photo_elms.append(
el(
"img",
{"src": photo.thumbnail_url.geturl(), "style": {"margin": "3px"}},
[],
)
)

return el("div", {"style": {"width": "75%", "line-height": "0px"}}, photo_elms)


def fetching_dialog() -> VDom:
return el("div", {}, ["Loading..."])


def view(state: State) -> VDom:
return el(
"div",
{
"style": {
"display": "flex",
"justify-content": "center",
"align-items": "center",
"flex-flow": "column",
}
},
[
title("Simple Photo Album"),
album_selector(state.album_id),
fetching_dialog() if state.is_fetching else album_photos(state.photos),
],
)


def create_fetch_effect(
album_id: int,
) -> Callable[[Dispatch[Msg]], Coroutine[None, None, Any]]:
async def _fetch(dispatch: Dispatch[Msg]) -> None:
recv_photos = await fetch_photos(album_id=album_id)
dispatch(ReceivePhotos(recv_photos))

return _fetch


def init() -> tuple[State, list[Effect[Msg]]]:
return (State(album_id=1, is_fetching=True, photos=[]), [create_fetch_effect(1)])


def update(msg: Msg, state: State) -> tuple[State, list[Effect[Msg]]]:
match msg:
case SelectAlbum(album_id):
state = State(album_id=album_id, is_fetching=True, photos=[])
return (state, [create_fetch_effect(album_id=album_id)])
case ReceivePhotos(photos):
state = State(album_id=state.album_id, is_fetching=False, photos=photos)
return (state, [])


app = AlfortDom[State, Msg](
init=init,
view=view,
update=update,
)
app.main(root="root")
7 changes: 7 additions & 0 deletions docs/examples/simple_api/pkg_install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import micropip # type: ignore # noqa: F401

try:
# try to use development version
await micropip.install("../dist/alfort_dom-0.0.0.dev0-py3-none-any.whl") # type: ignore # noqa: F704
except ValueError:
await micropip.install("alfort-dom") # type: ignore # noqa: F704
6 changes: 5 additions & 1 deletion docs/examples/todomvc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ def with_local_storage(update: Update["Msg", "Model"]) -> Update["Msg", "Model"]
@functools.wraps(update)
def _update(msg: Msg, model: Model) -> tuple[Model, list[Effect[Msg]]]:
model, effects = update(msg, model)
return model, [lambda _: save_model(model), *effects]

async def _save_model(_: Dispatch[Msg]) -> None:
save_model(model)

return model, [_save_model, *effects]

return _update

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ include = ["alfort_dom/py.typed"]

[tool.poetry.dependencies]
python = "^3.10"
alfort = "^0.1.8"
alfort = "^0.1.9"

[tool.poetry.group.dev.dependencies]
poethepoet = "^0.13.1"
Expand Down
37 changes: 37 additions & 0 deletions stubs/pyodide/http/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# derived from https://github.com/pyodide/pyodide/blob/main/src/py/pyodide/http.py

from io import StringIO
from typing import Any, BinaryIO, TextIO

from .. import JsProxy

def open_url(url: str) -> StringIO: ...

class FetchResponse:
def __init__(self, url: str, js_response: JsProxy) -> None: ...
@property
def body_used(self) -> bool: ...
@property
def ok(self) -> bool: ...
@property
def redirected(self) -> bool: ...
@property
def status(self) -> str: ...
@property
def status_text(self) -> str: ...
@property
def type(self) -> str: ...
@property
def url(self) -> str: ...
def clone(self) -> "FetchResponse": ...
async def buffer(self) -> JsProxy: ...
async def string(self) -> str: ...
async def json(self, **kwargs: Any) -> Any: ...
async def memoryview(self) -> memoryview: ...
async def bytes(self) -> bytes: ...
async def _into_file(self, f: TextIO | BinaryIO) -> None: ...
async def unpack_archive(
self, *, extract_dir: str | None, format: str | None
) -> None: ...

async def pyfetch(url: str, **kwargs: Any) -> FetchResponse: ...

0 comments on commit 828c88a

Please sign in to comment.