Python plugins
Python plugins (contrib)
The four packages share one drift-guarded contract; see the contrib ecosystem for the layout and the integration pages for plugin-specific setup.
# python-musefs: self-contained
cd contrib/python-musefs && python -m pytest && ruff check . && ruff format --check .
# beets: install the local python-musefs first so the suite tests the working
# tree, not the PyPI release (see the beets integration page for the venv flow)
cd contrib/beets && pip install -e ../python-musefs && pip install -e ".[test]" && python -m pytest tests
# picard: no install needed (vendored + pythonpath=".")
cd contrib/picard && python -m pytest tests
# lidarr: install the local python-musefs first so the suite tests the working
# tree, not the PyPI release (see the lidarr integration page for the env flow)
cd contrib/lidarr && pip install -e ../python-musefs && pip install -e ".[test]" && python -m pytest tests
Gotchas that have bitten before:
- On PEP 668 "externally managed" systems, bare
pip installfails — use a venv for the beets suite. - The real-Picard tests
importorskipPicard and Qt: without an importable Picard (e.g. the system package onPYTHONPATH), they silently skip. When touching the Picard plugin, make sure they actually ran. - The Lidarr integration is gated by two automated tiers, both deterministic
and network-free (Lidarr's metadata server is mocked too):
- PR check —
.github/workflows/lidarr-smoke.yml(scripts/lidarr-smoke.sh): a fast smoke that proves the Custom Script exec path on a real Lidarr (its Test event) and runs the content leg (musefs-lidarr-synctag-writes,musefs-lidarr-importsymlink, served-mount tags, unchanged bytes) against a local mock Lidarr API. Runs on PRs touching the Lidarr surface. - Release gate —
.github/workflows/lidarr-e2e.yml(scripts/lidarr-e2e/run-e2e.sh): the full real-instance e2e. A real Lidarr, driven by local metadata/indexer/qBittorrent mocks, performs a genuine download-client import of a real CC0 album as aNewDownload, firingOnReleaseImport, which execs the real musefs scripts; the served mount is then asserted to carry Lidarr-supplied metadata the backing file lacked, bytes unchanged. This gates the Pythonpy-v*publish and closes what used to be the manual download-client gap. The vendored CC0 fixture isscripts/lidarr-e2e/fixtures/.
- PR check —
musefs_common/schema.pyis generated frommusefs-db/src/schema.rs. After a schema change:MUSEFS_REGEN_SCHEMA_PY=1 cargo test -p musefs-db schema_py, then re-vendor Picard's copy withpython contrib/python-musefs/vendor_to_picard.py. Drift is enforced by amusefs-dbunit test and the Picard vendor-sync test.MAX_ART_BYTESincontrib/python-musefs/src/musefs_common/constants.pyis hand-mirrored frommusefs-core/src/scan.rs— update both sides together.