Contributing¶
Thank you for considering a contribution to Cloup.
Getting started¶
Please discuss a proposed change before opening a pull request:
Search the issue tracker for an existing report or proposal.
Open an issue describing the problem, the desired behavior, and your proposed approach.
Wait for a maintainer to confirm that the change is appropriate and agree on its scope.
If the maintainer agrees, create a branch, implement the change, and open a pull request linked to the issue.
Starting with an issue avoids duplicated work and gives maintainers and contributors a place to settle API and compatibility decisions before code is written.
Development¶
Prerequisites¶
Cloup uses Hatch for isolated Python environments and Task as its project command interface. Install both as isolated tools:
$ pipx install hatch
$ pipx install "go-task-bin>=3.46.1"
The equivalent UV commands are:
$ uv tool install hatch
$ uv tool install "go-task-bin>=3.46.1"
go-task-bin is an unofficial Python package that distributes the Task binary.
See Task’s official installation guide
for the other supported installation methods.
Hatch can install and manage the required Python interpreters, so a separate tool
such as pyenv is not required.
It creates environments automatically when their commands are first used.
To store them under .hatch/ in the repository instead of Hatch’s global data
directory, run:
$ hatch config set dirs.env.virtual .hatch
Set up the development environment¶
Clone your fork and enter the repository:
$ git clone https://github.com/<your-username>/cloup.git
$ cd cloup
Create the dev environment with Python 3.10 and print its location:
$ task env
Select the reported Python interpreter in your IDE. The environment contains Cloup in editable mode together with the test, coverage, and typing dependencies, so it can run tests and type checks directly from the IDE.
Run task --list to see all available project commands.
Using Task¶
Invoke one project task by name, for example:
$ task lint
When several task names are provided on the command line, Task runs them
sequentially by default.
Use --parallel to run independent requested tasks concurrently:
$ task --parallel lint docs
Dependencies declared by a single task run concurrently by default, so aggregate
commands such as task test:all and task qa:all need no --parallel flag.
Use --failfast when one failure should cancel the other running tasks:
$ task --failfast qa:all
The project does not impose a concurrency limit.
Set one for a particular run with task --concurrency N COMMAND or the
TASK_CONCURRENCY environment variable.
Parallel output is prefixed with the task that produced it.
Code quality¶
Use the following commands while developing:
Command |
Purpose |
|---|---|
|
Lint the code and check its formatting style. |
|
Lint in fix mode and format the code. |
|
Lint the code with Ruff, optionally fixing violations. |
|
Format the code with Ruff. |
|
Type-check the code in the development environment. |
|
Type-check in every Python and Click compatibility environment. |
Ruff enforces Pyflakes rules, stable non-formatting pycodestyle rules, and warnings.
Whitespace and hard line-length rules that overlap with ruff format are left to
the formatter, which uses the existing 90-character target. In particular, the
former E241 and E251 exceptions are no longer needed, W191 is omitted
because it conflicts with the formatter, and Ruff does not implement the obsolete
W503 rule.
Testing¶
The primary development environment and every test environment expose the same test and typing scripts. The test matrix covers every supported Python version with the latest compatible Click release, plus older supported Click release lines on the latest Python. This ensures that type checking observes the same dependencies and standard library as the corresponding test run.
Command |
Purpose |
|---|---|
|
Run tests with the development environment. |
|
Run every Python and Click compatibility environment in parallel. |
|
Upgrade Click to the latest release allowed by each test environment. |
|
Run tests in the development environment and generate terminal and HTML coverage reports. |
|
Collect coverage from every test environment in parallel and combine the results. |
Use -- before arguments that should be forwarded to pytest.
For example, stop after the first failure with:
$ task test -- -x
For example, run the full test matrix sequentially with:
$ task --concurrency 1 test:all
Quality assurance workflows¶
The aggregate tasks are the recommended checks before submitting changes:
Command |
Purpose |
|---|---|
|
Run lint and formatting checks first, then type checking, tests, and documentation using the primary environments. |
|
Run lint, formatting, and documentation checks plus typing and tests in every test environment. |
Use task qa during routine development and task qa:all before opening or
updating a pull request.
For contiguous, failure-focused logs, use Task’s grouped output:
$ task --output group --output-group-error-only qa:all
An open Task pull request from
Cloup’s maintainer proposes a built-in task --tui interface.
Besides launching tasks, it executes their task graph inside the TUI, gives every
task invocation a separately inspectable output pane, and can copy or save an
individual task’s output—or save all outputs into separate files.
The feature is not part of a released Task version yet, and its interface may change
while the pull request is under review.
Documentation¶
Build the documentation and treat warnings as errors with:
$ task docs
Start a live-reloading server that watches the documentation and package sources with:
$ task docs:serve
Pass -a after -- when changing CSS or other static files so Sphinx rebuilds
every page:
$ task docs:serve -- -a
Dependencies¶
Development dependencies belong to their corresponding environments in
hatch.toml.
The development and Python test environments deliberately resolve compatible
versions afresh so scheduled CI can detect dependency compatibility problems.
Reproducibility-sensitive lint, documentation, and package-checking environments use
committed PEP 751 lockfiles.
Regenerate affected lockfiles after changing a locked environment:
$ hatch env lock
Use --upgrade only when intentionally upgrading locked dependencies:
$ hatch env lock --upgrade
Commit every changed pylock.*.toml file together with its hatch.toml change.
Building distributions¶
Build the source distribution and wheel and validate their metadata with:
$ task build
Pull requests¶
Keep pull requests focused on the scope agreed in the issue.
Include tests for behavioral changes and update user documentation when the public
API or documented behavior changes.
Before requesting review, run task qa:all and task build.