assert-pytest-fixture-is-requested
Assert that every pytest fixture is asked for by something.
A fixture runs only when something asks for it. Delete the last test that asks, and the fixture stays: it is collected into every session that loads its file, the tests written for it keep passing, and the coverage gate on its package stays green. Nothing shows the requester has gone.
A check that matches the fixture's name against the source cannot answer this. A fixture's name is an ordinary identifier that anything else may bind, so a local variable credits it and so does an unrelated function of the same name. Worse, matching a name cannot tell which definition a request resolves to, and it counts a request written inside a factory that nothing ever calls.
So this tool asks pytest. It runs a real collection, reads the fixtures off
it, and adds the one thing a collection cannot see: getfixturevalue.
What counts as asking
pytest resolves five of the six ways itself, and the collection reports them:
- a test function taking the fixture as a parameter
- another fixture taking it as a parameter
- a
pytest.mark.usefixturesmark naming it as a string - a
request.getfixturevaluecall naming it as a string autouse=True, which asks on every in-scope test's behalf
The sixth is a request.getfixturevalue call on a variable, where the name
arrives from somewhere else:
def create_log_group_tests(log_group_fixture: str) -> type:
class TestLogGroup:
def test_retention(self, request):
log_group = request.getfixturevalue(log_group_fixture)
Following that argument back to its call sites is interprocedural analysis.
This tool takes the blunt instrument instead: where a getfixturevalue
call is handed anything but a string literal, every string constant
anywhere in the trees counts as a possible request. That over-credits — a
dictionary key spelled like a fixture will spare a dead one — and the miss
is the right way to be wrong, since a fixture wrongly kept costs a line and
a fixture wrongly deleted costs a red suite. It degrades to nothing where a
repository makes no such call.
Why a collection rather than a parse
Two things only pytest knows.
Which definition a request resolves to. Where conftests at two levels publish the same fixture name, pytest hands each item the one visible to it. A name match credits both, so a definition that every requester shadows looks alive.
Whether the asking is reachable. A parameter of a test method inside a factory nothing calls is not a request, because the class is never built and the method never becomes a test.
Install
pip install assert-pytest-fixture-is-requested
Use
assert-pytest-fixture-is-requested test lib
The trees are collected and read. Because the tool runs a real pytest
collection, it must run where the target's tests import: install the test
dependencies and set PYTHONPATH as the suite expects.
Options
--defined-in TREE— a tree the own-tests exclusion applies to. Repeatable.--dont-search-in PATTERN— a path whose requests do not credit a fixture of the matching package, with{package}standing for the package name. Repeatable.--import-mode MODE— the pytest import mode. Defaults toimportlib, which reads a whole tree whose test files repeat a basename.--rootdir PATH— the directory reported paths are expressed against. Defaults to the working directory.--pytest-argument ARGUMENT— a further argument for the collection, such as--pytest-argument=--confcutdir=test. Repeatable.--annotate— print each finding as a GitHub Actions error annotation.--quiet,--count,--verbose— choose the output.--fail-fast,--warn-only— stop at the first finding, or always exit 0.
The own-tests exclusion
A suite written to exercise a fixture asks for it, so crediting that suite makes every such fixture look used. Name the trees the exclusion applies to and the shape of the suite that does not count:
assert-pytest-fixture-is-requested test lib \
--defined-in lib/python \
--dont-search-in 'test/lib/python/test_{package}'
A fixture published from lib/python/<package>/ is then not credited by a
request from test/lib/python/test_<package>/. A fixture defined under
test/ is credited by a request from anywhere, its own file included,
because the conftest that publishes it and the suite that asks for it are
the same subtree by design.
Exit codes
0— every fixture is asked for1— at least one fixture is asked for by nothing2— a tree was missing, a file was unreadable, or the collection failed
A collection error exits 2 rather than 1, because a file that fails to import registers none of its requests and would make live fixtures look dead.
GitHub Actions
- uses: 10U-Labs/assert-pytest-fixture-is-requested@latest
with:
trees: test lib
defined-in: lib/python
dont-search-in: test/lib/python/test_{package}
verbose: "true"
Limitations
- The tool must run where the target's tests import cleanly.
- A dynamic
getfixturevaluecall makes every string constant a possible request, which deliberately over-credits. - Fixtures registered by pytest itself and by installed plugins are ignored, because they are written outside the trees handed over.
Licence
Apache-2.0.
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 assert_pytest_fixture_is_requested-20260907234601.tar.gz.
File metadata
- Download URL: assert_pytest_fixture_is_requested-20260907234601.tar.gz
- Upload date:
- Size: 29.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f14ccdd4ee54cf877a04ec0884678ee4372ad80d85c0a2a35c744452f0bee82
|
|
| MD5 |
db29fe72b7283a2d4032c2e88fc033e2
|
|
| BLAKE2b-256 |
a01dadb61e95b7878edf5419fccab5d0b0ad67da43dc777a072c445a21aada4c
|
Provenance
The following attestation bundles were made for assert_pytest_fixture_is_requested-20260907234601.tar.gz:
Publisher:
release.yml on 10U-Labs/assert-pytest-fixture-is-requested
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assert_pytest_fixture_is_requested-20260907234601.tar.gz -
Subject digest:
6f14ccdd4ee54cf877a04ec0884678ee4372ad80d85c0a2a35c744452f0bee82 - Sigstore transparency entry: 2753977529
- Sigstore integration time:
-
Permalink:
10U-Labs/assert-pytest-fixture-is-requested@be143c2d92af2647ff8d7ce686ca6cd1852b62a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/10U-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@be143c2d92af2647ff8d7ce686ca6cd1852b62a2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file assert_pytest_fixture_is_requested-20260907234601-py3-none-any.whl.
File metadata
- Download URL: assert_pytest_fixture_is_requested-20260907234601-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
005db39504f10b80a26e91e58873f891c8889cbc5d0cdc822c908e78175adf6b
|
|
| MD5 |
742437dc0609a50b0268e6917e3f1a06
|
|
| BLAKE2b-256 |
189d467ff93f26681295cb059f9ffde3397db3b13622a1066ca12d8b3274fa54
|
Provenance
The following attestation bundles were made for assert_pytest_fixture_is_requested-20260907234601-py3-none-any.whl:
Publisher:
release.yml on 10U-Labs/assert-pytest-fixture-is-requested
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assert_pytest_fixture_is_requested-20260907234601-py3-none-any.whl -
Subject digest:
005db39504f10b80a26e91e58873f891c8889cbc5d0cdc822c908e78175adf6b - Sigstore transparency entry: 2753977538
- Sigstore integration time:
-
Permalink:
10U-Labs/assert-pytest-fixture-is-requested@be143c2d92af2647ff8d7ce686ca6cd1852b62a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/10U-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@be143c2d92af2647ff8d7ce686ca6cd1852b62a2 -
Trigger Event:
push
-
Statement type: