Skip to content
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
2 changes: 1 addition & 1 deletion .site/gallery/peterhinch.html
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ <h2 class="console-label">Console output</h2>
import sys
from js import document, window

from displaydev import env_set
from boarddev import env_set

# Hinch demos use 320x240 (gallery default is 320x480).
env_set("PYDEVICES_WIDTH", 320)
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Board configs never own an `appdev.App`. `AutoDisplay` is imported from
Host defaults and env semantics:
[App and board config — `timer_async`](https://github.com/PyDevices/pydevices/blob/main/docs/app-and-board-config.md#timer_async).
Examples never read this variable — only library `board_config` and harnesses
that call `displaydev.env_set`.
that call `boarddev.env_set`.

**Preferred for agents / matrix:** pass wrapper `--timer-async` (the example
kit does this). That uses `env_set` and works for Windows PE under WSL without
Expand Down
2 changes: 1 addition & 1 deletion lib/examples/car_cluster/car_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

input_map.capture_virtual_devices()

from displaydev import env_bool, env_get, env_set
from boarddev import env_bool, env_get, env_set

env_set("PYDEVICES_WIDTH", "1024")
env_set("PYDEVICES_HEIGHT", "512")
Expand Down
2 changes: 1 addition & 1 deletion lib/examples/drum_machine/drum_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
# board_config reads these; a board's board_config ignores them (its display
# is a fixed size), so an app can ask for its designed resolution without
# ever fighting real hardware.
from displaydev import env_set
from boarddev import env_set

env_set("PYDEVICES_WIDTH", 720)
env_set("PYDEVICES_HEIGHT", 480)
Expand Down
4 changes: 2 additions & 2 deletions lib/examples/google_photos/google_photos.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

Join Wi-Fi before running on a microcontroller. Optional desktop panel size:
edit ``_WIDTH`` / ``_HEIGHT`` / ``_SCALE`` below (applied via
``displaydev.env_set`` before ``board_config`` is imported; never on MCUs).
``boarddev.env_set`` before ``board_config`` is imported; never on MCUs).
"""

import sys
Expand All @@ -46,7 +46,7 @@
if _PKG not in sys.path:
sys.path.insert(0, _PKG)

from displaydev import env_set
from boarddev import env_set

# Local desktop test panel -- change these and re-run. Must stay above board_config.
_WIDTH = None
Expand Down
2 changes: 1 addition & 1 deletion lib/examples/lv_test_timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import time

from board_config import display_drv
from displaydev import env_get
from boarddev import env_get
import multimer

# Optional logical orientation for LVGL (hw MADCTL/SDL/PG or software rotate).
Expand Down
4 changes: 2 additions & 2 deletions lib/examples/roku_remote/roku_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
on a microcontroller. Optional fixed target: ``ROKU_HOST`` in :mod:`roku_engine`.

Desktop panel size: edit ``_WIDTH`` / ``_HEIGHT`` / ``_SCALE`` below. Those are
applied via ``displaydev.env_set`` before any front end imports ``board_config``.
applied via ``boarddev.env_set`` before any front end imports ``board_config``.
Leave ``_SCALE`` as ``None`` to keep the desktop ``AutoDisplay`` default
(autoscale still fits the window).
"""
Expand All @@ -49,7 +49,7 @@
if _PKG not in sys.path:
sys.path.insert(0, _PKG)

from displaydev import env_set
from boarddev import env_set

# Local desktop test panel — change these and re-run. Must stay above board_config.
# Match LilyGO T-HMI (ST7789 I80): 240x320. Never apply on MCU boards (panel
Expand Down
2 changes: 1 addition & 1 deletion lib/examples/roku_remote/roku_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def sim_reason():
(missing ``socket`` or no station IPv4 / Wi‑Fi).
"""
try:
from displaydev import env_bool, env_get
from boarddev import env_bool, env_get
except ImportError:
if _is_pyscript():
return "pyscript"
Expand Down
2 changes: 1 addition & 1 deletion lib/examples/spectrum/spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import sys

from displaydev import env_get, env_set
from boarddev import env_get, env_set

# A desktop board_config reads these; a real board's display ignores them.
if env_get("PYDEVICES_WIDTH") is None:
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/ps_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def parse_names(raw):

def set_board_defaults():
"""Set the gallery's browser defaults without importing board_config."""
from displaydev import env_set
from boarddev import env_set

env_set("PYDEVICES_WIDTH", BOARD_WIDTH)
env_set("PYDEVICES_HEIGHT", BOARD_HEIGHT)
Expand Down Expand Up @@ -337,7 +337,7 @@ def _ensure_board_config(mip_mod, status=None, url_base=None):
def ensure_board_config(status=None):
"""Ensure browser ``board_config`` (desktop package) is importable.

Call after ``utils.path`` and before ``from displaydev import env_set`` /
Call after ``utils.path`` and before ``from boarddev import env_set`` /
importing demos or setup modules that ``import board_config``. The desktop
package pulls in ``displaydev`` (not frozen in the gallery wasm). Set size
overrides with ``env_set`` after this returns and before the first
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import sys

from displaydev import env_get
from boarddev import env_get

_DESKTOP = frozenset(("linux", "darwin", "win32", "unix", "webassembly", "emscripten"))

Expand Down
11 changes: 6 additions & 5 deletions scripts/gen_package_pyi.sh
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
#!/usr/bin/env bash
# Regenerate IDE type stubs for three core PyDevices packages into tools/typings/.
# Regenerate IDE type stubs for the core PyDevices packages into tools/typings/.
#
# Usage:
# ./scripts/gen_package_pyi.sh
# ./scripts/gen_package_pyi.sh --help
#
# Requires the repo-root .venv (mypy / stubgen). Output is committed under
# tools/typings/{displaydev,appdev,multimer}/ for stubPath.
# tools/typings/{displaydev,appdev,multimer}/ and the single-module stubs
# (events, keys, boarddev) for stubPath.

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

PACKAGES=(displaydev appdev multimer)
MODULES=(events keys)
MODULES=(events keys boarddev)
OUT=tools/typings
STUBGEN="${ROOT}/.venv/bin/stubgen"
PYTHON="${ROOT}/.venv/bin/python"
Expand All @@ -24,7 +25,7 @@ usage() {
Usage: ./scripts/gen_package_pyi.sh

Regenerate mypy stubgen .pyi trees for displaydev, appdev,
multimer, events, and keys into tools/typings/ (Pylance / pyright stubPath).
multimer, events, keys, and boarddev into tools/typings/ (Pylance / pyright stubPath).

(source is gitignored; public API is pygraphics.FrameBuffer).
EOF
Expand Down Expand Up @@ -66,7 +67,7 @@ fi
echo "Running stubgen → ${OUT}/ …"
"$STUBGEN" --ignore-errors -o "$OUT" \
-p displaydev -p appdev -p multimer \
-m events -m keys
-m events -m keys -m boarddev

# Gitignored generated module; public FrameBuffer lives in _framebuf_plus.

Expand Down
2 changes: 1 addition & 1 deletion tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ see [Windows PE under WSL](#windows-pe-under-wsl).
`micropython.exe` and `python.exe` are Windows PE binaries launched from WSL.
They cannot read Linux-exported environment variables. The kit therefore
forwards only values that must cross that boundary via wrapper argv +
`displaydev.env_set` (notably `--timer-async` / `--multimer-source`).
`boarddev.env_set` (notably `--timer-async` / `--multimer-source`).

**Do not forward `SDL_VIDEODRIVER` / `SDL_AUDIODRIVER` to PE.** Unix cells stay
headless from the shell `SDL_*=dummy` export; PE keeps a real Windows video
Expand Down
2 changes: 1 addition & 1 deletion tools/example_test_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ def main(argv=None):
# Apply --env / --timer-async via env_set before board_config / SDL init
# (deadline hook and the example both import board_config).
try:
from displaydev import env_set
from boarddev import env_set
except Exception:
env_set = None
if env_set is not None:
Expand Down
4 changes: 2 additions & 2 deletions tools/multimer_source_preload.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
launched from WSL cannot see exported ones, so a sweep across interpreters sets
``MULTIMER_SOURCE`` inside the child, makes multimer choose its source at once,
and checks that the one it got is the one asked for. Other ``--env`` values go
through ``displaydev.env_set()``. The target script keeps the real command line
through ``boarddev.env_set()``. The target script keeps the real command line
(``sys.argv`` is read-only on CircuitPython), so scripts must locate their own
flags anywhere in ``sys.argv`` rather than at a fixed index.

Expand Down Expand Up @@ -118,7 +118,7 @@ def main(argv):
_bootstrap_path(source_workspace)

if env:
from displaydev import env_set
from boarddev import env_set

for name, value in env:
env_set(name, value)
Expand Down
2 changes: 1 addition & 1 deletion tools/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _positive_scale(value):


def _apply_display_overrides(resolution, scale):
from displaydev import env_set
from boarddev import env_set

if resolution is not None:
width, height = resolution
Expand Down
36 changes: 25 additions & 11 deletions tools/typings/appdev/app.pyi
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import events
import keys
import types
from .devices import Encoder as Encoder, HostEvents as HostEvents, Joystick as Joystick, Keypad as Keypad, Touch as Touch
from .devices import ENCODER as ENCODER, Encoder as Encoder, HOST as HOST, HostEvents as HostEvents, JOYSTICK as JOYSTICK, Joystick as Joystick, KEYPAD as KEYPAD, Keypad as Keypad, POINTER as POINTER, Touch as Touch
from _typeshed import Incomplete

DEFAULT_REFRESH_MS: int
SERVICE_TICK_MS: int

class _TimerSubscription:
def __init__(self, app, entry) -> None: ...
def cancel(self) -> None: ...

class _RefreshClaim:
def __init__(self, app) -> None: ...
def release(self) -> None: ...

class _PollingClaim:
def __init__(self, app) -> None: ...
def release(self) -> None: ...

class _RefreshPaused:
def __init__(self, app) -> None: ...
def __enter__(self): ...
def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None): ...

class App:
events = events
keys = keys
HOST = HOST
POINTER = POINTER
ENCODER = ENCODER
KEYPAD = KEYPAD
JOYSTICK = JOYSTICK
@classmethod
def current(cls): ...
devices: Incomplete
Expand All @@ -27,9 +36,9 @@ class App:
keypad_dev: Incomplete
encoder_dev: Incomplete
joystick_dev: Incomplete
def __init__(self, board_config=None, *, displays=None, host_read=None, touch_read=None, touch_rotation_table=None, refresh_period=None, timer_async=None) -> None: ...
def __init__(self, board_config=None, *, displays=None, host_read=None, touch_read=None, touch_rotation_table=None, refresh_period=None) -> None: ...
@property
def timer_async(self): ...
def strategy(self): ...
@property
def displays(self): ...
@property
Expand All @@ -40,6 +49,8 @@ class App:
def before_quit(self): ...
@before_quit.setter
def before_quit(self, value) -> None: ...
@property
def timers(self): ...
def add_display(self, drv): ...
def remove_display(self, drv) -> None: ...
def add_touch(self, read, *, display=None, rotation_table=None): ...
Expand All @@ -50,13 +61,16 @@ class App:
def unregister(self, dev) -> None: ...
def on(self, event_type_or_list, callback=None): ...
def off(self, event_type_or_list, callback) -> None: ...
def every(self, ms, callback=None): ...
def stop_timer(self) -> None: ...
def every(self, ms=None, callback=None, *, period=None, name=None): ...
def on_tick(self, callback, period=..., **_ignored): ...
def stop_timers(self) -> None: ...
stop_timer = stop_timers
def pause_refresh(self): ...
def resume_refresh(self) -> None: ...
def refresh_paused(self): ...
def pause_polling(self): ...
def resume_polling(self) -> None: ...
def poll(self): ...
def arm_async_refresh(self) -> None: ...
def run(self, tick_ms=...) -> None: ...
def run(self, tick_ms=...): ...
def run_async(self, coro_or_fn): ...
def request_quit(self, code=None) -> None: ...
10 changes: 10 additions & 0 deletions tools/typings/boarddev.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
def bind_lazy(ns, peripherals_mod): ...
def audio_provider(): ...
def pcm_out(format=None, **kwargs): ...
def pcm_in(format=None, **kwargs): ...
def audio_out(format=None, **kwargs): ...
def env_set(name, value) -> None: ...
def env_bool(name, default: bool = False): ...
def env_get(name, default=None): ...
def env_int(name, default: int = 0): ...
def env_float(name, default: float = 0.0): ...
57 changes: 47 additions & 10 deletions tools/typings/displaydev/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,29 +1,61 @@
from _typeshed import Incomplete

__all__ = ['DisplayDriver', 'alloc_buffer', 'byteswap', 'capabilities', 'color332', 'color565', 'color565_swapped', 'color_rgb', 'desktop_work_area', 'env_bool', 'env_float', 'env_get', 'env_int', 'env_set', 'fit_scale_to_desktop', 'notify_board_config_scale_override']
__all__ = ['DisplayDriver', 'alloc_buffer', 'byteswap', 'capabilities', 'color332', 'color565', 'color565_swapped', 'color_rgb']

byteswap: Incomplete

def env_set(name, value) -> None: ...
def env_bool(name, default: bool = False): ...
def env_get(name, default=None): ...
def env_int(name, default: int = 0): ...
def env_float(name, default: float = 0.0): ...
def desktop_work_area(display_index: int = 0): ...
def fit_scale_to_desktop(width, height, scale, desktop_w, desktop_h, *, margin=..., chrome_w: int = 0, chrome_h: int = 0): ...
def notify_board_config_scale_override(driver_name, requested, fitted, *, quiet: bool = False) -> None: ...
def capabilities(): ...
def alloc_buffer(size): ...
def color565(r, g=None, b=None): ...
def color565_swapped(r, g: int = 0, b: int = 0): ...
def color332(r, g, b): ...
def color_rgb(color): ...

class FrameClock:
name: Incomplete
count: int
last: Incomplete
def __init__(self, period_ms, name=None) -> None: ...
@property
def period_ms(self): ...
@period_ms.setter
def period_ms(self, value) -> None: ...
@property
def running(self): ...
def subscribe(self, fn): ...
def unsubscribe(self, fn) -> None: ...
def stop(self) -> None: ...

class _FpsMeter:
now: Incomplete
diff: Incomplete
def __init__(self, now, diff) -> None: ...
mark: Incomplete
win_us: int
win_frames: int
win_present: int
win_flushes: int
win_pixels: int
frame_us: int
frame_max: int
last_fps: Incomplete
seconds: float
frames: int
present_us: float
flushes: int
pixels: int
def reset(self) -> None: ...
def frame(self, t, dt) -> None: ...
def flush(self, t, dt, pixels) -> None: ...
def snapshot(self): ...

class DisplayDriver:
needs_refresh: bool
requires_async_timer: bool
refresh_period_ms: int
share_framebuffer: bool
quit_chord: Incomplete
@property
def frame_clock(self): ...
def framebuffers(self) -> None: ...
byteswap: Incomplete
touch_scale: float
Expand Down Expand Up @@ -67,6 +99,11 @@ class DisplayDriver:
def vsa_area(self): ...
@property
def bfa_area(self): ...
def measure_fps(self, on: bool = True): ...
def frame_done(self) -> None: ...
def fps(self): ...
def fps_reset(self) -> None: ...
def fps_print(self, seconds: int = 5) -> None: ...
def vscrdef(self, tfa: int, vsa: int, bfa: int) -> None: ...
def vscsad(self, vssa: int | None = None) -> int: ...
@property
Expand Down
Loading
Loading