Contributing#
The same guide that ships as CONTRIBUTING.md in the repository, so that a
reader of this site does not have to leave it.
The idea, first#
cinnamon separates two things.
Components carry the weight. They are where a program’s logic lives, and the part meant to be customised.
Configurations describe that weight. They are lightweight, numerous, and quick to write, because the normal case is running many experiments over the same component.
Most of the design follows from that split, and a change that blurs it needs a
good argument. A configuration holds parameters and RegistrationKey
references, never a live model, connection, or other domain object.
Setting up#
git clone git@github.com:nlp-unibo/cinnamon.git
cd cinnamon
python -m venv .venv && source .venv/bin/activate
pip install -e ".[cli,dev]"
Optional extras: examples (pandas, scikit-learn) to run examples/, and
docs (Sphinx, the theme, mermaid) to build this site.
Running the checks#
One command, the same checks CI runs:
nox
Command |
What it does |
|---|---|
|
lint plus the full test suite on the current interpreter |
|
|
|
the full suite behind the 100% coverage gate |
|
the suite with the CLI extra not installed |
|
this documentation, warnings treated as errors |
|
one specific interpreter |
Plain pytest still works for a quick inner loop. nox exists so that “is
this green?” is one command rather than four across five environments. CI runs
the full 3.10 to 3.14 matrix, and you do not need to reproduce that locally.
The flow#
Branch off
main. One logical change per branch:feat/…,fix/…,perf/…,docs/…,chore/….Work, with tests. See the invariants below.
Run
noxuntil green.Open a pull request. CI runs the full matrix, and the
All checks passedjob is the one that gates the merge.Merge with a fast-forward, rebasing if
mainhas moved. History stays linear, sogit log --onelinereads as a list of changes rather than a braid.Delete the branch.
Direct pushes to main are for genuine emergencies. The flow costs a couple
of minutes and has already paid for itself: a bug that 296 passing tests missed
was caught at merge time by running the real command against a real project.
Invariants CI enforces#
100% statement and branch coverage. Not a vanity number. It is there so
that a line nobody exercises has to be justified out loud, with a
# pragma: no cover and a reason. Twice now it has caught a change that
looked safe: an optimisation that broke union dispatch, and a guard removed as
“dead” that was load-bearing.
ruff and mypy clean, with the formatter applied. Markdown is excluded from the formatter, because prose is hand-wrapped.
3.10 through 3.14. Genuine differences live in that range, such as PEP 649
annotations on 3.14 and itertools.batched from 3.12, and the library has
been broken by a new release before.
Writing tests#
Assert an outcome, not that the code ran. A test that calls a function and checks nothing raises coverage and verifies nothing.
Make fakes match the real protocol. A
Cancelbutton that returned its label instead of its value once made a broken feature look tested.Add a regression test with every bug fix, and check that it fails against the old code before you keep it.
Then run the real thing. The suite is not the last word. Several bugs here survived a green suite and died the moment someone ran
cmn-checkagainst an actual project.Before tagging a release, run a downstream project’s suite against the branch. 2.1.2 shipped on 557 passing tests at 100% branch coverage and broke pyhighlights in 49 of them: it forgot the caller’s own imports, so a second build handed back a second copy of every class. Coverage measures lines, not arrangements, and the arrangement that broke, a caller importing from a directory it then scans, is not one this project builds for itself. The check is two commands, run in the downstream checkout:
uv pip install -e ../cinnamon && uv run pytest
CI runs this for you on any pull request touching
cinnamon/orpyproject.toml, in.github/workflows/downstream.yml. It is not part ofall-green, because that job counts a skipped dependency as a failure and this one is skipped on a documentation-only pull request. Read it before tagging: a redDownstreamis a release that must not go out, whatever this repository’s own matrix says.
Commit messages#
A subject line that says what changed, and a body that says why: what the old
behaviour was, what it cost, and what was rejected along the way. The git
log of this project is meant to be readable six months later by someone
deciding whether to undo your change.
Documentation#
Public API changes belong in docsrc/. Anything a user types, such as a CLI
flag, a field type, or an exception they will see, should be documented in the
same pull request.
nox -s docs builds the site into docsrc/build/html with warnings treated
as errors, and the docs.yml workflow publishes that build to GitHub Pages. A
page that moves keeps its old URL alive with a stub under
docsrc/source/_redirects: GitHub Pages serves static files and cannot issue
a redirect, so a zero-delay meta refresh is the mechanism available.