Fix skala.ase import failure on CPU-only environments#71
Merged
Conversation
skala.gpu4pyscf/__init__.py used pytest.skip(allow_module_level=True) at module load time when CUDA was unavailable. pytest.skip raises pytest.outcomes.Skipped, which derives from BaseException, not ImportError. The try/except ImportError around 'import skala.gpu4pyscf' in skala.ase.calculator therefore did not catch it, and importing skala.ase failed on any host that lacked CUDA but had pytest installed (all CI runners and dev environments). This broke the docs build (docs/ase.ipynb fails on 'from skala.ase import Skala') and any CPU-only use of the ASE calculator since #58. Replace the pytest.skip with a plain ImportError, which is the correct signal for an unusable module and is handled by the existing try/except in calculator.py. The find_spec('pytest') gate is dropped: it was both insufficient (any env with pytest installed triggered the bug) and unnecessary (the module being unimportable on non-CUDA hosts is the right behavior independent of pytest). Test modules already use pytest.skip themselves, which is the correct place for that pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After the previous commit, importing skala.gpu4pyscf on hosts without
CUDA raises ImportError. This is the right semantics for normal callers
(skala.ase.calculator catches it), but the Tests workflow runs
'pytest --doctest-modules --pyargs skala', which collects doctests by
importing every module under src/skala/. The ImportError therefore turns
into a collection error for skala.gpu4pyscf.{__init__,dft,gradients,
grids} on CPU runners.
Add src/skala/conftest.py with a collect_ignore_glob that skips
'gpu4pyscf/*.py' when CUDA is unavailable. The conftest lives at the
skala/ level rather than inside gpu4pyscf/ so pytest can load it without
first triggering the gpu4pyscf package import. Dedicated test modules
in tests/test_gpu4pyscf_*.py keep their own pytest.skip guard.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
awvwgk
approved these changes
May 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
The docs build has been failing since #58 because
docs/ase.ipynbcannot execute the very first cell:The CI traceback (
myst_nb.core.execute.base.ExecutionError) hides the underlying notebook error; thelinkcheckstep is just the last to surface it (the HTML build hits the same failure a few seconds earlier).src/skala/ase/calculator.pydoes:But
src/skala/gpu4pyscf/__init__.pyhad, at module level:pytest.skip(...)raisespytest.outcomes.Skipped, which derives fromBaseException, notImportError. So on any host where (a) CUDA is unavailable and (b)pytestis installed — which is every CI runner and every dev env that installs.[dev]or.[doc]— theexcept ImportErrordoes not catch it, andimport skala.asefails withSkipped. This breaks both the docs notebook and any CPU-only use of the ASE calculator.Repro on
main:Fix
Two coordinated changes.
1.
src/skala/gpu4pyscf/__init__.py— replace the module-levelpytest.skipwith a plainImportError. Theskala.gpu4pyscfpackage genuinely requires CUDA, so "module is unusable" is best expressed asImportError, which is the standard signal callers already handle (includingcalculator.py'stry/except ImportError). Thefind_spec("pytest")gate is dropped: it was both insufficient (any env with pytest installed triggered the bug) and unnecessary (the module being unimportable on non-CUDA hosts is correct independent of pytest).2.
src/skala/conftest.py(new) — the originalpytest.skipwas, despite the broken mechanism, trying to do something legitimate: preventpytest --doctest-modules --pyargs skala(used by.github/workflows/test.yml) from failing collection of the gpu4pyscf modules on CPU runners. After change (1), pytest collection sees theImportErrorand errors out. Restore the intended behavior with acollect_ignore_globthat skipsgpu4pyscf/*.pywhen CUDA is unavailable. The conftest is placed atsrc/skala/rather than insidesrc/skala/gpu4pyscf/because, as a regular package, the inner directory's conftest would itself be imported asskala.gpu4pyscf.conftest, triggering the failing__init__.pybefore pytest could read it.Dedicated tests in
tests/test_gpu4pyscf_*.pyalready use their ownpytest.skip(allow_module_level=True)guard, which is the correct place for that pattern (inside test modules, where pytest does the importing).Verification
from skala.ase import Skalaworks on a CPU-only env.Skala(..., device="cuda")andcalc.set(device="cpu")) work, becausecalculator.pycatches theImportErrorand only raises atcalculate()time ifdevice="cuda"is actually invoked.sphinx-build -b html docs docs/_build/htmlsucceeds end-to-end.pytest --doctest-modules --pyargs skala tests/→ 159 passed, 4 skipped on CPU-only env.ruff format,ruff check,mypypass on both changed files.