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
21 changes: 15 additions & 6 deletions docs/timing-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -539,12 +539,21 @@ runs, not the cloud's; the cloud's container was 4 cores, the bench is 8.
delivery, as designed: 84 callbacks a second through `sleep_ms` with the
main thread idle, 0 while it spins, and `report()` answers over the serial
console. Same mechanism as the unix build in Phase 4.
- **Pending:** the LVGL launcher and drum machine on the phone (kept the
screen at brightness 1 for photosensitivity and stayed within the P4/phone
windows); the mechanism they would exercise, main-thread bytecode
delivery, is what the Android numbers already prove. PyScript/Pyodide
pages (the `asyncio` source, the same code the Jupyter proof runs) and an
`mp-wasm` rebuild carrying the bridge fix remain the two browser follow-ups.
- **Follow-ups (2026-09-26, after 0.6.1).** The browser checks are done.
Under PyScript/Pyodide, `lv_test_timer` shows `Timer: asyncio/idle` and
its seconds count and arc keep moving. An `mp-wasm` rebuild carrying the
bridge fix passes `wasm_host.mjs` under node, runs `lv_test_timer` in the
direct gallery host (`Timer: wasm/idle`), brings all 20 portal heroes
up with no errors, and passes a new workbench timers test. The runtime
that shipped with 0.6.1 threw `function signature mismatch` on every
timer callback in all three places. The vendored runtimes are in
PyDevices.github.io#9 and workbench#1, and the runner's
`MULTIMER_BACKEND` line is dropped with its recipes moved to 0.6.1 in
android-runner#24.
**Still pending:** the LVGL launcher and drum machine visual pass on the
phone. An APK from android-runner#24 builds and installs, but the S21's
secure lock screen kept the activity from ever drawing, so nothing was
seen. The desktop launcher on 0.6.1 was checked under Xvfb instead.
- **Phase 6, the deliverables (here).** The four repository series were
exported with `git format-patch` from branches on each repository's
`origin/main`, then re-applied with `git am` onto a fresh checkout of each
Expand Down
8 changes: 6 additions & 2 deletions docs/timing-hardware-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,9 @@ per-plan record of pass/fail and anything found.
mechanism it exercises is what the numbers already prove. `--install-apk`
installs the 0.2.3 release; a prior local-key debug build must be uninstalled
first.
- **Not run:** PyScript/Pyodide in a browser (the `asyncio` source, proven via
Jupyter in the cloud) and an `mp-wasm` rebuild carrying the bridge fix.
- **Browsers, 2026-09-26 — pass.** PyScript/Pyodide: `lv_test_timer` reports
`Timer: asyncio/idle` and animates. The `mp-wasm` rebuild with the bridge fix
runs the same demo in the direct gallery host (`Timer: wasm/idle`, 298 → 495
deliveries in a second), all 20 portal heroes, and workbench's simulator. The
runtime that shipped with 0.6.1 threw `function signature mismatch` on every
timer callback. Details: [timing-design.md](timing-design.md#ledger).
8 changes: 7 additions & 1 deletion lib/multimer/_hostloop.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ def _cmdline_tokens():
return _win32_cmdline()
except Exception:
pass
# CPython 3.10+ keeps the flags itself (macOS has no /proc).
argv = getattr(sys, "orig_argv", None)
if argv:
return tuple(argv)
return ()


Expand Down Expand Up @@ -183,7 +187,9 @@ def interactive():
flags = getattr(sys, "flags", None)
if getattr(flags, "interactive", 0):
return True
return _main_file() is None
# ``python -c`` has no ``__main__.__file__`` either, but no prompt
# follows it: it is a batch entry, like ``-m``.
return _main_file() is None and not batch()
if _mcu() and _impl() == "circuitpython":
# CircuitPython cannot tell code.py from the REPL, and delivers
# nothing in the background either way: the exit hook is the only
Expand Down
13 changes: 13 additions & 0 deletions tests/test_hostloop.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ def test_circuitpython_firmware_is_never_interactive(self):
self._fake_impl("circuitpython", "rp2")
self.assertFalse(_hostloop.interactive())

def test_cpython_dash_c_is_not_interactive(self):
"""``python -c`` has no ``__main__.__file__``, and no prompt follows it."""
self._patch(_hostloop, "_impl", lambda: "cpython")
self._patch(_hostloop, "_main_file", lambda: None)
self._patch(_hostloop, "_cmdline_tokens", lambda: ("python", "-c", "import app"))
self.assertFalse(_hostloop.interactive())

def test_cpython_bare_prompt_is_interactive(self):
self._patch(_hostloop, "_impl", lambda: "cpython")
self._patch(_hostloop, "_main_file", lambda: None)
self._patch(_hostloop, "_cmdline_tokens", lambda: ("python",))
self.assertTrue(_hostloop.interactive())

def test_circuitpython_firmware_takes_the_exit_hook(self):
self._fake_impl("circuitpython", "rp2")
self._patch(_hostloop, "_cmdline_tokens", lambda: ())
Expand Down
Loading