Developing mass-driver

Read below the project’s “Development” section of the README for guidance on development.

Python setup

This repository uses Python3.11, using Poetry as package manager to define a Python package inside src/mass_driver/.

poetry will create virtual environments if needed, fetch dependencies, and install them for development.

For ease of development, a Makefile is provided, use it like this:

make  # equivalent to "make all" = install lint docs test build
# run only specific tasks:
make install
make lint
make test
# Combine tasks:
make install test

Once installed, the module’s code can now be reached through running Python in Poetry:

$ poetry run python
>>> from mass_driver import main
>>> main("blabla")

This codebase uses pre-commit to run linting tools like ruff. Use pre-commit install to install git pre-commit hooks to force running these checks before any code can be committed, use make lint to run these manually. Testing is provided by pytest separately in make test.

Documentation

Documentation is generated via Sphinx, using the cool myst_parser plugin to support Markdown files like this one.

Other Sphinx plugins provide extra documentation features, like the recent sphinx-autodoc2 to generate API reference without headaches, and with myst-markdown support in docstrings too!

To build the documentation, run

# Requires the project dependencies provided by "make install"
make docs
# Generates docs/build/html/

To browse the website version of the documentation you just built, run:

make docs-serve

And remember that make supports multiple targets, so you can generate the documentation and serve it:

make docs docs-serve

Makefile

In order to automate (less typing) and document (list in one place) the development commands, a Makefile is provided at the repo’s root.

See it here:

DOCKER_IMAGE_NAME=mass-driver
APP_VERSION=$(shell poetry version --short)

.PHONY: all
all: install lint test docs build install-hooks

.PHONY: install
install:
	poetry install

# Enforce the pre-commit hooks
.PHONY: install-hooks
install-hooks:
	pre-commit install

.PHONY: lint
lint:  # Use all linters on all files (not just staged for commit)
	pre-commit run --all --all-files

.PHONY: test
test:
	poetry run pytest

ACTION=run --no-pause
FILE=clone.toml
.PHONY: run
run:  # Remember to export GITHUB_API_TOKEN beforehand
	poetry run mass-driver ${ACTION} ${FILE}

.PHONY: docs
docs: clean-docs
	cd docs && make html
	poetry run doc2dash \
		--force \
		--name mass-driver \
		docs/build/html \
		--destination docs/build/docset \
		--icon docs/source/_static/icon_small.png

.PHONY: clean-docs
clean-docs:
	-find docs/build/ -delete

.PHONY: docs-serve
docs-serve:
	cd docs/build/html && python3 -m http.server

.PHONY: build
build:
	poetry build

.PHONY: docker-build-release
docker-build-release:
	docker build \
		-t "${DOCKER_IMAGE_NAME}:${APP_VERSION}" \
		-f release.Dockerfile \
		.

.PHONY: docker-build-dev
docker-build-dev:
	docker build -t ${DOCKER_IMAGE_NAME}-dev .

# Make a release commit + tag, creating Changelog entry
# Set BUMP variable to any of poetry-supported (major, minor, patch)
# or number (1.2.3 etc), see 'poetry version' docs for details
.PHONY: release
# Default the bump to a patch (v1.2.3 -> v1.2.4)
release: BUMP=patch
release:
# Set the new version Makefile variable after the version bump
	$(eval NEW_VERSION := $(shell poetry version --short ${BUMP}))
	sed -i \
		"s/\(## \[Unreleased\]\)/\1\n\n## v${NEW_VERSION} - $(shell date -I)/" \
		CHANGELOG.md
	git add CHANGELOG.md pyproject.toml
	git commit -m "Bump to version v${NEW_VERSION}"
	git tag -a v${NEW_VERSION} \
		-m "Release v${NEW_VERSION}"

# Less commonly used commands

# Generate/update the poetry.lock file
.PHONY: lock
lock:
	poetry lock --no-update

# Update dependencies (within pyproject.toml specs)
# Update the lock-file at the same time
.PHONY: update
update:
	poetry update --lock

# Generate a pip-compatible requirements.txt
# From the poetry.lock. Mostly for CI use.
.PHONY: export-requirements
export-requirements:
	poetry run pip freeze > requirements.txt

# Install poetry from pip
# IMPORTANT: Make sure "pip" resolves to a virtualenv
# Or that you are happy with poetry installed system-wide
.PHONY: install-poetry
install-poetry:
	pip install poetry

# Ensure Poetry will generate virtualenv inside the git repo /.venv/
# rather than in a centralized location. This makes it possible to
# manipulate venv more simply
.PHONY: poetry-venv-local
poetry-venv-local:
	poetry config virtualenvs.in-project true

# Delete the virtualenv to clean dependencies
# Useful when switching to a branch with less dependencies
# Requires the virtualenv to be local (see "poetry-venv-local")
.PHONY: poetry-venv-nuke
poetry-venv-nuke:
	find .venv -delete