fix(wake): fail closed on unsupported openWakeWord/tflite-runtime Python versions - #94197
vadelma-agent wants to merge 5 commits into
Conversation
8347b9f to
213ae58
Compare
Keep the released openWakeWord 0.6.0 path on the Python versions where its tflite-runtime wheels exist, and fail closed before lazy installation elsewhere. Preserve the existing macOS bridge and document the separate project-level Python ceiling. Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
Keep openWakeWord selectable on Darwin while failing closed for the Linux tflite-runtime path on Python 3.12+. Add resolver, bridge, lazy-install, and supported CPython 3.11 import coverage without changing [all]. Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
Parameterize the macOS ARM64 bridge regression across CPython 3.12 and 3.13, exercising the production unsupported-runtime gate in both cases. Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
The Linux-only tflite-runtime compatibility boundary must not exclude openWakeWord from Windows CPython 3.12+ installs. Preserve the ONNX path and add positive Windows marker and engine coverage alongside the Linux negative and Darwin bridge tests. Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
213ae58 to
f4a5748
Compare
Exemplary fail-closed design: the shared predicate (
Minor: the autouse fixture monkeypatching |
What does this PR do?
Fixes a real dependency-resolution failure in the optional
wakeextra andadds an honest, fail-closed compatibility boundary instead of a silent
broken state.
Bug (observed behavior).
openwakeword==0.6.0requirestflite-runtimeon Linux, and
tflite-runtime==2.14.0on PyPI only ships CPython 3.11wheels for Linux x86_64/aarch64/armv7l — there is no
cp312/cp313/cp314wheel and no sdist. Before this PR:
The same failure occurs on Python 3.12 and 3.13 on Linux. It is a wheel
availability failure, not a
[all]regression —wakeis intentionallyexcluded from
[all], so ordinaryuv sync --extra all --extra devinstalls are unaffected — but any Linux user on Python 3.12+ who explicitly
opts into
wake(or runs--all-extras) hits an opaque resolver error withno remediation. It also silently blocks upgrading the project's own
requires-pythonceiling toward 3.14 whilewake's Linux dependency chainstays capped at 3.11.
Fix. Add an explicit, platform-aware compatibility boundary:
wakeextra'sopenwakeword==0.6.0pin now carries the markerpython_version < '3.12' or sys_platform != 'linux', matching exactlywhere the locked
tflite-runtimewheels (Linux) and the existingmacOS bridge / Windows ONNX path actually work.
tools/lazy_deps.pygets a single sharedopenwakeword_supported()/openwakeword_unsupported_reason()predicate used by both the lazyinstaller and the wake runtime, so the resolver marker can't drift from
first-use behavior.
(
check_wake_word_requirements) and engine construction(
_OpenWakeWordEngine.__init__) fail closed before any lazypip/uvinstall is attempted, with an actionable message: use Python3.11, pick another configured wake provider, or wait for the upstream
LiteRT-based release.
ai-edge-litertbridge is preserved andregression-tested on simulated CPython 3.12 and 3.13 — this PR does not
touch or replace that code path.
TFLite boundary does not remove
openwakewordfrom Windows Python 3.12+installs, and a
windows_onlyregression test exercises that path on thereal Windows CI runner.
[all]is unchanged; this only affects thewakeextra's own marker andthe corresponding
uv.lockmarker.Why this approach.
ai-edge-litertcannot become a silent drop-inreplacement for Linux
tflite-runtimeyet: the current PyPI release has noarmv7lwheel (tracked upstream ingoogle-ai-edge/LiteRT#6043),
so switching Linux to it now would quietly drop 32-bit Raspberry Pi support.
Upstream
openWakeWordhas a merged-but-unreleased PR(dscripka/openWakeWord#289)
that migrates to
ai-edge-litert; once that ships on PyPI with verifiedmodel/runtime evidence, the Linux boundary can be revisited. Until then, the
safest and most honest fix is an explicit marker plus a fail-closed error —
not a broken resolver, and not a silent unverified backend swap.
Related Issue
No existing GitHub issue for this exact resolver failure. The related
upstream
ai-edge-litertarmv7l gap is tracked atgoogle-ai-edge/LiteRT#6043 (external repo).
Fixes #
Type of Change
Changes Made
pyproject.toml:[project.optional-dependencies].wake— add thepython_version < '3.12' or sys_platform != 'linux'marker toopenwakeword==0.6.0.uv.lock: regenerate the corresponding marker on the lockedopenwakewordrequirement (uv lock, no other package changes).tools/lazy_deps.py: addopenwakeword_supported()andopenwakeword_unsupported_reason()as the single sharedplatform/Python-aware compatibility predicate.
tools/wake_word.py: fail closed with an actionable message incheck_wake_word_requirements()and_OpenWakeWordEngine.__init__()before any lazy install is attempted on an unsupported Linux interpreter;
preserve the existing macOS ARM64
ai-edge-litertbridge path unchanged.tests/test_project_metadata.py: marker-evaluation tests for theLinux/Darwin boundary (project marker and locked marker), a lockfile
assertion that the three published CPython 3.11 Linux wheel architectures
(x86_64/aarch64/armv7l) remain present and no cp312+ wheel is claimed, and
a CPython-3.11-only
pytest.importorskip-gated import smoke fortflite_runtime.interpreter/openwakeword.model.tests/tools/test_lazy_deps.py: predicate tests for the Linux boundaryand the Darwin bridge, plus a fail-closed test asserting
ensure()nevercalls
pip/uvor probes installer policy when the predicate reportsunsupported.
tests/tools/test_wake_word.py: requirements-probe and engine-constructionfail-closed tests (simulated Python 3.12/3.13/3.14), a parameterized
Darwin ARM64 bridge-preservation regression on simulated CPython 3.12 and
3.13, a Windows-only positive ONNX-path regression on simulated CPython
3.12 and 3.13 (executed by the real Windows CI lane), and a
subprocess-isolated test that
tools.lazy_deps/tools.wake_wordremain importable when every optional wake dependency(
ai_edge_litert,numpy,onnxruntime,openwakeword,pvporcupine,sherpa_onnx,sounddevice,tflite_runtime) is blocked at import time.website/docs/user-guide/features/wake-word.md: document the LinuxCPython 3.11 boundary, the preserved macOS bridge, and that
[all]isunaffected.
How to Test
tflite-runtime==2.14.0directly(unaffected by this PR, since the PyPI package itself is unchanged):
uv sync --extra wake --locked --python 3.14 --dry-run --no-install-projecton an unpatched
pyproject.toml/uv.lockfails with the resolver errorquoted above.
selects no
openwakeword/tflite-runtimepackages; Python 3.11 stillselects both, with all three Linux wheel architectures available.
uv run --extra dev --extra wake --locked pytest -q tests/tools/test_lazy_deps.py tests/tools/test_wake_word.py tests/test_project_metadata.pyuv run --extra dev --extra messaging --locked pytest -q tests/gateway/test_wake_delivery.py tests/gateway/test_kanban_notifier_apiserver_wake.py tests/gateway/test_kanban_notifier_wake_only_ordering.pyChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass — not run as a full suite in this PR; see focused/overlap evidence belowuv; Darwin ARM64 coverage is exercised through simulatedsys.platform/sys.version_infoin the test suite (no physical macOS hardware used)Documentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/A (no config keys changed)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/A (no architecture/workflow change)Test evidence (exact head)
Base:
f14059fad20e17acf2512785114791566e70bd06(liveorigin/mainat thefinal refresh before publication). Head:
f4a57481c090b13893fab72811f0d7945dd3ce50.uv run --extra dev --extra wake --locked pytest -q tests/tools/test_lazy_deps.py tests/tools/test_wake_word.py tests/test_project_metadata.py→ 106 passed, 6 skippeduv run --extra dev --extra messaging --locked pytest -q tests/gateway/test_wake_delivery.py tests/gateway/test_kanban_notifier_apiserver_wake.py tests/gateway/test_kanban_notifier_wake_only_ordering.py→ 10 passeduv run --extra dev --locked ruff check tools/lazy_deps.py tools/wake_word.py tests/tools/test_lazy_deps.py tests/tools/test_wake_word.py tests/test_project_metadata.py→ All checks passed!uv lock --check→ passedgit diff --check <base>..HEAD→ passed (worktree clean)uv sync --all-extras --locked --python 3.12 --dry-run --no-install-project→ passeduv sync --all-extras --locked --python 3.13 --dry-run --no-install-project→ passeduv sync --extra wake --locked --python 3.12 --dry-run --no-install-project→ passed, resolves withoutopenwakeword/tflite-runtimeretain
openwakeword; the Windows-only engine test verifies the ONNX pathwithout probing the Linux TFLite bridge.
Known limitation, stated explicitly: this repository's
project.requires-pythonis currently>=3.11,<3.14, so a full repositoryuv sync --all-extras --locked --python 3.14is rejected before dependencyresolution even runs, independent of this PR. This PR does not raise that
ceiling (that's the separate Python 3.14 support PR, #92548) and does not
claim a repository-level Python 3.14
[all]pass. The Python 3.14 wakemarker behavior itself is verified with a minimal, uncapped reproducer
project outside the repository's own
requires-pythonconstraint, and withdurable marker-evaluation unit tests inside the repository
(
tests/test_project_metadata.py) that assert the marker's boolean outcomedirectly for
python_version == 3.14without depending on the repository'sown interpreter ceiling.
Rollback: revert this PR's commits; this restores the pre-change
Python-only-unconditional
openwakewordmarker and lazy-install behavior(the resolver failure on Linux Python 3.12+ returns, matching current
main).