Skip to content

Commit b053b4d

Browse files
committed
Converted to use uv and hatch over venv and tox
1 parent 6efc60c commit b053b4d

File tree

9 files changed

+129
-55
lines changed

9 files changed

+129
-55
lines changed

.devcontainer/devcontainer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"remoteEnv": {
99
// Allow X11 apps to run inside the container
1010
"DISPLAY": "${localEnv:DISPLAY}"
11+
// Add venv to path for cmd line tools to be recognised by default, e.g. hatch
12+
"PATH": "${containerWorkspaceFolder}/.venv/bin:${containerEnv:PATH}"
1113
},
1214
"customizations": {
1315
"vscode": {
@@ -41,6 +43,6 @@
4143
],
4244
// Mount the parent as /workspaces so we can pip install peers as editable
4345
"workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind",
44-
// After the container is created, install the python project in editable form
45-
"postCreateCommand": "pip install $([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e '.[dev]' && pre-commit install"
46+
// After the container is created, install the uv env
47+
"postCreateCommand": "bash .devcontainer/post-install.sh"
4648
}

.github/actions/install_requirements/action.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ inputs:
44
python-version:
55
description: Python version to install, default is from Dockerfile
66
default: "dev"
7-
pip-install:
8-
description: Parameters to pass to pip install
9-
default: "$([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e .[dev]"
107

118
runs:
129
using: composite
@@ -20,15 +17,25 @@ runs:
2017
echo "PYTHON_VERSION=$PYTHON_VERSION" >> "$GITHUB_ENV"
2118
shell: bash
2219

23-
- name: Setup python
24-
uses: actions/setup-python@v5
20+
- name: Install uv and set the python version
21+
uses: astral-sh/setup-uv@v5
2522
with:
2623
python-version: ${{ env.PYTHON_VERSION }}
24+
enable-cache: true
25+
cache-dependency-glob: "uv.lock"
2726

28-
- name: Install packages
29-
run: pip install ${{ inputs.pip-install }}
27+
- name: Install dependencies
28+
run: uv sync --dev
3029
shell: bash
3130

3231
- name: Report what was installed
33-
run: pip freeze
32+
run: uv pip list
33+
shell: bash
34+
35+
- name: Add venv path to Github environment
36+
run: echo "VENV_PATH=.venv" >> $GITHUB_ENV
37+
shell: bash
38+
39+
- name: Add venv path to Github Path
40+
run: echo "${{ env.VENV_PATH }}/bin:$PATH" >> $GITHUB_PATH
3441
shell: bash

.github/workflows/_hatch.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
on:
2+
workflow_call:
3+
inputs:
4+
hatch:
5+
type: string
6+
description: What to run under hatch
7+
required: true
8+
9+
10+
jobs:
11+
run:
12+
runs-on: "ubuntu-latest"
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Install python packages
19+
uses: ./.github/actions/install_requirements
20+
21+
- name: Run hatch
22+
run: |
23+
IFS=',' read -ra SCRIPTS <<< "${{ inputs.hatch }}"
24+
for script in "${SCRIPTS[@]}"; do
25+
echo "Running $script"
26+
hatch run $script
27+
done

.github/workflows/_release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Create GitHub Release
2424
# We pin to the SHA, not the tag, for security reasons.
2525
# https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions
26-
uses: softprops/action-gh-release@7b4da11513bf3f43f9999e90eabced41ab8bb048 # v2.2.0
26+
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1
2727
with:
2828
prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
2929
files: "*"

.github/workflows/_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
pip-install: ".[dev]"
5252

5353
- name: Run tests
54-
run: tox -e tests
54+
run: hatch run tests
5555

5656
- name: Upload coverage to Codecov
5757
uses: codecov/codecov-action@v5

.github/workflows/ci.yml

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,45 @@ jobs:
1111
lint:
1212
needs: check
1313
if: needs.check.outputs.branch-pr == ''
14-
uses: ./.github/workflows/_tox.yml
14+
uses: ./.github/workflows/_hatch.yml
1515
with:
16-
tox: pre-commit
16+
hatch: precommit,type-check
1717

1818
test:
1919
needs: check
2020
if: needs.check.outputs.branch-pr == ''
21+
strategy:
22+
matrix:
23+
runs-on: ["ubuntu-latest"] # can add windows-latest, macos-latest
24+
python-version: ["3.11"]
25+
include:
26+
# Include one that runs in the dev environment
27+
- runs-on: "ubuntu-latest"
28+
python-version: "dev"
29+
fail-fast: false
2130
uses: ./.github/workflows/_test.yml
2231
with:
23-
python-version: dev
24-
runs-on: ubuntu-latest
32+
runs-on: ${{ matrix.runs-on }}
33+
python-version: ${{ matrix.python-version }}
2534
secrets:
2635
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
2736

28-
docs:
37+
container:
2938
needs: check
3039
if: needs.check.outputs.branch-pr == ''
31-
uses: ./.github/workflows/_docs.yml
40+
uses: ./.github/workflows/_container.yml
3241
permissions:
33-
contents: write
42+
contents: read
43+
packages: write
3444

35-
example:
36-
needs: test
37-
if: github.ref_name == 'main'
38-
uses: ./.github/workflows/_example.yml
39-
secrets:
40-
EXAMPLE_DEPLOY_KEY: ${{ secrets.EXAMPLE_DEPLOY_KEY }}
45+
dist:
46+
needs: check
47+
if: needs.check.outputs.branch-pr == ''
48+
uses: ./.github/workflows/_dist.yml
4149

4250
release:
4351
if: github.ref_type == 'tag'
44-
needs: docs
52+
needs: [dist]
4553
uses: ./.github/workflows/_release.yml
4654
permissions:
4755
contents: write

Dockerfile

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,28 @@ ARG PYTHON_VERSION=3.11
44
FROM python:${PYTHON_VERSION} AS developer
55

66
# Add any system dependencies for the developer/build environment here
7-
RUN apt-get update && apt-get install -y --no-install-recommends \
8-
graphviz \
9-
&& rm -rf /var/lib/apt/lists/*
7+
RUN apt-get update && apt upgrade -y && rm -rf /var/lib/apt/lists/*
8+
# Install uv using the official installer script
9+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
10+
11+
# The build stage installs the context into the venv
12+
FROM developer AS build
13+
# install uv
14+
RUN pip install -U uv
15+
# disable update check
16+
ENV UV_CHECK_UPDATE=false
17+
# copy files
18+
# * means it will only try to copy uv.lock if it exists already
19+
COPY pyproject.toml uv.lock* README.md LICENSE /project/
20+
COPY src/ /project/src
21+
22+
# install dependencies and project into the local packages directory
23+
WORKDIR /project
24+
RUN uv sync --dev --no-editable
25+
26+
# The runtime stage copies the built venv into a slim runtime container
27+
FROM python:${PYTHON_VERSION}-slim AS runtime
28+
# Add apt-get system dependecies for runtime here if needed
29+
COPY --from=build /project/.venv/ /project/.venv
30+
ENV PATH="/project/.venv/bin:$PATH"
1031

11-
# Set up a virtual environment and put it in PATH
12-
RUN python -m venv /venv
13-
ENV PATH=/venv/bin:$PATH

post-install.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pip install --upgrade pip
2+
uv python install
3+
uv sync --dev

pyproject.toml

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ requires-python = ">=3.10"
99

1010
[project.optional-dependencies]
1111
dev = [
12+
"basedpyright>=1.27.1",
1213
"copier",
14+
"hatch>=1.14.0",
1315
"myst-parser",
1416
"pre-commit",
1517
"pydata-sphinx-theme>=0.12",
16-
"pytest",
18+
"pytest>=8.3.4",
1719
"ruff",
1820
"sphinx-autobuild",
1921
"sphinx-copybutton",
2022
"sphinx-design",
21-
"tox",
22-
"tox-direct",
2323
]
2424

25+
[tool.uv]
26+
default-groups = []
27+
2528
[tool.setuptools_scm]
2629

2730
[tool.pytest.ini_options]
@@ -32,27 +35,33 @@ addopts = """
3235
# Doctest python code in docs, python code in src docstrings, test functions in tests
3336
testpaths = "tests"
3437

35-
# tox must currently be configured via an embedded ini string
36-
# See: https://github.com/tox-dev/tox/issues/999
37-
[tool.tox]
38-
legacy_tox_ini = """
39-
[tox]
40-
skipsdist=True
38+
[tool.hatch.envs.default.scripts]
39+
all = [
40+
"hatch run precommit:precommit",
41+
"hatch run type-check:type-check",
42+
"hatch run tests:tests",
43+
"hatch run docs:docs"
44+
]
45+
precommit = ["hatch run precommit:precommit"]
46+
type-check = ["hatch run type-check:type-check"]
47+
tests = ["hatch run tests:tests"]
48+
docs = ["hatch run docs:docs"]
49+
50+
[tool.hatch.envs.precommit]
51+
description = "Run pre-commit"
52+
scripts = { precommit = ["pre-commit run --show-diff-on-failure {args}"] }
53+
54+
[tool.hatch.envs.type-check]
55+
description = "Run type-checking"
56+
scripts = { type-check = ["basedpyright --stats src {args}"] }
57+
58+
[tool.hatch.envs.tests]
59+
description = "Run tests"
60+
scripts = { tests = ["pytest {args}"] }
4161

42-
[testenv:{pre-commit,tests,docs}]
43-
# Don't create a virtualenv for the command, requires tox-direct plugin
44-
direct = True
45-
passenv = *
46-
allowlist_externals =
47-
pre-commit
48-
pytest
49-
sphinx-build
50-
sphinx-autobuild
51-
commands =
52-
pre-commit: pre-commit run --all-files --show-diff-on-failure {posargs}
53-
tests: pytest {posargs}
54-
docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html
55-
"""
62+
[tool.hatch.envs.docs]
63+
description = "Run docs"
64+
scripts = { docs = ["sphinx-{args:build} -EW --keep-going -T docs build/html"] }
5665

5766
[tool.ruff]
5867
src = ["src", "tests"]

0 commit comments

Comments
 (0)