assert-no-pytest-plugin-declarations
Assert that no conftest declares a pytest plugin.
Why
pytest loads a plugin once. Whether a given pytest_plugins line is
doing anything is therefore decided by files other than the one it is
written in — by a module in another directory, or by a conftest further
up the path that has already asked for the same module. Reading the
line tells you nothing about whether it is load-bearing, and no amount
of reading the file around it will either.
A fixture has two ways to reach a suite that do not have that problem.
It can be inherited, by sitting in a conftest above the suite that wants
it. Or it can be imported, by a from ... import ... written in the
conftest that needs it. Both are ordinary Python that ordinary tools
follow: pylint reports the import nothing uses, mypy resolves it, and
the sibling tool assert-pytest-fixture-name-is-needed reads the name
it binds. A pytest_plugins line is a second mechanism for the same
job that none of the three can see through.
It also holds package dependencies up, silently. A declaration that registers no fixture at all still imports its module, and so keeps that module's own imports load-bearing with nothing anywhere saying so. The line cannot be deleted without a reader first working out, across the whole tree, what would stop being imported if it went.
So the rule is the whole of it. Not a redeclaration, not a duplicate of one further up: any declaration at all.
Installation
pip install assert-no-pytest-plugin-declarations
Usage
# Every test tree this repository publishes
assert-no-pytest-plugin-declarations test
# The same, leaving out tests somebody else wrote
assert-no-pytest-plugin-declarations test \
--exclude 'test/vendor/*'
Options
| Option | Effect |
|---|---|
--exclude PATTERNS |
Comma-separated globs to leave out. |
--annotate |
Print each finding as a GitHub Actions ::error annotation. |
--quiet |
Print nothing; report through the exit code. |
--count |
Print only how many findings there were. |
--verbose |
Print the files read, the findings and a summary. |
--fail-fast |
Stop at the first finding. |
--warn-only |
Always exit 0. |
Exit codes
| Code | Meaning |
|---|---|
| 0 | No file declares a pytest plugin |
| 1 | A file declares a pytest plugin |
| 2 | A tree was missing, unreadable, or would not parse |
What counts as a declaration
Any assignment to the name pytest_plugins, whatever it is assigned:
| Written as | Example |
|---|---|
| A list | pytest_plugins = ["fixtures.aws"] |
| A string | pytest_plugins = "fixtures.aws" |
| An annotation | pytest_plugins: list[str] = [] |
| An addition | pytest_plugins += ["fixtures.aws"] |
| One target of several | pytest_plugins = names = [] |
The value is never inspected, because the declaration this tool most wants to refuse is the one whose value cannot be worked out by reading: a name built elsewhere, or a list a loop appends to. An empty list is a finding like any other. It registers nothing today and is an invitation to the next person to add an entry rather than a conftest.
What is walked
A directory argument is read recursively for *.py files. .git,
__pycache__ and node_modules are skipped, and everything else you
want left out goes in --exclude. Each file is read on its own and
needs nothing from any other, so a single file is as valid an argument
as a tree.
Every Python file is read, not only files named conftest.py. pytest
honours the name in a conftest and in a test module, and a line that
sits anywhere else is one that starts working the day the file is
renamed or its contents are moved.
GitHub Actions
- name: Assert no conftest declares a pytest plugin
uses: 10U-Labs/assert-no-pytest-plugin-declarations@latest
with:
trees: test
annotate defaults to true there, so each finding lands on the line it
names in the diff.
License
Apache-2.0
Metadata
Release files for assert-no-pytest-plugin-declarations 20260902062339
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| assert_no_pytest_plugin_declarations-20260902062339.tar.gz | 31.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| assert_no_pytest_plugin_declarations-20260902062339-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.1 kB
Release files / assert_no_pytest_plugin_declarations-20260902062339.tar.gz
| Download URL | assert_no_pytest_plugin_declarations-20260902062339.tar.gz |
|---|---|
| Size | 31.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c85114ccaf00107aa051f9ceac462d416bac65535b32b099269339cf8ece706a
|
|
BLAKE2b-256 checksum How to use checksums |
68f6984567c9b4bdf376631ae6d3be9638d9d82ba908d933a1ba78a57becb1f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / assert_no_pytest_plugin_declarations-20260902062339-py3-none-any.whl
| Download URL | assert_no_pytest_plugin_declarations-20260902062339-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17da8858a05fd6cf6a986be5161e627e5dcab839eb3c72019f2e12ab81479818
|
|
BLAKE2b-256 checksum How to use checksums |
a9bd7f39cec138301e097eecfa979ab527f6bbffe2b7efd780b2a4eb51bd93b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logSecurity for assert-no-pytest-plugin-declarations 20260902062339
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for assert_no_pytest_plugin_declarations-20260902062339.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.