Skip to content

Commit

Permalink
python 3.10 as min target, fix some socket type issues, other type is…
Browse files Browse the repository at this point in the history
…sues (#46)
  • Loading branch information
ogrodnek authored Sep 17, 2024
1 parent 2085400 commit 57ff9d6
Show file tree
Hide file tree
Showing 29 changed files with 1,173 additions and 1,652 deletions.
5 changes: 4 additions & 1 deletion examples/justfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
start:
PYVIEW_SECRET=`openssl rand -base64 16` poetry run uvicorn examples.app:app --reload
PYVIEW_SECRET=`openssl rand -base64 16` poetry run uvicorn examples.app:app --reload

type-check:
poetry run pyright
1,659 changes: 570 additions & 1,089 deletions examples/poetry.lock

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion examples/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,28 @@ readme = "README.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.9.16"
python = ">=3.10,<3.12"
pyview-web = {path = "..", develop = true}
aiohttp = "^3.10.2"
pillow = "^10.4.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
black = "24.3.0"
pyright = "1.1.380"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"


[tool.pyright]
exclude = [
".venv",
"examples",
"examples/.venv",
"**/vendor",
"**/node_modules",
"**/__pycache__",
]
14 changes: 8 additions & 6 deletions examples/views/checkboxes/checkboxes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, ConnectedLiveViewSocket, is_connected
from typing import TypedDict
import random

Expand Down Expand Up @@ -26,23 +26,25 @@ class CheckboxContext(TypedDict):


class CheckboxLiveView(LiveView[CheckboxContext]):
async def mount(self, socket: LiveViewSocket[CheckboxContext], _session):
socket.context = {"checkboxes": CHECKBOXES.checkboxes}
async def mount(self, socket: LiveViewSocket[CheckboxContext], session):
socket.context = CheckboxContext({"checkboxes": CHECKBOXES.checkboxes})

if socket.connected:
if is_connected(socket):
await socket.subscribe("checkboxes")
socket.schedule_info("random_toggle", 3)

async def handle_event(
self, event, payload, socket: LiveViewSocket[CheckboxContext]
self, event, payload, socket: ConnectedLiveViewSocket[CheckboxContext]
):
if event == "toggle":
index = int(payload["index"])
value = CHECKBOXES.toggle(index)

await socket.broadcast("checkboxes", {"index": index, "value": value})

async def handle_info(self, event, socket: LiveViewSocket[CheckboxContext]):
async def handle_info(
self, event, socket: ConnectedLiveViewSocket[CheckboxContext]
):
if event == "random_toggle":
index, value = CHECKBOXES.random_toggle()
await socket.broadcast("checkboxes", {"index": index, "value": value})
4 changes: 2 additions & 2 deletions examples/views/count/count.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class CountLiveView(LiveView[CountContext]):
to the backend to update state. We also snuck in handling URL params.
"""

async def mount(self, socket: LiveViewSocket[CountContext], _session):
socket.context = {"count": 0}
async def mount(self, socket: LiveViewSocket[CountContext], session):
socket.context = CountContext({"count": 0})

async def handle_event(self, event, payload, socket: LiveViewSocket[CountContext]):
if event == "decrement":
Expand Down
10 changes: 6 additions & 4 deletions examples/views/count_pubsub/count_pubsub.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, is_connected, ConnectedLiveViewSocket
from dataclasses import dataclass


Expand All @@ -21,12 +21,14 @@ class CountLiveViewPubSub(LiveView[Count]):
to see the state update in real time across all windows.
"""

async def mount(self, socket: LiveViewSocket[Count], _session):
async def mount(self, socket: LiveViewSocket[Count], session):
socket.context = Count()
if socket.connected:
if is_connected(socket):
await socket.subscribe("count")

async def handle_event(self, event, payload, socket: LiveViewSocket[Count]):
async def handle_event(
self, event, payload, socket: ConnectedLiveViewSocket[Count]
):
if event == "decrement":
socket.context.decrement()
if event == "increment":
Expand Down
2 changes: 2 additions & 0 deletions examples/views/fifa/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .fifa import FifaAudienceLiveView

__all__ = ["FifaAudienceLiveView"]
13 changes: 8 additions & 5 deletions examples/views/fifa/fifa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, ConnectedLiveViewSocket
from typing import TypedDict
from .data import FifaAudience, list_items, Paging

Expand All @@ -15,12 +15,15 @@ class FifaAudienceLiveView(LiveView[FifaContext]):
Table Pagination, and updating the URL from the backend.
"""

async def mount(self, socket: LiveViewSocket[FifaContext], _session):
async def mount(self, socket: LiveViewSocket[FifaContext], session):
paging = Paging(1, 10)
audiences = list_items(paging)
socket.context = {"audiences": audiences, "paging": paging}
socket.context = FifaContext(
{"audiences": list_items(paging), "paging": paging}
)

async def handle_event(self, event, payload, socket: LiveViewSocket[FifaContext]):
async def handle_event(
self, event, payload, socket: ConnectedLiveViewSocket[FifaContext]
):
paging = socket.context["paging"]
paging.perPage = int(payload["perPage"][0])
paging.page = 1
Expand Down
2 changes: 1 addition & 1 deletion examples/views/file_upload/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class FileUploadDemoLiveView(LiveView[FileUploadDemoContext]):
File upload example, with previews and progress bars.
"""

async def mount(self, socket: LiveViewSocket[FileUploadDemoContext], _session):
async def mount(self, socket: LiveViewSocket[FileUploadDemoContext], session):
config = socket.allow_upload(
"photos",
constraints=UploadConstraints(
Expand Down
7 changes: 1 addition & 6 deletions examples/views/form_validation/data.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
from __future__ import annotations
from pydantic import BaseModel, Field
from pydantic.types import constr

import datetime
import uuid
import random


plant_name = constr(min_length=3, max_length=20)


class Plant(BaseModel):
name: plant_name
name: str = Field(min_length=3, max_length=20)
watering_schedule_days: int = Field(ge=1, le=30)
last_watered: datetime.datetime = Field(default_factory=datetime.datetime.now)
id: str = Field(default_factory=lambda: uuid.uuid4().hex)
Expand Down
2 changes: 1 addition & 1 deletion examples/views/form_validation/plants.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class PlantsLiveView(LiveView[PlantsContext]):
More Form Validation
"""

async def mount(self, socket: LiveViewSocket[PlantsContext], _session):
async def mount(self, socket: LiveViewSocket[PlantsContext], session):
socket.context = PlantsContext(plants())

async def handle_event(self, event, payload, socket: LiveViewSocket[PlantsContext]):
Expand Down
2 changes: 1 addition & 1 deletion examples/views/js_commands/js_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ class JsCommandsLiveView(LiveView[dict]):
JS Commands let you update the DOM without making a trip to the server.
"""

async def mount(self, socket: LiveViewSocket[dict], _session):
async def mount(self, socket: LiveViewSocket[dict], session):
socket.context = {}
2 changes: 1 addition & 1 deletion examples/views/kanban/kanban.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class KanbanLiveView(LiveView[KanbanContext]):
(another hooks example showing integration w/ SortableJS).
"""

async def mount(self, socket: LiveViewSocket[KanbanContext], _session):
async def mount(self, socket: LiveViewSocket[KanbanContext], session):
socket.context = KanbanContext()

async def handle_event(self, event, payload, socket: LiveViewSocket[KanbanContext]):
Expand Down
8 changes: 5 additions & 3 deletions examples/views/maps/map.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, ConnectedLiveViewSocket
from dataclasses import dataclass
from .parks import national_parks
from pyview.vendor.ibis import filters
Expand All @@ -25,12 +25,14 @@ class MapLiveView(LiveView[MapContext]):
forth between the liveview and the JS library.
"""

async def mount(self, socket: LiveViewSocket[MapContext], _session):
async def mount(self, socket: LiveViewSocket[MapContext], session):
socket.context = MapContext(
parks=national_parks, selected_park_name=national_parks[0]["name"]
)

async def handle_event(self, event, payload, socket: LiveViewSocket[MapContext]):
async def handle_event(
self, event, payload, socket: ConnectedLiveViewSocket[MapContext]
):
print(event, payload)

park = [p for p in national_parks if p["name"] == payload["name"]][0]
Expand Down
2 changes: 1 addition & 1 deletion examples/views/podcasts/podcasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class PodcastLiveView(LiveView):
URL Parameters, client navigation updates, and dynamic page titles.
"""

async def mount(self, socket: LiveViewSocket[PodcastContext], _session):
async def mount(self, socket: LiveViewSocket[PodcastContext], session):
casts = podcasts()
socket.context = PodcastContext(casts[0], casts)

Expand Down
12 changes: 7 additions & 5 deletions examples/views/presence/presence.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, ConnectedLiveViewSocket, is_connected
from pyview.events import InfoEvent
from typing import Optional
from .avatars import Avatar, UserRepository
Expand Down Expand Up @@ -29,18 +29,20 @@ class PresenceLiveView(LiveView[PresenceContext]):
A simple example of presence tracking. Open this example in multiple windows.
"""

async def mount(self, socket: LiveViewSocket[PresenceContext], _session):
async def mount(self, socket: LiveViewSocket[PresenceContext], session):
socket.context = PresenceContext(connected=USER_REPO.all())

if socket.connected:
if is_connected(socket):
user = USER_REPO.register_avatar()
socket.context.current_user = user
socket.live_title = user.name

await socket.broadcast("presence", {"user": user, "action": "joined"})
await socket.subscribe("presence")

async def handle_info(self, event, socket: LiveViewSocket[PresenceContext]):
async def handle_info(
self, event, socket: ConnectedLiveViewSocket[PresenceContext]
):
if event.name == "presence":
socket.context.message = Message(
user=event.payload["user"], action=event.payload["action"]
Expand All @@ -51,7 +53,7 @@ async def handle_info(self, event, socket: LiveViewSocket[PresenceContext]):
if event.name == "clear_message":
socket.context.message = None

async def disconnect(self, socket: LiveViewSocket[PresenceContext]):
async def disconnect(self, socket: ConnectedLiveViewSocket[PresenceContext]):
USER_REPO.unregister_avatar(socket.context.current_user)

await socket.broadcast(
Expand Down
30 changes: 15 additions & 15 deletions examples/views/registration/registration.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import annotations
from pyview import LiveView, LiveViewSocket
from typing import TypedDict, Optional
from pydantic import BaseModel, validator
from pydantic.types import constr
from typing_extensions import Self

from pydantic import BaseModel, Field, model_validator
from pyview.changesets import change_set, ChangeSet
from pyview.vendor.ibis import filters
from markupsafe import Markup
Expand All @@ -27,20 +28,19 @@ def error_tag(changeset: ChangeSet, field_name: str) -> Markup:
).format(field_name=field_name, error=changeset.errors.get(field_name, ""))


checked_str = constr(min_length=3, max_length=20)


class Registration(BaseModel):
name: checked_str
email: checked_str
password: checked_str
password_confirmation: checked_str

@validator("password_confirmation")
def passwords_match(cls, v, values, **kwargs):
if "password" in values and v != values["password"]:
name: str = Field(min_length=3, max_length=20)
email: str = Field(min_length=3, max_length=20)
password: str = Field(min_length=3, max_length=20)
password_confirmation: str = Field(min_length=3, max_length=20)

@model_validator(mode="after")
def passwords_match(self) -> Self:
pw1 = self.password
pw2 = self.password_confirmation
if pw1 is not None and pw2 is not None and pw1 != pw2:
raise ValueError("passwords do not match")
return v
return self


class RegistrationContext(TypedDict):
Expand All @@ -54,7 +54,7 @@ class RegistrationLiveView(LiveView):
Form validation using Pydantic
"""

async def mount(self, socket: LiveViewSocket, _session):
async def mount(self, socket: LiveViewSocket, session):
socket.context = RegistrationContext(changeset=change_set(Registration))

async def handle_event(
Expand Down
6 changes: 3 additions & 3 deletions examples/views/status/status.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import psutil

from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, is_connected
from pyview.events import InfoEvent
from dataclasses import dataclass

Expand Down Expand Up @@ -44,9 +44,9 @@ class StatusLiveView(LiveView[StatusContext]):
Pushing updates from the backend to the client.
"""

async def mount(self, socket: LiveViewSocket[StatusContext], _session):
async def mount(self, socket: LiveViewSocket[StatusContext], session):
socket.context = StatusContext()
if socket.connected:
if is_connected(socket):
socket.schedule_info("refresh", 5)

async def handle_event(self, event, payload, socket: LiveViewSocket[StatusContext]):
Expand Down
2 changes: 1 addition & 1 deletion examples/views/volume/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class VolumeLiveView(LiveView[Volume]):
Keyboard events!
"""

async def mount(self, socket: LiveViewSocket[Volume], _session):
async def mount(self, socket: LiveViewSocket[Volume], session):
socket.context = Volume()

async def handle_event(self, event, payload, socket: LiveViewSocket[Volume]):
Expand Down
6 changes: 3 additions & 3 deletions examples/views/webping/webping.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyview import LiveView, LiveViewSocket
from pyview import LiveView, LiveViewSocket, is_connected
from dataclasses import dataclass, field
import datetime
from collections import deque
Expand Down Expand Up @@ -45,14 +45,14 @@ class PingLiveView(LiveView[PingContext]):
Another example of pushing updates from the backend to the client.
"""

async def mount(self, socket: LiveViewSocket[PingContext], _session):
async def mount(self, socket: LiveViewSocket[PingContext], session):
socket.context = PingContext(
[
PingSite("https://pyview.rocks"),
PingSite("https://examples.pyview.rocks"),
]
)
if socket.connected:
if is_connected(socket):
socket.schedule_info("ping", 10)
await self.handle_info(InfoEvent("ping"), socket)

Expand Down
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ docs:
docker:
docker build -t pyview .
docker run -p 8000:8000 pyview

type-check:
poetry run pyright
Loading

0 comments on commit 57ff9d6

Please sign in to comment.