Thank you for your interest in contributing to the development of comMS! This document covers setting up a development environment, the comMS project layout and code style, and how to submit changes.
As described in README.md, comMS requires Python 3.14 or later and uses uv for Python dependency management.
Clone the repository and install comMS in editable mode with all development dependencies:
git clone https://github.com/holsam/comMS
cd comMS
uv syncThis installs comMS as an editable package into a .venv managed by uv. The comms command will be available within the virtual environment.
To activate the environment manually:
source .venv/bin/activateIt is recommended that any development environment includes the external binaries that comMS wraps: the Crux toolkit and ThermoRawFileParser.
See Installing external tools in README.md for the expected layout.
comMS follows the below structure:
comMS/
bin/ # External binaries
src/
comms/
cli/ # Typer command definitions (argument parsing, help text)
commands/ # Logic for each individual command
gui/ # PySide6 GUI for the `experiment` command
r/ # R scripts used by the `report` command
deps/ # Dependency checking/installation (also exposed via `comms r-utils`)
sections/ # One script per report section (qc, pca, da, secondary-species, concordance, aux/ev-markers)
utils/ # Shared R helpers (import, normalisation, status tracking, theming)
utils/ # Shared Python utilities (e.g I/O, paths, config, Crux/TRFP wrappers)
config.toml # Bundled default configuration
main.py # Typer app assembly, imported by the `comms` console-script entry point
tests/
conftest.py # Shared fixtures and binary-availability guards
fixtures/
generate_fixtures.py # Synthetic FASTA and mzML generator
unit/ # Pure logic tests, no external binaries required
integration/ # End-to-end tests, may require Crux and/or TRFP
pyproject.toml # Project configuration
uv.lock # UV lockfile
Each command is split across two files:
| File | Purpose |
|---|---|
cli/<command>.py |
Defines the Typer command, argument types, and default values drawn from config |
commands/<command>.py |
Contains all command logic, using functions which are importable and testable without invoking Typer |
When adding a new command, please keep these files separate.
- Use
camelCasefor functions andsnake_casefor local variables. - User-facing terminal output should use Rich markup via
from rich import print. - Logging should use the shared
logMsglogger fromcomms.utils.log. UselogMsg.debug,logMsg.info,logMsg.warning,logMsg.errorat appropriate levels. - Config values should be defined in the
configdict imported fromcomms.utils.settings. Configuration values should not be hard-coded. - Please use British English in docstrings, comments, and user-facing messages.
- Create
src/comms/commands/<name>.pywith arun_<name>()function. - Create
src/comms/cli/<name>.pywith a Typer instance and command definition. - Register the Typer instance in
src/comms/cli/cli.pyviacomms.add_typer(...). - Add any new config keys to
src/comms/config.tomlwith sensible defaults. - If new config keys are introduced, ensure the
config_setfunction and_apply_protocol_flagshelper function insrc/comms/commands/config.pyare updated accordingly. - Also ensure corresponding unit tests are created in
tests/unit/config.py - Write unit tests in
tests/unit/test_<name>.pycovering the business logic in isolation. - Write integration tests in
tests/integration/test_<name>.pyif the command wraps an external binary.
- Fork the repository and create a branch from
main. - Make your changes, ensuring the test suite passes.
- Open a pull request with a clear description of what the change does and why.
Please raise an issue before starting work on large changes so that the approach can be discussed first.