Contributing to Somnio¶
Thanks for helping improve Somnio. Contributions are welcome, including:
- Code changes via pull requests
- Documentation improvements
- Bug reports and feature requests
Setup¶
Prerequisites¶
- Python: Somnio supports Python 3.10+; for local development we recommend Python 3.12+.
- uv: Install the uv package manager.
Installation¶
1. Clone the repository
2. Install dependencies
3. Set up pre-commit hooks
Development workflow¶
This project follows GitHub Flow.
Tips and Conventions¶
- Commit messages should follow the format
Tag(context): Message.- Tags:
feat: New user-facing functionalityfix: Bug fixdocs: Documentation-only changesrefactor: Code change that neither fixes a bug nor adds a featuretest: Tests onlychore: Tooling/maintenance (deps, CI, formatting, etc.)
- Context: A short scope for where the change applies (a package/module, feature area, or subsystem), e.g.
cli,zmax,docs,io,logging. - Examples:
fix(zmax): Handle empty config,docs(contributing): Document commit format,feat(cli): Add --json output
- Tags:
- Branch names should also use the same tags, with no context:
tag/short-kebab-description, e.g.fix/handle-empty-config,docs/contributing-commit-format,feat/cli-json-output. - Keep PRs focused; avoid bundling unrelated changes. Squash before merging.
- Rebase your branch on the latest
masterwhen needed to minimize merge conflicts. - Make PR titles/descriptions clear and include a brief test plan when relevant.
Code structure¶
Somnio is both a library (importable by other Python code) and a CLI application.
- Library code:
src/somnio/- Library code should avoid CLI-only dependencies.
- CLI code:
src/somnio/cli/src/somnio/cli/main.py: Typerappand top-level optionssrc/somnio/cli/commands/: one module per subcommand
Logging¶
To avoid surprising host applications:
- Library code uses the standard library
loggingmodule (no Loguru imports). - Library code must not configure handlers (no
basicConfig(), no global setup). - The package installs a
NullHandler()so importingsomnionever emits logs by default. - The CLI uses Loguru and configures logging once at startup.
Writing logs in library modules¶
Use module-level loggers:
Writing logs in CLI code¶
Use Loguru logger:
Linting and formatting¶
Somnio uses Ruff for both linting and formatting. If you've set up pre-commit hooks, linting and formatting will run automatically before each commit.
Run the linter¶
Fix issues automatically when possible:
Format code¶
Pre-commit (manual run)¶
You can also run all pre-commit checks manually:
Testing¶
Somnio uses pytest for tests.
Run tests¶
Test conventions¶
- Location: Put tests in
tests/. Prefer mirroring the source layout (e.g.,src/somnio/foo.py→tests/test_foo.py). - Naming: Use
test_*.pyfiles andtest_*functions. Name tests by behavior (test_parses_empty_file) rather than implementation. - Structure: Use Arrange–Act–Assert and keep each test focused on one behavior.
- Fixtures: Prefer
pytestfixtures for setup/teardown (and reuse). Avoid shared global state between tests. - Isolation: Tests should be deterministic and run in any order. Avoid network calls and reliance on the local machine/user environment.
- I/O: Use
tmp_pathfor filesystem work; don’t write into the repo tree. - Assertions: Prefer simple
assertstatements; usepytest.raises(...)for error cases. - Speed: Keep unit tests fast; if you add slow/integration tests, document how to run them and register any custom markers in
pyproject.toml.
Releases¶
Somnio uses semantic versioning (MAJOR.MINOR.PATCH). Breaking API or behavior changes increment MAJOR; backward-compatible additions increment MINOR; backward-compatible fixes increment PATCH. Pre-releases may use suffixes such as a1, b1, rc1 on the version string in pyproject.toml.
Changelog¶
User-facing changes for each version belong in the root CHANGELOG.md. Before tagging a release, add a dated section for the new version (move items out of Unreleased when you cut the release).
Git tags and PyPI¶
- Set
versioninpyproject.tomlto the release you are shipping (or runuv version <x.y.z>). - Commit the version bump and changelog updates on
master(or your release branch, then merge). - Create an annotated tag whose name is
vplus the same version string, for examplev0.2.0:
The tag name without the leading v must match project.version in pyproject.toml, or the Publish to PyPI workflow will fail.
- GitHub Actions builds the sdist and wheel, runs tests, and runs
uv publishto PyPI using Trusted Publishing (OIDC). No long-lived API token is stored in the repository; configure the trusted publisher and environment once as described in the workflow file comments.
GitHub Release notes¶
When you publish a tag, create a GitHub Release for that tag. Use the release description as the human-readable announcement: you can paste or summarize the corresponding CHANGELOG.md section so subscribers see highlights in their feed.
Documentation¶
This repo uses MkDocs for documentation.
Serve docs locally:
Docstrings¶
All public modules, functions, classes, and methods should include docstrings. Somnio follows the Google Python Style Guide for docstring formatting.
Where appropriate, API and reference documentation should be generated automatically using MkDocstrings. Auto-generated reference documentation is intended to complement narrative documentation, not replace it.
Writing conventions¶
- Use kebab-case for file names (e.g.,
installation-setup.md) - Place files in the appropriate subfolder under
docs/ - Use a single top-level heading (
#) per page - Use
##,###, etc. for subsections - Use relative links when linking between documentation pages
- Keep paths stable to avoid broken links
- Use fenced code blocks with a language identifier where possible:
- Keep pages focused and concise
- Prefer multiple small pages over one very long page
- Write in clear, direct language
TODOs and issue tracking¶
Somnio uses a lightweight convention for TODOs so that follow-up work (docs, tests, refactors, etc.) stays visible and actionable.
- Source of truth: Anything non-trivial should be tracked as a GitHub issue (use the issue templates when possible).
- In-code TODOs: Allowed. Prefer linking to an issue/ticket for anything that won't be handled immediately.
- Author is optional: You may write
TODO:orTODO(name):.
TODO format (Python)¶
Prefer one of these forms:
# TODO: [tests] Add regression test for empty config.
# TODO(ali): [docs] Explain config precedence.
Notes:
- Use a short tag like
[docs],[tests],[refactor],[logging],[config]at the start of the description. - If applicable, add an issue reference on the next line (URL) or a ticket id like
ABC-123.
TODO format (Markdown)¶
Use HTML comments so TODOs don't render in the docs:
Suggested labels¶
If you maintain labels in the GitHub repo, these tend to work well:
- Area:
docs,tests,cli,logging,config - Type:
bug,tech-debt - Priority:
priority:high,priority:medium,priority:low