Development#
We use the following tools and guidelines when developing opda.
Before contributing to opda
Before contributing to opda, it’s a good idea to discuss in an issue what you’d like to do. A pull request might not get accepted. You can save effort by discussing things beforehand and reducing the chance of this outcome.
Make sure you’ve installed all optional dependencies and python versions necessary for development.
Run the full validation suite via nox:
$ pip install --editable .[ci]
$ nox
Run the full suite on every commit.
You can find more on specific topics below.
Tests#
Run tests with pytest:
$ pytest
Some tests use randomness. For reproducibility, the random seed prints
when a test fails if the log level is at least INFO
(the default).
Tests are organized into levels. Lower levels run faster and are
suitable for quick feedback during development. To run the tests at and
below a specific level, use the --level
option:
$ pytest --level 2
Tests up to level 0 are run by default. Tests without a specified level
are always run. To run all levels, use the --all-levels
option:
$ pytest --all-levels
You can also use nox to run the tests (e.g., in continuous integration):
$ nox --session test
Lint#
Lint the repository using ruff:
$ ruff check .
Use ruff check --watch .
to continually lint the repository with
updates on file changes.
This project does not use a formatter. Basic stylistic conventions are enforced by the linter; otherwise, style should be used to maximize the readability and communicate the intent of the code.
The linter can automatically fix many errors it identifies, which can be helpful for formatting the more rote stylistic issues:
$ ruff check --fix .
For continuous integration, run the linter via nox:
$ nox --session lint
You can also use nox to verify that the repository conforms to its target support policy for Python and core dependency versions:
$ nox --session support
Docs#
Build the docs with Sphinx.
First, generate the API reference documentation:
$ rm -rf docs/reference/ # delete existing files if necessary
$ SPHINX_APIDOC_OPTIONS='members' \
sphinx-apidoc \
--separate \
--no-toc \
--maxdepth 1 \
--module-first \
--output-dir docs/reference/ \
src/opda/
Then, build the documentation:
$ sphinx-build \
--jobs auto \
-W \
--keep-going \
-d "docs/_build/doctrees/" \
-b html \
docs/ docs/_build/html/
Finally, serve the documentation locally using Python’s
http.server
:
$ python -m http.server --directory docs/_build/html/
Now, you can navigate in your browser to the printed URL in order to view the docs.
To validate the documentation, check for broken links using
linkcheck
:
$ sphinx-build \
--jobs auto \
-W \
--keep-going \
-d "docs/_build/doctrees/" \
-b linkcheck \
docs/ docs/_build/linkcheck/
And test the documentation’s correctness by executing examples as
doctests
:
$ pytest \
--doctest-modules \
--doctest-glob "**/*.rst" \
-- README.rst docs/ src/
--doctest-modules
runs doctests from the docstrings in any python
modules, while --doctest-globs "**/*.rst"
searches reStructuredText
files for doctests. The arguments (README.rst docs/ src/
) ensure
pytest looks at the right paths for these tests.
In continuous integration, we build and test the documentation via nox:
$ nox --session docs
Packaging#
Before building the package, you must preprocess
pyproject.toml to remove parts specific to local
installations. The easiest way to do this is to run the package
session using nox:
$ nox --session package
After running this session, you’ll find the dist/
directory
containing the built distributions. See the package
session in
noxfile.py for further details.
You can test the package against all supported versions of Python and
the core dependencies using the testpackage
nox session.
$ nox --session testpackage -- dist/*.whl
It takes one positional argument: the package to test. The separator for
options and arguments, --
, is required.
As there are many possible combinations of supported versions, running all of these tests will take a long time. You might prefer to run a particular combination instead:
$ nox \
--session "testpackage-3.11(numpy='1.26', scipy='1.12')" \
-- \
dist/*.whl
Use nox --list
to see all supported combinations.
Conventions#
This project uses the following unique conventions to help with maintenance.
# backwards compatibility
All backwards compatibility code should have a
# backwards compatibility (${DEPENDENCY} < ${VERSION})
comment either before:# backwards compatibility (Python < 3.11) import sys ...
or on the same line:
session.install("pip >= 21.2") # backwards compatibility (pip < 21.2)
That way, when dependencies are updated, it’s easy to find and remove unnecessary backwards compatibility code.
# build: local-only
Some lines in pyproject.toml should only be used for local builds, and not the distribution package. Mark these lines with a
# build: local-only
comment at the end, or place these lines after the# -- build: local-only -----
header.- Pull request conventions
Merge new changes via pull requests. Use the branch name for the pull request’s name. Merge commit messages should match git’s default:
"Merge branch '${BRANCH}'"
with no further description.