assert-pytest-class-holds-state
Assert that every pytest class holds a fixture, an attribute, a helper or a base.
Why Must a Class Hold Something?
A pytest class earns its place three ways. It holds a fixture, whose scope is
then the class. It holds an attribute or a helper that its methods reach
through self. Or it derives from a shared suite, collecting one set of tests
for many subjects.
A class that does none of those is a namespace. It costs an unused self on
every signature, a level of indentation on every body, a prefix on every node
ID, and it suggests a setup that is not there. The methods belong at module
level, where pytest collects them just as readily.
no-self-use is the mechanical signal and the wrong instrument. It reports on
a method that happens not to touch self, so it flags an autouse fixture
sitting in the class that is its scope, and it flags a kept class's one
stateless method. This tool asks what the class is for instead, so a class that
holds anything at all is silent rather than waived.
Installation
pip install assert-pytest-class-holds-state
Usage
Command Line
# Scan specific files
assert-pytest-class-holds-state test_example.py
# Scan directories recursively
assert-pytest-class-holds-state test/
# Use glob patterns
assert-pytest-class-holds-state "test/**/test_*.py"
# Exclude patterns
assert-pytest-class-holds-state test/ --exclude "**/conftest.py"
# Verbose output
assert-pytest-class-holds-state test/ --verbose
# Fail fast (exit on first finding)
assert-pytest-class-holds-state test/ --fail-fast
# Warn only (always exit 0)
assert-pytest-class-holds-state test/ --warn-only
GitHub Actions
- uses: 10U-Labs/assert-pytest-class-holds-state@latest
with:
files: "test/"
verbose: "true"
As a Python Module
python -m assert_pytest_class_holds_state test/
Output Format
Default output shows one finding per line:
path/to/test_file.py:10:TestExample: the test methods belong at module level
Format: file_path:line_number:class_name, followed by the reason. The line
number is the class statement.
Exit Codes
0: No findings (or--warn-onlyspecified)1: Findings detected2: Error (missing files, syntax errors, etc.)
What Counts as Holding Something?
A class whose name begins with Test is refused only when all four of these
are true:
- it has no base and no class keyword
- it carries no decorator
- its body holds no assignment
- every function in its body is a test — a name beginning with
testthat nopytest.fixturedecorator files as a fixture
Anything else passes. An inheritance stub passes on its base, even with an
empty body. A fixture holder passes on the fixture, autouse or not. A class
holding a @staticmethod helper, a plain helper, or a setup_method passes on
the non-test function. A class carrying @pytest.mark.integration passes on
the decorator, and one carrying region = "us-east-2" passes on the
assignment.
A decorator on a method is not a decorator on the class, so
@pytest.mark.parametrize on every test does not save a namespace.
What Is Never Examined
A class defined inside a function is a suite the function produces, not a namespace someone wrote around loose methods. Its methods close over the function's arguments and cannot move to module level, and pytest never collects it until another module inherits from it. The tool does not descend into function bodies at all.
Only files pytest would collect are scanned: test_*.py and *_test.py.
Options
| Option | Description |
|---|---|
--exclude PATTERNS |
Glob patterns to exclude (comma-separated) |
--quiet |
Suppress all output (exit code only) |
--count |
Output only the number of findings |
--verbose |
Show detailed processing information |
--fail-fast |
Exit after first finding |
--warn-only |
Always exit 0, even with findings |
License
Apache 2.0 - See LICENSE.txt
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_class_holds_state-20260907154656.tar.gz.
File metadata
- Download URL: assert_pytest_class_holds_state-20260907154656.tar.gz
- Upload date:
- Size: 26.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab789107109d775e992e5e60da1200fbfc8c3c8a24e8ba3013111562bd60d10c
|
|
| MD5 |
c35db5d6840ec87b6955fbf3059f5bda
|
|
| BLAKE2b-256 |
266226cf73fdd573a3c88a70b0fc933f3680a5ee2b8068224ddf1e5f7bf46857
|
Provenance
The following attestation bundles were made for assert_pytest_class_holds_state-20260907154656.tar.gz:
Publisher:
release.yml on 10U-Labs/assert-pytest-class-holds-state
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assert_pytest_class_holds_state-20260907154656.tar.gz -
Subject digest:
ab789107109d775e992e5e60da1200fbfc8c3c8a24e8ba3013111562bd60d10c - Sigstore transparency entry: 2752354965
- Sigstore integration time:
-
Permalink:
10U-Labs/assert-pytest-class-holds-state@e8e26e23158c407c9fe54d91a02cbc7241bb1092 -
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@e8e26e23158c407c9fe54d91a02cbc7241bb1092 -
Trigger Event:
push
-
Statement type:
File details
Details for the file assert_pytest_class_holds_state-20260907154656-py3-none-any.whl.
File metadata
- Download URL: assert_pytest_class_holds_state-20260907154656-py3-none-any.whl
- Upload date:
- Size: 11.8 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 |
9947a24be4aac5bdf038898957fa146f5bd97ca07ec464f057b1fa4c2f2c4629
|
|
| MD5 |
8f3149b01e9ca41ac711b06e9fbd95d2
|
|
| BLAKE2b-256 |
33ad5549e6407411af8229944a64b5f9d4da211e87504f8092b72cc2f4688f7c
|
Provenance
The following attestation bundles were made for assert_pytest_class_holds_state-20260907154656-py3-none-any.whl:
Publisher:
release.yml on 10U-Labs/assert-pytest-class-holds-state
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assert_pytest_class_holds_state-20260907154656-py3-none-any.whl -
Subject digest:
9947a24be4aac5bdf038898957fa146f5bd97ca07ec464f057b1fa4c2f2c4629 - Sigstore transparency entry: 2752354976
- Sigstore integration time:
-
Permalink:
10U-Labs/assert-pytest-class-holds-state@e8e26e23158c407c9fe54d91a02cbc7241bb1092 -
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@e8e26e23158c407c9fe54d91a02cbc7241bb1092 -
Trigger Event:
push
-
Statement type: