Pseudotest: Regression testing framework for scientific software
Project description
pseudotest
pseudotest is a YAML-driven regression testing framework for scientific software.
It runs one executable against one or more input files in an isolated temporary directory, then validates outputs with flexible file/content/directory match rules.
Highlights
- YAML test definitions for reproducible regression checks
- Per-input execution settings (
InputMethod,Processors,ExpectedFailure,ExtraFiles) - Built-in content extraction:
grep,line,field,column,field_re/field_im(complex magnitude) - File and directory based checks:
size,count_files,file_is_present - Numeric and string comparisons with optional tolerance (
tol) - Vector-style broadcasted matches for concise match definition
- CLI for running tests and for updating failing references or tolerances in-place
- Optional YAML report output for CI artifacts
- MPI support via
MPIEXECenvironment variable
Installation
From PyPI
pip install pseudotest
From source
git clone <repo-url>
cd pseudotest
pip install -e .
Optional dependencies
pip install -e .[devel,test] # ruff, pre-commit, pytest, pytest-mock, pytest-cov
pip install -e .[docs] # mkdocs
Command-line usage
Two entry points are installed:
pseudotest— run tests from a YAML filepseudotest-update— run tests and update failing config entries in-place
Run regression tests
pseudotest test.yaml -D /path/to/executables
| Option | Default | Description |
|---|---|---|
-D, --directory DIR |
. |
Directory containing executables |
-p, --preserve |
off | Keep temporary working directory after run |
-v / -vv |
off | Logging verbosity (INFO / DEBUG) |
-t, --timeout N |
600 |
Per-input execution timeout in seconds |
-r, --report FILE |
— | Append YAML report document to FILE |
Update failing tests
# Increase tolerances to cover observed deltas
pseudotest-update test.yaml -D ./bin --tolerance
# Replace reference values with observed values
pseudotest-update test.yaml -D ./bin --reference
# Write the updated config to a separate file
pseudotest-update test.yaml -D ./bin --reference --output updated.yaml
| Option | Description |
|---|---|
-t, --tolerance |
Compute and set tol for failing numeric matches |
-r, --reference |
Replace reference values with observed values |
-o, --output FILE |
Write changes to FILE instead of overwriting the original |
--timeout N |
Per-input execution timeout in seconds |
YAML test format
Minimal example
Name: My regression test
Executable: solver.x
Inputs:
case_01.in:
Matches:
total_energy:
file: output.txt
grep: "Energy:"
field: 2
value: -42.5000
tol: 1e-4
Full schema
Name: My regression test # required
Enabled: true # set to false to skip the entire suite
Executable: solver.x # filename looked up in -D/--directory
InputMethod: argument # argument | stdin | rename (default: argument)
RenameTo: input.dat # required when InputMethod: rename
Inputs:
case_01.in:
ExtraFiles: [basis.dat, pseudo.UPF] # copied into work dir before execution
Processors: 4 # MPI process count (requires MPIEXEC env var)
ExpectedFailure: false # true = non-zero exit code is treated as pass
InputMethod: argument # overrides top-level InputMethod for this input
Matches:
<match_name>: ...
Input methods
| Mode | Execution shape |
|---|---|
argument (default) |
solver.x case_01.in |
stdin |
solver.x < case_01.in |
rename |
Copy input as RenameTo, then run solver.x |
Match types
Extract a field from a line found by keyword
Energy:
file: results.txt
grep: "Total energy:" # find first line containing this substring
field: 3 # extract the 3rd whitespace-separated token (1-based)
value: -42.5000
tol: 1e-4
Extract a field from a specific line number
Status:
file: output.txt
line: 5 # 1-based; negative values count from the end (line: -1 = last line)
field: 2
value: converged
Extract from the line after a keyword
When both grep and line are present, line is an offset from the matched line (0 = same, 1 = next):
Force:
file: results.txt
grep: "Forces (Ha/Bohr):"
line: 1 # one line after the match
field: 2
value: -0.00123
tol: 1e-5
Extract by character column (fixed-width output)
Band Gap:
file: bands.txt
grep: "Band gap"
column: 21 # start at character 21 (1-based), take first token
value: 1.0342
tol: 1e-3
Count matching lines
Warnings:
file: run.log
grep: "WARNING"
count: 0 # assert no lines contain "WARNING"
Complex number magnitude
Extracts two fields and compares sqrt(re² + im²) to value:
eigenvalue:
file: evals.txt
grep: "Eigenvalue:"
field_re: 2 # field holding the real part
field_im: 3 # field holding the imaginary part
value: 3.1416
tol: 1e-4
File size
restart:
file: restart.bin
size: 65536
Directory checks
dir_count:
directory: output
count_files: 5
dir_has_file:
directory: output
file_is_present: summary.txt
Broadcast (vector checks)
List values expand a single match into one sub-check per element. All list parameters must have equal length; scalars are reused:
multi_energy:
matches: ["Run1", "Run2"]
file: [run1/out.txt, run2/out.txt]
grep: "Energy:"
field: 2
value: [-10.0, -20.0]
tol: 1e-6 # scalar: applies to both elements
matches is optional and names each match in the list.
Protecting a match from automatic updates
critical:
file: results.txt
grep: "Final value"
field: 3
value: 123.45
protected: true # pseudotest-update will never modify this match
MPI support
Set MPIEXEC to your MPI launcher to enable parallel execution:
MPIEXEC=mpiexec pseudotest test.yaml -D ./bin
Processors in each input controls the process count. Supported launchers:
| Launcher | Process-count flag |
|---|---|
mpiexec, mpirun, mpiexec.hydra, orterun |
-np |
srun (SLURM) |
-n |
aprun (Cray) |
-n |
Python API
from pseudotest import PseudoTestRunner
runner = PseudoTestRunner()
exit_code = runner.run(
test_file_path="test.yaml",
executable_directory="./bin",
preserve_workdir=False,
timeout=600,
report_file="report.yaml", # optional
update_mode=None, # "tolerance" | "reference" | None
update_output=None, # optional path for updated config
)
Exit codes
| Code | Meaning |
|---|---|
0 |
All tests passed |
1 |
One or more executions or matches failed |
2 |
Configuration or usage error |
3 |
Runtime error |
99 |
Internal/unexpected error |
Documentation
Detailed MkDocs-ready guides are in docs/:
docs/user-guide.md— full feature reference with examplesdocs/developer-guide.md— architecture, adding match types, internals
Run locally:
pip install -e .[docs]
zensical serve
License
Mozilla Public License 2.0 (MPL-2.0)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pseudotest-0.1.0.tar.gz.
File metadata
- Download URL: pseudotest-0.1.0.tar.gz
- Upload date:
- Size: 58.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b94b2485a78d2a4b0c8539a8d0e18bfd22a6cda985e351567f1ed31b4611fa95
|
|
| MD5 |
6d69da5727c9b1dd00bf5733d81c49cc
|
|
| BLAKE2b-256 |
6a18c9e0b9f5864c8c5393f04774deefab310687fc7233754aa3ed9278d78282
|
Provenance
The following attestation bundles were made for pseudotest-0.1.0.tar.gz:
Publisher:
cd.yml on micaeljtoliveira/pseudotest
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pseudotest-0.1.0.tar.gz -
Subject digest:
b94b2485a78d2a4b0c8539a8d0e18bfd22a6cda985e351567f1ed31b4611fa95 - Sigstore transparency entry: 990459780
- Sigstore integration time:
-
Permalink:
micaeljtoliveira/pseudotest@c6ef17dc1274c2a87b5586e0a79b85f8f1cf9cd8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/micaeljtoliveira
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@c6ef17dc1274c2a87b5586e0a79b85f8f1cf9cd8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pseudotest-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pseudotest-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fafde68416f99bfeba66e4e3db0e99f653cdc2cdee9143a909c05ed4eebf30c
|
|
| MD5 |
b9714524af1c3d90ae9a9aa4ed21c481
|
|
| BLAKE2b-256 |
6c2cdcfc4b5b3f97a99fa1db3b5c064f7117df2b49c3d39980f9a7b52b3fc1b7
|
Provenance
The following attestation bundles were made for pseudotest-0.1.0-py3-none-any.whl:
Publisher:
cd.yml on micaeljtoliveira/pseudotest
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pseudotest-0.1.0-py3-none-any.whl -
Subject digest:
0fafde68416f99bfeba66e4e3db0e99f653cdc2cdee9143a909c05ed4eebf30c - Sigstore transparency entry: 990459815
- Sigstore integration time:
-
Permalink:
micaeljtoliveira/pseudotest@c6ef17dc1274c2a87b5586e0a79b85f8f1cf9cd8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/micaeljtoliveira
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
cd.yml@c6ef17dc1274c2a87b5586e0a79b85f8f1cf9cd8 -
Trigger Event:
push
-
Statement type: