From 3f6f6a31455c88e81673fcb1daebe4f08da2c1bb Mon Sep 17 00:00:00 2001 From: StuBehan Date: Thu, 30 Apr 2026 12:02:47 +0200 Subject: [PATCH] chore: enable mypy disallow_untyped_defs for stackvox/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tightens the type bar so every function in stackvox/ has explicit param and return annotations. Tests stay on the looser config — pytest fixtures and pytest-mock's mocker are Any-heavy, and strict bans buy little there. Surfaced exactly one untyped function: the CoreAudio device-change callback in _start_device_watcher had `addrs` and `data` parameters without annotations. They're a ctypes.POINTER and a c_void_p we don't actually read — annotated as `Any` with a comment explaining why we ignore them. Co-Authored-By: Claude Opus 4.7 (1M context) --- pyproject.toml | 6 ++++-- stackvox/daemon.py | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 74a4a37..0548285 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,6 +106,7 @@ warn_redundant_casts = true warn_return_any = true check_untyped_defs = true no_implicit_optional = true +disallow_untyped_defs = true [[tool.mypy.overrides]] # Third-party deps without inline type stubs. @@ -113,8 +114,9 @@ module = ["kokoro_onnx", "sounddevice", "soundfile"] ignore_missing_imports = true [[tool.mypy.overrides]] -# Tests use pytest-mock's mocker.patch which returns Any-heavy values; don't -# require full strictness there. +# Tests rely on pytest-mock's `mocker` (Any-heavy) and pytest fixtures with +# implicit Any-typed kwargs. Strict untyped-def bans buy little here, so +# tests stay on the looser config. module = "tests.*" disallow_untyped_defs = false diff --git a/stackvox/daemon.py b/stackvox/daemon.py index e25c5ac..299f126 100644 --- a/stackvox/daemon.py +++ b/stackvox/daemon.py @@ -130,7 +130,10 @@ def _read_default_device() -> int: last_device = [_read_default_device()] - def _on_device_change(obj_id: int, n: int, addrs, data) -> int: + def _on_device_change(obj_id: int, n: int, addrs: Any, data: Any) -> int: + # `addrs` is a ctypes.POINTER(_PropAddr); `data` is a c_void_p — neither + # is needed because we already know which property fired (only one is + # registered) and we re-read the device ID directly. try: current = _read_default_device() if current and current != last_device[0]: