[project] name = "musicmouse" version = "2.0.0" description = "Host backend for the MusicMouse RFID music player" # Raspberry Pi OS (Bookworm) ships Python 3.11, and its system interpreter is what the # device runs. Staying on it means apt and piwheels supply prebuilt armhf wheels for # the native dependencies (pydantic-core, Pillow), instead of needing a separate # toolchain to fetch a newer interpreter and compile them on the Pi. requires-python = ">=3.11" dependencies = [ "aiomqtt>=2.0", "fastapi>=0.115", # Podcast RSS feeds in the wild are full of small quirks (odd dates, missing # namespaces); parsing them by hand invites silently dropping episodes. "feedparser>=6.0", # Also what tests drive the ASGI app with - plain httpx is deprecated in favour of # this for exactly that. Runtime uses it to proxy the room page's Home Assistant # calls, so the long-lived token never has to leave the backend. "httpx2>=2.12", "mutagen>=1.47", "pillow>=10.4", "pydantic>=2.7", "pyserial-asyncio>=0.6", "python-vlc>=3.0", "ruamel.yaml>=0.18", "uvicorn>=0.30", # uvicorn ships no websocket implementation of its own; without this the # state-push upgrade is answered with a 404 and the UI never updates. "websockets>=13", ] [project.optional-dependencies] dev = ["mypy>=1.10", "pytest-asyncio>=0.23", "pytest>=8.0", "ruff>=0.5"] # Off by default: the reactive background is nice, not required, and librosa/numpy are # a real install cost on a Pi. Missing this group means `build_analyzer()` falls back # to `NullAnalyzer` and the background stays at its static baseline - never a crash. analysis = ["librosa>=1.0", "numpy>=2.0"] [project.scripts] musicmouse = "musicmouse.__main__:main" [build-system] requires = ["setuptools>=68"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] include = ["musicmouse*"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" filterwarnings = ["error"] [tool.ruff] line-length = 100 target-version = "py311" # Course material and scratch work, not part of the backend. See notebooks/README.md. extend-exclude = ["notebooks"] [tool.ruff.lint] select = ["ARG", "B", "C4", "E", "F", "I", "N", "PTH", "RUF", "SIM", "UP", "W"] [tool.ruff.lint.per-file-ignores] "tests/*" = ["ARG001"] # Entity is an ABC with optional hooks: empty bodies and unused args are the point. "musicmouse/services/mqtt/entity.py" = ["ARG002", "B027"] [tool.mypy] python_version = "3.11" strict = true files = ["musicmouse"] warn_unreachable = true [[tool.mypy.overrides]] # numpy ships its own types, but only when the `analysis` extra is installed - a plain # checkout must still type-check clean, so it needs the same treatment as librosa. module = ["vlc", "serial_asyncio", "ruamel.*", "librosa.*", "numpy", "feedparser"] ignore_missing_imports = true