Development#

Clone the Git repository:

git clone https://github.com/cachedjdk/cjdk.git
cd cjdk

Make sure to enable the pre-commit Git hooks:

uv tool install pre-commit
# Or: pipx install pre-commit
pre-commit install

We use ty for type checking. This will be added to the pre-commit hook in the future (when an official ty hook is available), but for now, you can run it manually:

uv run ty check

To run the tests:

uv run pytest

To build the documentation with Jupyter Book:

CJDK_HIDE_PROGRESS_BARS=1 uv run --group docs jb build docs/
# Now view docs/_build/html/index.html

Some of the documentation pages are Jupyter notebooks stored in MyST Markdown format using Jupytext. To edit these in Jupyter Lab, right-click the file and select “Open With > Notebook” (if it asks you to select a kernel, you probably tried to open a Markdown file that is not a notebook).

New notebook pages can be added by first creating the notebook (.ipynb) in Jupyter Lab, then running jupytext mypage.ipynb --to myst. Delete the .ipynb file so that the MyST (.md) file is the single source of truth.

Modularity#

We try to maintain good separation of concerns between modules, each of which should have a single area of responsibility. The division will undoubtedly evolve over time. See each module’s docstring for their intended scope (and keep it up to date!). Think hard before introducing new dependencies between modules.

All internal modules (which currently are all modules except for __init__.py) begin with an underscore. The public API is defined by _api and _exceptions and exposed by __init__.py. The command-line interface, defined in __main__.py, uses the public API only.

All module-internal names are prefixed with an underscore. Such names should not be used from another module. Modules must avoid reaching into each other’s internals.

Testing#

Everything should have a unit test. In this project, we avoid access to the internet and to the user’s cjdk cache directory in all unit tests. Instead, temporary directories are used to mock the cache, and, where needed, a mock server is used to test downloads.

Unit test modules should try not to import cjdk modules other than the one under test, although sometimes this is unavoidable.

Actual use of the internet (including the Coursier index) and the user cache directory is limited to integration tests, which are kept separate.

Versioning#

cjdk uses SemVer 2, with the scope of API for versioning purposes comprising the Python API, command-line interface, and environment variables for configuration.

As specified by SemVer, anything can change during the 0.x series, although the plan is to keep disruptive changes to a minimum.

Making API changes#

  1. Document in docstring. For Python API, follow our flavor of NumPy style.

  2. List in the “unreleased” section of docs/changelog.md. Change the planned next release version if necessary.

  3. Document in Jupyter Book (docs/). Add versionadded, versionchanged, or deprecated directive.

If changing the next release version, ensure that any existing versionadded, versionchanged, or deprecated directives are updated.

Release procedure#

  1. Ensure docs/changelog.md lists all changes since the last release, and convert the “unreleased” section to the new version.

  2. Also ensure that there are no versionadded, versionchanged, or deprecated directives with a patch or minor version that is being skipped without releasing.

  3. Tag the commit to release.

The rest is taken care of automatically.