Management commands¤
The entry-point to run commands to manage the project is our Python make script, located in the scripts folder. You can either call it directly with ./scripts/make, or you can use direnv to add the script to your command line path. Once direnv is installed and hooked into your shell, allow it once for this directory with direnv allow. Now you can directly call the Python script with make. The Makefile is just here to provide auto-completion.
Try typing make or make help to show the available commands.
$ make
Available commands
help Print this help. Add task name to print help.
setup Setup all virtual environments (install dependencies).
run Run a command in the default virtual environment.
multirun Run a command for all configured Python versions.
allrun Run a command in all virtual environments.
3.x Run a command in the virtual environment for Python 3.x.
clean Delete build artifacts and cache files.
vscode Configure VSCode to work on this project.
Commands¤
Commands are always available: they don't require any Python dependency to be installed.
setup¤
Setup all virtual environments (install dependencies).
make setup
The setup command installs all the Python dependencies required to work on the project. Virtual environments and dependencies are managed by uv. Development dependencies are listed in the devdeps.txt file.
The command will create a virtual environment in the .venv folder, as well as one virtual environment per supported Python version in the .venvs/3.x folders. Supported Python versions are listed in the scripts/make file, and can be overridden by setting the PYTHON_VERSIONS environment variable.
If you cloned the repository on the same file-system as uv's cache, everything will be hard linked from the cache, so don't worry about wasting disk space.
Once dependencies are installed, try running make or make help again, to show additional tasks.
$ make
Available commands
help Print this help. Add task name to print help.
setup Setup all virtual environments (install dependencies).
run Run a command in the default virtual environment.
multirun Run a command for all configured Python versions.
allrun Run a command in all virtual environments.
3.x Run a command in the virtual environment for Python 3.x.
clean Delete build artifacts and cache files.
vscode Configure VSCode to work on this project.
Available tasks
build Build source and wheel distributions.
changelog Update the changelog in-place with latest commits.
check Check it all!
check-api Check for API breaking changes.
check-docs Check if the documentation builds correctly.
check-quality Check the code quality.
check-types Check that the code is correctly typed.
coverage Report coverage as text and HTML.
docs Serve the documentation (localhost:8000).
docs-deploy Deploy the documentation to GitHub pages.
format Run formatting tools on the code.
fuzz Fuzz Griffe against generated Python code.
publish Publish source and wheel distributions to PyPI.
release Release a new version of the project.
test Run the test suite.
These tasks are written using duty (a task runner), and located in the duties.py module in the repository root.
Some of these tasks will run in the default virtual environment (.venv), while others will run in all the supported Python version environments (.venvs/3.x).
Source code in scripts/make.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | |
help¤
Print this help. Add task name to print help.
make help [TASK]
When the Python dependencies are not installed, this command just print the available commands. When the Python dependencies are installed, duty is available so the command can also print the available tasks.
If you add a task name after the command, it will print help for this specific task.
Source code in scripts/make.py
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
run¤
Run a command in the default virtual environment.
make run <CMD> [ARG...]
This command runs an arbitrary command inside the default virtual environment (.venv). It is especially useful to start a Python interpreter without having to first activate the virtual environment: make run python.
Source code in scripts/make.py
168 169 170 171 172 173 174 175 176 177 178 179 180 | |
multirun¤
Run a command for all configured Python versions.
make multirun <CMD> [ARG...]
This command runs an arbitrary command inside the environments for all supported Python versions. It is especially useful for running tests.
Source code in scripts/make.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |
allrun¤
Run a command in all virtual environments.
make multirun <CMD> [ARG...]
This command runs an arbitrary command inside the default environment, as well as the environments for all supported Python versions.
This command is especially useful to install, remove or update dependencies in all environments at once. For example, if you want to install a dependency in editable mode, from a local source:
make allrun uv pip install -e ../other-project
Source code in scripts/make.py
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | |
3.x¤
Run a command in the virtual environment for Python 3.x.
make 3.x <CMD> [ARG...]
This command runs an arbitrary command inside the environment of the selected Python version. It can be useful if you want to run a task that usually runs in the default environment with a different Python version.
Source code in scripts/make.py
225 226 227 228 229 230 231 232 233 234 235 236 237 | |
clean¤
Delete build artifacts and cache files.
make clean
This command simply deletes build artifacts and cache files and folders such as build/, .cache/, etc.. The virtual environments (.venv and .venvs/*) are not removed by this command.
Source code in scripts/make.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
vscode¤
Configure VSCode to work on this project.
make vscode
This command configures the VSCode editor by copying the following files into the .vscode directory:
launch.json, for run configurations (to run debug sessions)settings.json, for various editor settings like linting tools and their configurationtasks.json, for running tasks directly from VSCode's interface
Warning: These files will be overwritten every time the command is run.
Source code in scripts/make.py
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | |
Tasks¤
Tasks require the Python dependencies to be installed. They use various tools and libraries to assert code quality, run tests, serve the documentation locally, or build and publish distributions of your project. There are multiple ways to run tasks:
make TASK, the main, configured way to run a taskmake run duty TASK, to run a task in the default environmentmake multirun duty TASK, to run a task on all supported Python versionsmake allrun duty TASK, to run a task in all environmentsmake 3.x duty TASK, to run a task on a specific Python version
build¤
Build source and wheel distributions.
make build
Build distributions of your project for the current version. The build task uses the build tool to build .tar.gz (Gzipped sources archive) and .whl (wheel) distributions of your project in the dist directory.
Source code in duties.py
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | |
changelog¤
Update the changelog in-place with latest commits.
make changelog [bump=VERSION]
Update the changelog in-place. The changelog task uses git-changelog to read Git commits and parse their messages to infer the new version based on our commit message convention.
The new version will be based on the types of the latest commits, unless a specific version is provided with the bump parameter.
If the group of commits contains only bug fixes (fix:) and/or commits that are not interesting for users (chore:, style:, etc.), the changelog will gain a new patch entry. It means that the new suggested version will be a patch bump of the previous one: 0.1.1 becomes 0.1.2.
If the group of commits contains at least one feature (feat:), the changelog will gain a new minor entry. It means that the new suggested version will be a minor bump of the previous one: 0.1.1 becomes 0.2.0.
If there is, in the group of commits, a commit whose body contains something like Breaking change, the changelog will gain a new major entry, unless the version is still an "alpha" version (starting with 0), in which case it gains a minor entry. It means that the new suggested version will be a major bump of the previous one: 1.2.1 becomes 2.0.0, but 0.2.1 is only bumped up to 0.3.0. Moving from "alpha" status to "beta" or "stable" status is a choice left to the developers, when they consider the package is ready for it.
The configuration for git-changelog is located at config/git-changelog.toml.
Parameters:
-
bump(str, default:'') –Bump option passed to git-changelog.
Source code in duties.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | |
check¤
Check it all!
make check
Composite command to run all the check commands:
check-quality, to check the code quality on all Python versionscheck-types, to type-check the code on all Python versionscheck-docs, to check the docs on all Python versionscheck-api, to check for API breaking changes
Source code in duties.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
check-api¤
Check for API breaking changes.
make check-api
Compare the current code to the latest version (Git tag) using Griffe, to search for API breaking changes since latest version. It is set to allow failures, and is more about providing information than preventing CI to pass.
Parameters:
-
*cli_args(str, default:()) –Additional Griffe CLI arguments.
Source code in duties.py
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | |
check-docs¤
Check if the documentation builds correctly.
make check-docs
Build the docs with MkDocs in strict mode.
The configuration for MkDocs is located at mkdocs.yml.
This task builds the documentation with strict behavior: any warning will be considered an error and the command will fail. The warnings/errors can be about incorrect docstring format, or invalid cross-references.
Source code in duties.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
check-quality¤
Check the code quality.
make check-quality
Check the code quality using Ruff.
The configuration for Ruff is located at config/ruff.toml. In this file, you can deactivate rules or activate others to customize your analysis. Rule identifiers always start with one or more capital letters, like D, S or BLK, then followed by a number.
You can ignore a rule on a specific code line by appending a noqa comment ("no quality analysis/assurance"):
print("a code line that triggers a Ruff warning") # noqa: ID
...where ID is the identifier of the rule you want to ignore for this line.
Example:
import subprocess
```console
$ make check-quality
✗ Checking code quality (1)
> ruff check --config=config/ruff.toml src/ tests/ scripts/
src/your_package/module.py:2:1: S404 Consider possible security implications associated with subprocess module.
```
Now add a comment to ignore this warning.
```python title="src/your_package/module.py"
import subprocess # noqa: S404
```
```console
$ make check-quality
✓ Checking code quality
```
You can disable multiple different warnings on a single line
by separating them with commas, for example `# noqa: D300,D301`.
You can disable a warning globally by adding its ID into the list in config/ruff.toml.
You can also disable warnings per file, like so:
[per-file-ignores]
"src/your_package/your_module.py" = [
"T201", # Print statement
]
Source code in duties.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
check-types¤
Check that the code is correctly typed.
make check-types
Run type-checking on the code with Mypy.
The configuration for Mypy is located at config/mypy.ini.
If you cannot or don't know how to fix a typing error in your code, as a last resort you can ignore this specific error with a comment:
print("a code line that triggers a Mypy warning") # type: ignore[ID]
...where ID is the name of the warning.
Example:
result = data_dict.get(key, None).value
```console
$ make check-types
✗ Checking types (1)
> mypy --config-file=config/mypy.ini src/ tests/ scripts/
src/your_package/module.py:2:1: Item "None" of "Data | None" has no attribute "value" [union-attr]
```
Now add a comment to ignore this warning.
```python title="src/your_package/module.py"
result = data_dict.get(key, None).value # type: ignore[union-attr]
```
```console
$ make check-types
✓ Checking types
```
Source code in duties.py
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | |
coverage¤
Report coverage as text and HTML.
make coverage
Combine coverage data from multiple test runs with Coverage.py, then generate an HTML report into the htmlcov directory, and print a text report in the console.
Source code in duties.py
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | |
docs¤
Serve the documentation (localhost:8000).
make docs
This task uses MkDocs to serve the documentation locally.
Parameters:
-
*cli_args(str, default:()) –Additional MkDocs CLI arguments.
-
host(str, default:'127.0.0.1') –The host to serve the docs from.
-
port(int, default:8000) –The port to serve the docs on.
Source code in duties.py
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | |
docs-deploy¤
Deploy the documentation to GitHub pages.
make docs-deploy
Use MkDocs to build and deploy the documentation to GitHub pages.
Source code in duties.py
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | |
format¤
Run formatting tools on the code.
make format
Format the code with Ruff. This command will also automatically fix some coding issues when possible.
Source code in duties.py
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
fuzz¤
Fuzz Griffe against generated Python code.
Parameters:
-
ctx(Context) –The context instance (passed automatically).
-
size(int, default:20) –The size of the case set (number of cases to test).
-
seeds(_Seeds, default:_Seeds()) –Seeds to test or exclude (comma-separated integers).
-
min_seed(int, default:0) –Minimum value for the seeds range.
-
max_seed(int, default:1000000) –Maximum value for the seeds range.
Source code in duties.py
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | |
publish¤
Publish source and wheel distributions to PyPI.
make publish
Publish the source and wheel distributions of your project to PyPI using Twine.
Source code in duties.py
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | |
release¤
Release a new version of the project.
make release [version=VERSION]
This task will:
- Stage changes to
pyproject.tomlandCHANGELOG.md - Commit the changes with a message like
chore: Prepare release 1.0.0 - Tag the commit with the new version number
- Push the commit and the tag to the remote repository
- Build source and wheel distributions
- Publish the distributions to PyPI
- Deploy the documentation to GitHub pages
Parameters:
-
version(str, default:'') –The new version number to use. If not provided, you will be prompted for it.
Source code in duties.py
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | |
test¤
Run the test suite.
make test
Run the test suite with Pytest and plugins. Code source coverage is computed thanks to coveragepy.
Parameters:
-
*cli_args(str, default:()) –Additional Pytest CLI arguments.
Source code in duties.py
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | |