[project] name = "desklock-gateway" version = "0.2.2" description = "Voice gateway bridging the DeskLock device to the Tatlock butler (STT/chat/TTS)" requires-python = ">=3.11" dependencies = [ "fastapi>=0.115", "uvicorn[standard]>=0.30", "httpx>=0.27", "pydantic-settings>=2.4", ] [project.optional-dependencies] speech = [ "faster-whisper>=1.0", "piper-tts>=1.2", ] dev = [ "pytest>=8.0", "pytest-asyncio>=0.24", "ruff>=0.6", "mypy>=1.11", ] [build-system] requires = ["setuptools>=68"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["src"] [tool.ruff] line-length = 100 src = ["src"] # Selected explicitly, because the default set is not a constant. # # With no `select` here, ruff lints with whatever its installed version # defaults to — 413 rules under 0.16.3. `dev` pins only `ruff>=0.6`, and CI # installs that extra fresh on every run, so the gate's scope was a function of # when pip last resolved rather than of this code. Two findings appeared here # the first time a converged environment ran the gate, in a file nobody had # touched (T-47). # # That is the failure this repo keeps meeting from the other side: a check # whose result depends on something other than the thing it checks. Pinning the # ruff version would freeze the symptom; naming the rules fixes it, and makes # a future ruff release a decision rather than a surprise. # # ASYNC is here on purpose — this is a websocket gateway, and it is the one # family whose findings would be genuine bugs rather than style. # BLE (blind except) is deliberately absent: main.py catches bare Exception # when a device disappears mid-send, which is correct there and would need a # noqa on every occurrence to say so. [tool.ruff.lint] select = ["E", "W", "F", "I", "UP", "B", "ASYNC", "SIM", "C4"] [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] [tool.mypy] python_version = "3.11" # The speech extra is deliberately absent from a default setup. `make setup` # installs the gateway without it; `make setup-speech` adds faster-whisper and # piper-tts, which pull several GB of ML wheels for a backend the deployment # does not use — settings.tts_backend defaults to "speaches", a network call to # the shared service on 8601. Both imports are lazy, inside the functions that # need them, so their absence is a runtime fact rather than a defect. # # numpy is here for the same reason: nothing depends on it directly, it arrives # with faster-whisper. # # Without these overrides, `make typecheck` fails on a machine that followed the # documented setup — the pre-push gate turning red for doing the right thing, # which is how a gate stops being read (T-56). The right assertion is "these # modules may be absent", not "install several GB so the type checker is happy". [[tool.mypy.overrides]] module = [ "piper", "piper.*", "faster_whisper", "faster_whisper.*", "numpy", "numpy.*", ] ignore_missing_imports = true