Skip to content

Contributing

Contributions are welcome and greatly appreciated! Every little bit helps, and credit will always be given.

Environment Setup

amos uses uv to manage its environment. After cloning the repository, install every dependency (including the optional packages that the tests use) and the pre-commit hooks:

uv sync
uv run pre-commit install

Then run the tests, the linter, and the type checker:

uv run pytest
uv run ruff check
uv run mypy

Development

Follow this basic process:

  1. Fork and clone the repository.
  2. Create a new branch: git checkout -b feature-or-bugfix-name.
  3. Edit the code.
  4. If you added functionality or features, update the documentation accordingly.

If you are unsure about how to fix or ignore a warning, just let the continuous integration fail, and we will help you during review.

Don't bother updating the changelog, we will take care of this.

Adding a technique

Most contributions to amos are new techniques. To add one:

  1. Find the module of its genre (loaders, cleaners, mungers, mergers, shapers, describers, splitters, transformers, samplers, models, validators, metrics, evaluators, inferers, or plots) and copy a similar technique. Every class is a dataclasses.dataclass.
  2. Wrap tools from other packages by their import paths (in contents or tools), not by importing them at the top of a module. They are imported only when the technique is used, so amos stays light and its optional packages stay optional. If the tool comes from a new package, add the package to an extra in pyproject.toml and to options._EXTRAS.
  3. Give the class a docstring whose first line describes the technique. The tables of the technique catalog in docs/catalog.md are made from these lines: write them again with uv run python docs/scripts/technique_catalog.py. A unit test checks that the catalog is up to date. If the technique (or a function) uses a tool from another package, end the description with a "Wraps:" section that names the tool by its import path, links to its documentation, and names its package:
Wraps:
    [`sklearn.preprocessing.StandardScaler`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html)
    from scikit-learn.

List several tools as a list, each with what it is used for (such as "to classify"). A unit test checks that each tool in contents or tools is linked this way. 4. Make sure the technique learns only from the training rows, records what it did in the dataset's history, and uses the dataset's seed for anything random. 5. Add tests. Tests that use an optional package call requires (in tests/conftest.py) so that they are skipped where the package cannot be imported.

Examples in the README and the documentation are run by tests/test_docs.py. The comment lines after a print statement are its expected output.

The figures in the README are drawn by the breast cancer study in the README itself. If that study changes, draw them again (they are saved in docs/img):

uv run python docs/scripts/readme_figures.py

Pull requests guidelines

Link to any related issue in the Pull Request message.

During the review, we recommend using fixups:

# SHA is the SHA of the commit you want to fix
git commit --fixup=SHA

Once all the changes are approved, you can squash your commits:

git rebase -i --autosquash main

And force-push:

git push -f

If this seems all too complicated, you can push or force-push each new commit, and we will squash them ourselves if needed, before merging.

Style Guidelines

This package follows the Google Python Style Guide with two notable exceptions:

  1. It always adds spaces around "=". This not only violates the Google guide, it violates PEP8, the foundational Python style guide from which all other resources are derived. I defy this strong, long-standing norm because I find it more readable. My brain and eyes have trouble seeing two separate objects when an equal sign is in the middle. I imagine that I am not alone in this accessibility issue. Further, as PEP8 itself notes, required spaces around equal signs are becoming increasing common with type annotations becoming part of best practices (and, as a result, signatures to classes, functions, and methods regularly include spaces around the equal signs). I realize that this will seem alien to many coders, but it is far easier on my eyes.
  2. I use some so-called "power features", primarily dunder methods, to make my interfaces easier to access and use. This is disfavored in the Google Python Style Guide because such code is often more difficult for others to read. To address that concern, I try to document and comment as to what the code is doing whenever I used any of the "power features" of Python.

Because of the first exception, the project does not use a code formatter (such as ruff format), which would remove those spaces.