Testing with nox
The pypfilt testing suite uses the pytest framework and the nox automation tool.
The test cases are contained in the ./tests
directory, and can be run with:
nox
This will also reproduce the images included in the online documentation.
Controlling how tests are run
You can pass arguments to pytest by running the tests
session and using --
to separate nox arguments from pytest arguments.
For example:
To run specific test cases whose names contain a specific string:
nox -s tests -- -k PATTERN
To control the display of logging messages:
nox -s tests -- -o log_cli=true --log-cli-level=INFO
For further details, see the pytest command-line documentation or run:
nox -s tests -- --help
The nox configuration
The noxfile.py
contents are shown below, and include targets that check whether the documentation in ./doc
builds correctly.
import nox
import os
from pathlib import Path
import shutil
# Ensure that nox supports session tags.
nox.needs_version = '>=2022.8.7'
@nox.session()
def build(session):
"""Build source and binary (wheel) packages."""
build_dir = Path('build')
if build_dir.exists():
shutil.rmtree(build_dir)
pkg_dir = Path('.nox-build')
if pkg_dir.exists():
shutil.rmtree(pkg_dir)
session.install('build')
session.run('python', '-m', 'build', '--outdir', pkg_dir)
# On local machines, copy the wheel to a known directory that can be used
# by upstream packages.
if os.environ.get('GITLAB_CI') == 'true':
print('Detected GitLab CI, will not copy package')
else:
packages = sorted(pkg_dir.glob('*.whl'))
if len(packages) != 1:
raise ValueError(f'Found {len(packages)} packages')
package = packages[0]
dest_dir = Path.home() / '.ci-packages'
dest_dir.mkdir(parents=True, exist_ok=True)
print(f'Copying {package} to {dest_dir}')
shutil.copy(package, dest_dir)
@nox.session(reuse_venv=True)
def publish(session):
"""Publish a binary (wheel) package to PyPI."""
if not session.posargs:
print('No package specified, nothing to publish')
return
session.install('twine')
# NOTE: support building packages with metadata 2.3.
session.install('pkginfo>=1.10.0')
session.run('twine', *session.posargs)
@nox.session()
def tests(session):
"""Run test cases and record the test coverage."""
session.install('.[plot,tests]')
# Run the test cases and report the test coverage.
package = 'pypfilt'
session.run(
'python3',
'-bb',
Path(session.bin) / 'pytest',
f'--cov={package}',
'--pyargs',
package,
'./tests',
'./doc',
*session.posargs,
)
# Ensure that regression test outputs have not changed.
session.run(
'git', 'diff', '--exit-code', '--stat', 'tests/', external=True
)
@nox.session(reuse_venv=True)
def docs(session):
"""Build the HTML documentation."""
session.install('-r', 'requirements-rtd.txt')
session.run(
'sphinx-build', '-W', '-b', 'html', './doc', './doc/build/html'
)
@nox.session(tags=['check'])
def ruff(session):
"""Check code for linter warnings and formatting issues."""
check_files = ['src', 'tests', 'doc', 'noxfile.py']
session.install('ruff ~= 0.3')
session.run('ruff', 'check', *check_files)
session.run('ruff', 'format', '--diff', *check_files)