diff --git a/docs/timing-design.md b/docs/timing-design.md index 28837028..e4a64a4f 100644 --- a/docs/timing-design.md +++ b/docs/timing-design.md @@ -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 diff --git a/docs/timing-hardware-tests.md b/docs/timing-hardware-tests.md index f8613e35..13102d20 100644 --- a/docs/timing-hardware-tests.md +++ b/docs/timing-hardware-tests.md @@ -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). diff --git a/lib/multimer/_hostloop.py b/lib/multimer/_hostloop.py index 3db7205b..dec03ba1 100644 --- a/lib/multimer/_hostloop.py +++ b/lib/multimer/_hostloop.py @@ -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 () @@ -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 diff --git a/tests/test_hostloop.py b/tests/test_hostloop.py index fb589b2d..3d6e7785 100644 --- a/tests/test_hostloop.py +++ b/tests/test_hostloop.py @@ -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: ())