Skip to content

Commit 5d9e666

Browse files
authored
chore: Switch to tox for testing and CI (#900)
* chore(deps): Update lower bounds so uv lowest-direct passes tests * chore(tox): Adapt tox from fmriprep, use uv_resolution * chore(ci): Switch to tox-gh-actions for testing * Replace test workflow with tox * chore: Pin pyyaml 5.4 * chore: Update pytest/coverage config * ci: Add FORCE_COLOR to CI environment * ci: Skip pre-release tests for 3.9/3.10
1 parent b898643 commit 5d9e666

File tree

3 files changed

+216
-191
lines changed

3 files changed

+216
-191
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 67 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3-
4-
name: Python package
1+
name: Tox
52

63
on:
74
push:
@@ -13,42 +10,17 @@ on:
1310
- cron: '0 0 * * *'
1411

1512
concurrency:
16-
group: python-${{ github.ref }}
13+
group: ${{ github.workflow }}-${{ github.ref }}
1714
cancel-in-progress: true
1815

19-
jobs:
20-
job_metadata:
21-
if: github.repository == 'nipreps/niworkflows'
22-
runs-on: ubuntu-latest
23-
outputs:
24-
commit_message: ${{ steps.get_commit_message.outputs.commit_message }}
25-
version: ${{ steps.show_version.outputs.version }}
26-
steps:
27-
- name: Checkout
28-
uses: actions/checkout@v4
29-
with:
30-
fetch-depth: 0
31-
- name: Print head git commit message
32-
id: get_commit_message
33-
run: |
34-
if [[ -z "$COMMIT_MSG" ]]; then
35-
COMMIT_MSG=$(git show -s --format=%s $REF)
36-
fi
37-
echo commit_message=$COMMIT_MSG | tee -a $GITHUB_OUTPUT
38-
env:
39-
COMMIT_MSG: ${{ github.event.head_commit.message }}
40-
REF: ${{ github.event.pull_request.head.sha }}
41-
- name: Detect version
42-
id: show_version
43-
run: |
44-
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
45-
VERSION=${GITHUB_REF##*/}
46-
else
47-
pipx run hatch version # Once to avoid output of initial setup
48-
VERSION=$( pipx run hatch version )
49-
fi
50-
echo version=$VERSION | tee -a $GITHUB_OUTPUT
16+
permissions:
17+
contents: read
18+
19+
env:
20+
# Force tox and pytest to use color
21+
FORCE_COLOR: true
5122

23+
jobs:
5224
build:
5325
if: github.repository == 'nipreps/niworkflows'
5426
runs-on: ubuntu-latest
@@ -118,140 +90,73 @@ jobs:
11890
datalad get -J 2 -r ds000003 ds000030/sub-10228/func
11991
12092
test:
121-
needs: [build, get_data, job_metadata]
93+
needs: [get_data]
12294
runs-on: ubuntu-latest
12395
strategy:
12496
matrix:
12597
python-version: ["3.9", "3.10", "3.11", "3.12"]
126-
install: [repo]
98+
dependencies: [latest, pre]
12799
include:
128-
- python-version: "3.12"
129-
install: sdist
130-
- python-version: "3.12"
131-
install: wheel
132-
- python-version: "3.12"
133-
install: editable
134-
135-
env:
136-
INSTALL_TYPE: ${{ matrix.install }}
137-
138-
steps:
139-
- uses: actions/checkout@v4
140-
if: matrix.install == 'repo' || matrix.install == 'editable'
141-
with:
142-
fetch-depth: 0
143-
- name: Set up Python ${{ matrix.python-version }}
144-
uses: actions/setup-python@v5
145-
with:
146-
python-version: ${{ matrix.python-version }}
147-
- name: Load test data cache
148-
uses: actions/cache@v4
149-
id: stanford-crn
150-
with:
151-
path: ~/.cache/stanford-crn/
152-
key: data-v0-${{ github.ref_name }}-${{ github.sha }}
153-
- name: Load TemplateFlow cache
154-
uses: actions/cache@v4
155-
id: templateflow
156-
with:
157-
path: ~/.cache/templateflow
158-
key: templateflow-v0-${{ github.ref_name }}-${{ strategy.job-index }}-${{ github.sha }}
159-
restore-keys: |
160-
templateflow-v0-${{ github.ref_name }}-
161-
templateflow-v0-
162-
- name: Fetch packages
163-
if: matrix.install == 'sdist' || matrix.install == 'wheel'
164-
uses: actions/download-artifact@v3
165-
with:
166-
name: dist
167-
path: dist/
168-
- name: Select archive
169-
run: |
170-
if [ "$INSTALL_TYPE" = "sdist" ]; then
171-
ARCHIVE=$( ls dist/*.tar.gz )
172-
elif [ "$INSTALL_TYPE" = "wheel" ]; then
173-
ARCHIVE=$( ls dist/*.whl )
174-
elif [ "$INSTALL_TYPE" = "repo" ]; then
175-
ARCHIVE="."
176-
elif [ "$INSTALL_TYPE" = "editable" ]; then
177-
ARCHIVE="-e ."
178-
fi
179-
echo "ARCHIVE=$ARCHIVE" | tee -a $GITHUB_ENV
180-
- name: Install package
181-
run: python -m pip install $ARCHIVE
182-
- name: Check version
183-
run: |
184-
INSTALLED_VERSION=$(python -c 'import niworkflows; print(niworkflows.__version__, end="")')
185-
echo "INSTALLED: \"${INSTALLED_VERSION}\""
186-
test "${INSTALLED_VERSION}" = "${VERSION}"
187-
env:
188-
VERSION: ${{ needs.job_metadata.outputs.version }}
189-
- name: Install test dependencies
190-
run: python -m pip install "niworkflows[tests]"
191-
- name: Run tests
192-
run: pytest -sv --doctest-modules --cov niworkflows --pyargs niworkflows
193-
- uses: codecov/codecov-action@v4
194-
name: Submit to CodeCov
195-
with:
196-
token: ${{ secrets.CODECOV_TOKEN }}
197-
198-
test-pre:
199-
needs: [get_data, job_metadata]
200-
if: ${{ !contains(needs.job_metadata.outputs.commit_message, '[skip pre]') }}
201-
runs-on: ubuntu-latest
202-
strategy:
203-
matrix:
204-
# Only run --pre tests on Python versions within SPEC0 support
205-
python-version: ["3.11", "3.12"]
206-
install: [repo]
207-
pip-flags: ['--pre']
100+
- python-version: "3.9"
101+
dependencies: min
102+
exclude:
103+
# Do not test pre-releases for versions out of SPEC0
104+
- python-version: "3.9"
105+
dependencies: pre
106+
- python-version: "3.10"
107+
dependencies: pre
208108

209109
env:
210-
INSTALL_TYPE: ${{ matrix.install }}
211-
PIP_FLAGS: ${{ matrix.pip-flags }}
110+
DEPENDS: ${{ matrix.dependencies }}
212111

213112
steps:
214-
- name: Debug commit message
215-
run: echo "${{ needs.job_metadata.outputs.commit_message }}"
216-
- uses: actions/checkout@v4
217-
with:
218-
fetch-depth: 0
219-
- name: Set up Python ${{ matrix.python-version }}
220-
uses: actions/setup-python@v5
221-
with:
222-
python-version: ${{ matrix.python-version }}
223-
- name: Load test data cache
224-
uses: actions/cache@v4
225-
id: stanford-crn
226-
with:
227-
path: ~/.cache/stanford-crn/
228-
key: data-v0-${{ github.ref_name }}-${{ github.sha }}
229-
- name: Load TemplateFlow cache
230-
uses: actions/cache@v4
231-
id: templateflow
232-
with:
233-
path: ~/.cache/templateflow
234-
key: templateflow-v0-${{ github.ref_name }}-${{ strategy.job-index }}-${{ github.sha }}
235-
restore-keys: |
236-
templateflow-v0-${{ github.ref_name }}-
237-
templateflow-v0-
238-
- name: Install package
239-
run: python -m pip install $PIP_FLAGS .
240-
- name: Check version
241-
run: |
242-
INSTALLED_VERSION=$(python -c 'import niworkflows; print(niworkflows.__version__, end="")')
243-
echo "INSTALLED: \"${INSTALLED_VERSION}\""
244-
test "${INSTALLED_VERSION}" = "${VERSION}"
245-
env:
246-
VERSION: ${{ needs.job_metadata.outputs.version }}
247-
- name: Install test dependencies
248-
run: python -m pip install $PIP_FLAGS "niworkflows[tests]"
249-
- name: Run tests
250-
run: pytest -sv --doctest-modules --cov niworkflows --pyargs niworkflows
251-
- uses: codecov/codecov-action@v4
252-
with:
253-
token: ${{ secrets.CODECOV_TOKEN }}
254-
name: Submit to CodeCov
113+
- uses: actions/checkout@v4
114+
with:
115+
submodules: recursive
116+
fetch-depth: 0
117+
- name: Install the latest version of uv
118+
uses: astral-sh/setup-uv@v3
119+
- name: Load test data cache
120+
uses: actions/cache@v4
121+
id: stanford-crn
122+
with:
123+
path: ~/.cache/stanford-crn/
124+
key: data-v0-${{ github.ref_name }}-${{ github.sha }}
125+
- name: Load TemplateFlow cache
126+
uses: actions/cache@v4
127+
id: templateflow
128+
with:
129+
path: ~/.cache/templateflow
130+
key: templateflow-v0-${{ github.ref_name }}-${{ strategy.job-index }}-${{ github.sha }}
131+
restore-keys: |
132+
templateflow-v0-${{ github.ref_name }}-
133+
templateflow-v0-
134+
- uses: actions/cache@v4
135+
with:
136+
path: ~/.cache/templateflow
137+
key: templateflow-v1
138+
- name: Install dependencies
139+
run: |
140+
sudo apt update
141+
sudo apt install -y --no-install-recommends graphviz
142+
- name: Set up Python ${{ matrix.python-version }}
143+
uses: actions/setup-python@v5
144+
with:
145+
python-version: ${{ matrix.python-version }}
146+
- name: Display Python version
147+
run: python -c "import sys; print(sys.version)"
148+
- name: Install tox
149+
run: |
150+
uv tool install tox --with=tox-uv --with=tox-gh-actions
151+
- name: Show tox config
152+
run: tox c
153+
- name: Run tox
154+
run: tox -v --exit-and-dump-after 1200
155+
- uses: codecov/codecov-action@v4
156+
with:
157+
file: coverage.xml
158+
token: ${{ secrets.CODECOV_TOKEN }}
159+
if: ${{ always() }}
255160

256161
flake8:
257162
if: github.event_name != 'schedule'

pyproject.toml

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@ classifiers = [
2424
]
2525
dependencies = [
2626
"acres",
27-
"attrs",
27+
"attrs >=20.1",
2828
"importlib_resources >= 5.7; python_version < '3.11'",
29-
"jinja2",
29+
"jinja2 >=3",
3030
"looseversion",
31-
"matplotlib >= 3.4.2",
31+
"matplotlib >= 3.5",
3232
"nibabel >= 3.0",
33-
"nilearn >= 0.5.2",
33+
"nilearn >= 0.8",
3434
"nipype >= 1.8.5",
35-
"nitransforms >= 21.0.0",
36-
"numpy",
35+
"nitransforms >= 22.0.0",
36+
"numpy >= 1.20",
3737
"packaging",
38-
"pandas",
38+
"pandas >= 1.2",
3939
"pybids >= 0.15.1",
40-
"PyYAML",
41-
"scikit-image",
42-
"scipy",
43-
"seaborn",
40+
"PyYAML >= 5.4",
41+
"scikit-image >= 0.18",
42+
"scipy >= 1.8",
43+
"seaborn >= 0.11",
4444
"svgutils >= 0.3.4",
45-
"templateflow >= 0.7.2",
46-
"transforms3d",
45+
"templateflow >= 23.1",
46+
"transforms3d >= 0.4",
4747
]
4848

4949
[project.optional-dependencies]
@@ -62,12 +62,12 @@ style = [
6262
"flake8 >= 3.7.0",
6363
]
6464
tests = [
65-
"coverage >=5.2.1",
66-
"pytest >= 4.4",
67-
"pytest-cov",
65+
"coverage[toml] >=5.2.1",
66+
"pytest >= 6",
67+
"pytest-cov >= 2.11",
6868
"pytest-env",
69-
"pytest-xdist >= 1.28",
70-
"pytest-xvfb",
69+
"pytest-xdist >= 2.5",
70+
"pytest-xvfb >= 2",
7171
]
7272
# Aliases
7373
all = ["niworkflows[doc,pointclouds,style,tests]"]
@@ -116,23 +116,31 @@ skip-string-normalization = true
116116
extend-exclude = '_version.py'
117117

118118
[tool.pytest.ini_options]
119-
norecursedirs = ".git"
120-
addopts = "-sv --doctest-modules"
119+
minversion = "6"
120+
testpaths = ["niworkflows"]
121+
log_cli_level = "INFO"
122+
xfail_strict = true
123+
norecursedirs = [".git"]
124+
addopts = [
125+
"-svx",
126+
"-ra",
127+
"--strict-config",
128+
"--strict-markers",
129+
"--doctest-modules",
130+
# Config pytest-cov
131+
"--cov=niworkflows",
132+
"--cov-report=xml",
133+
"--cov-config=pyproject.toml",
134+
]
121135
doctest_optionflags = "ALLOW_UNICODE NORMALIZE_WHITESPACE ELLIPSIS"
122-
env = """
123-
PYTHONHASHSEED=0
124-
"""
125-
filterwarnings = """
126-
ignore::DeprecationWarning
127-
"""
136+
env = "PYTHONHASHSEED=0"
137+
filterwarnings = ["ignore::DeprecationWarning"]
128138
junit_family = "xunit2"
129139

130140
[tool.coverage.run]
131141
branch = true
132142
omit = [
133-
"*/tests/*",
134-
"niworkflows/_version.py",
135-
"niworkflows/conftest.py",
143+
"*/_version.py",
136144
]
137145

138146
[tool.coverage.report]
@@ -141,3 +149,9 @@ exclude_lines = [
141149
"raise NotImplementedError",
142150
"warnings\\.warn",
143151
]
152+
153+
[tool.coverage.paths]
154+
source = [
155+
"niworkflows",
156+
"**/site-packages/niworkflows"
157+
]

0 commit comments

Comments
 (0)