From hep-python-tools
Use when writing or configuring tests for a HEP Python project with pytest: setting up pyproject.toml test configuration, writing fixtures and parametrized tests, handling numerical tolerances for physics quantities, setting up code coverage, or choosing between unit and integration tests.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hep-python-tools:python-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
pytest is the standard test framework for Scientific Python. It provides simple
pytest is the standard test framework for Scientific Python. It provides simple assertion rewriting, powerful fixtures, parametrization, and marks — all with minimal boilerplate. For HEP code, special attention is needed for numerical tolerances (physics quantities are floats), RNG seeding (reproducible results), and testing the installed package (src layout requirement).
| Concept | Notes |
|---|---|
| Test discovery | Files named test_*.py; functions named test_* |
| Fixtures | Shared setup/teardown; defined in conftest.py or test files |
| Parametrize | Run one test with many input cases via @pytest.mark.parametrize |
pytest.approx | Float/array comparison with tolerance; prefer over == for floats |
filterwarnings | "error" turns warnings into failures — catch issues early |
src layout | Tests run against the installed package, not the local source |
pyproject.toml[tool.pytest.ini_options]
minversion = "8.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
xfail_strict = true
filterwarnings = ["error"]
log_level = "INFO"
testpaths = ["tests"]
-ra prints a summary of all non-passing results--showlocals prints local variables in tracebacksfilterwarnings = ["error"] catches deprecation warnings before they become
failures in upstream releasesdef test_jet_selection():
jets = [30.5, 15.2, 42.1, 8.0] # pT in GeV
selected = [pt for pt in jets if pt > 20]
assert selected == [30.5, 42.1]
from pytest import approx
import numpy as np
def test_invariant_mass():
m = compute_invariant_mass(pt=50.0, eta=1.2, phi=0.5, e=120.0)
assert m == approx(91.2, rel=1e-3) # Z mass, 0.1% tolerance
def test_array_output():
result = compute_weights(n_events=100)
expected = np.ones(100)
np.testing.assert_allclose(result, expected, rtol=1e-6)
Prefer pytest.approx for scalar comparisons (better error messages);
np.testing.assert_allclose for array comparisons.
import pytest
@pytest.fixture
def sample_events():
return {
"jet_pt": [50.0, 30.0, 80.0], # GeV
"jet_eta": [0.5, 1.2, -0.8],
"weight_mc": [1.0, 0.9, 1.1],
}
def test_event_selection(sample_events):
selected = [pt for pt in sample_events["jet_pt"] if pt > 40]
assert len(selected) == 2
import pytest
@pytest.mark.parametrize(
"pt, eta, expected",
[
(50.0, 0.5, True), # passes both cuts
(15.0, 0.5, False), # fails pT cut
(50.0, 3.0, False), # fails eta cut
],
ids=["central-hard", "soft-jet", "forward-jet"],
)
def test_jet_passes_selection(pt, eta, expected):
assert passes_selection(pt, eta, pt_min=20, eta_max=2.5) == expected
import pytest
def test_bad_file_raises():
with pytest.raises(FileNotFoundError):
load_ntuple("nonexistent.root")
# Run with coverage (pixi)
pixi run pytest --cov=src/my_hep_tool --cov-report=term-missing
# Or via coverage directly (preferred in CI)
coverage run -m pytest
coverage report
In pyproject.toml:
[tool.coverage.run]
source = ["my_hep_tool"]
branch = true
[tool.coverage.report]
exclude_also = ["if TYPE_CHECKING:"]
np.random.default_rng(42), random.seed(42)) — unseeded tests are
non-deterministic and will fail intermittently.== for floats: physics calculations accumulate floating-point
error; always use pytest.approx or np.testing.assert_allclose.pip install -e . (or pixi install) before pytest; otherwise you may test
stale or missing files.filterwarnings = ["error"] is strict: you will catch upstream
deprecations immediately. Add exemptions only for known false-positives:
"ignore::DeprecationWarning:some_package".__init__.py in tests/: it confuses package discovery and
is unnecessary.test_integration.py)
and mark them with @pytest.mark.slow so they can be skipped in fast CI.pixi run pytest; add a test task to pixi.tomlnox -s tests is useful for CI matrix testing across Python versions--cov flag or run coverage run -m pytestscikit-hep-testdata for small bundled test files rather than large git blobsnpx claudepluginhub usatlas/marketplace --plugin hep-python-toolsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.