-
Notifications
You must be signed in to change notification settings - Fork 39
218 lines (209 loc) · 10.1 KB
/
Copy pathtests.yml
File metadata and controls
218 lines (209 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
name: Tests
on:
push:
branches: [main]
pull_request:
concurrency:
group: tests-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: pytest (py${{ matrix.python }}, ani=${{ matrix.ani }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python: ["3.11", "3.12"]
ani: [false]
include:
- python: "3.12"
ani: true
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: ${{ matrix.python }}
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[ase,dev]" # dev provides pytest/pytest-cov
- name: Install ani extra
if: matrix.ani
run: pip install -e ".[ani]"
- name: Verify every test module imports
# --continue-on-collection-errors on the fast run hides a module that
# fails to import, so assert collection cleanliness separately.
run: pytest tests/ --collect-only -q
- name: Run fast tests
run: pytest tests/ -q -m "not slow" --continue-on-collection-errors
# Here rather than in `lint`, because this job is the only one that
# installs the dependencies. mypy resolves a third-party import to `Any`
# when the package is absent, so a dep-free run cannot see a wrong tensor,
# array or ASE argument at all -- it reported 40 errors where a run with
# the extras present reports 66, and the 26 it missed are precisely the
# ones a type checker is worth having here for.
#
# Only on the `ani` leg: three near-identical reports are noise, and this
# is the leg with the most complete type information. Running it under
# 3.12 does not weaken the floor -- `python_version = "3.11"` in
# pyproject.toml is what decides the semantics checked, not the
# interpreter.
- name: mypy (non-blocking until type debt is cleared)
if: matrix.ani
run: mypy src/Auto3D/ || true
no-aimnet:
# The conda-forge package will ship Auto3D's dependency set minus aimnet
# plus torchani and ase -- aimnet cannot be packaged for conda-forge (its
# dependency nvalchemi-toolkit-ops is pip-only). conda-recipe/meta.yaml is
# updated to that shape as part of the 3.1.1 release. This job emulates
# that environment and is the enforcement mechanism for the no-aimnet
# path: without it, the path rots the first time someone adds a
# module-level `import aimnet`.
#
# `pip uninstall -y aimnet` below leaves aimnet's own transitive
# dependencies installed, so this emulation cannot catch code that leans
# on a package that only arrives via aimnet's dependency tree -- the
# genuine conda build is the true gate for that.
name: no-aimnet (conda package environment)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Install, then remove aimnet
run: |
python -m pip install --upgrade pip
pip install -e ".[ani,ase,dev]"
pip uninstall -y aimnet
- name: Bare import works without aimnet
run: python -c "import Auto3D"
- name: Whole-suite collection stays clean without aimnet
run: pytest tests/ --collect-only -q
- name: No-aimnet behavior tests
run: pytest tests/test_no_aimnet.py -q
- name: ANI2xt still constructs (bundled weights, no download)
run: pytest "tests/test_model_factory.py" -q -k "ani2xt"
slow:
name: slow tests (NNP integration)
runs-on: ubuntu-latest
# These tests are NNP inference on CPU, so their wall time tracks whatever
# share of the runner we get. Three consecutive runs of the same commit
# took 6m21s, 17m57s and 6m52s: the middle one exceeded the old 20-minute
# ceiling and was cancelled *after* all 58 tests had passed, reporting a
# red slow tier for code that was fine. A job that fails on runner luck
# teaches people to ignore it, which is worse than a job that is slow.
# 45 gives roughly 2.5x headroom over the worst observed run while still
# catching a genuine hang.
timeout-minutes: 45
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Cache downloaded model weights
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# AIMNet2 weights download to ~/.cache/aimnet; torchani/torch.hub
# weights (ANI2x) land in ~/.cache/torch. Cache both so the slow
# suite does not re-download on every run.
path: |
~/.cache/aimnet
~/.cache/torch
key: nnp-model-cache-v1
- name: Install
run: |
python -m pip install --upgrade pip
# ase for thermo, ani for the torchani-gated slow tests, dev for pytest
pip install -e ".[ase,ani,dev]"
- name: Warm the AIMNet2 model cache (hard failure if unreachable)
# An unavailable gate must never be reportable as a passing gate. If the
# registry or network is down, fail here loudly rather than letting the
# suite skip or silently pass (audit: the remediation gate depends on
# this model being present).
run: |
python - <<'PY'
import sys
import torch
from Auto3D.engines.model_factory import create_model
try:
create_model("AIMNET", torch.device("cpu"))
except Exception as exc:
print(f"::error::AIMNet2 model unavailable, gate cannot run: {exc}")
sys.exit(1)
print("AIMNet2 model cache warm")
PY
- name: Run slow NNP + pipeline tests
# Previously limited to three files because the heavy end-to-end modules
# were flaky under combined ordering. test_auto3D.py now runs every
# pipeline test through the job_dir/isolated_input fixtures and
# test_thermo.py stages its opt_geometry inputs in tmp_path, so those
# two no longer write job directories or output SDFs into
# tests/files/. The remaining three (test_SPE.py, test_isomer_engine.py,
# test_tauto.py) still do not use the fixtures, so for them the
# protection is unchanged: main()'s microsecond-resolution job naming,
# strictly serial CI execution, and the autouse GPU-teardown fixture
# applied via the `slow` marker -- assessed at 70-80% confidence, not
# guaranteed (audit M31).
run: >
pytest tests/ -m slow -q
# Executes one notebook for real. Here rather than in the docs workflow
# because every one of the 20 needs a neural network potential, and this
# is the only job with the model cache and the `ani` extra.
#
# One, and the selection was measured on a CPU box with CUDA hidden --
# which is what a runner is -- rather than on a machine with a GPU. The
# dividing line is not notebook size, it is whether the notebook runs an
# optimization:
#
# single_point_energy (calc_spe, 4 records) 5.9 s
# geometry_optimization (opt_geometry, 4 records) > 600 s
#
# The same optimization notebook takes 74 s on a GPU, which is how it
# first looked affordable. Every other notebook either optimizes or runs
# `main()` end to end, so all of them land on the wrong side of that line;
# those paths are covered by the slow test tier above instead.
#
# What this closes: this notebook calling a function Auto3D no longer has,
# or passing an argument it no longer accepts, now fails here. What it
# does not: the other 19 are still parse-checked only, so the guard in
# tests/test_notebook_properties.py remains the only thing covering all
# 20 -- and it catches a wrong SD property name, not a wrong call.
- name: Execute the single-point notebook
run: |
pip install nbmake
pytest --nbmake --nbmake-timeout=600 example/single_point_energy.ipynb
lint:
name: ruff
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
# ruff needs no dependencies installed; mypy does, so it runs in the
# `test` job instead. See the note on that step.
# Pinned exactly, and matching the `dev` extra in pyproject.toml, because
# `ruff format --check` is a gate: ruff promotes formatting-style changes
# into its stable style across minor releases, with settings unchanged.
# An unpinned install turns any such release into a red build on whichever
# unrelated pull request happens to be open that day -- the same
# fails-on-luck failure mode the slow job's timeout comment describes.
#
# Bumping it is a deliberate act: raise both pins together, and if the new
# version reformats anything, that reformat is its own commit and its own
# `.git-blame-ignore-revs` entry.
- name: Install tooling
run: pip install ruff==0.15.9
- name: ruff check
run: ruff check src/Auto3D/ tests/
# CONTRIBUTING.md has told contributors to run `ruff format src/ tests/`
# since long before anything checked. Nothing did, so the tree drifted
# until the documented command produced a 169-file diff -- at which point
# nobody could follow the instruction on an ordinary pull request, and the
# drift compounded. The gate is the half that makes the instruction true.
#
# Unlike the mypy step, this one does NOT end in `|| true`. It starts from
# zero and the fix is one command, so there is no debt to grandfather.
- name: ruff format
run: ruff format --check src/ tests/