Patch Linter
Static analyzer that forbids unittest.mock.patch and pytest monkeypatch
mutations in tests. Prefer real dependency injection over patching.
Why
Patching reaches into other modules and couples tests to implementation details. Refactoring becomes harder, and failures become brittle. Inject dependencies (fakes, stubs, or test doubles passed as arguments) instead.
What is reported
| Pattern | Example |
|---|---|
unittest.mock.patch |
@patch(...), with patch(...) |
| Import aliases | from unittest.mock import patch as p → p(...) |
| Via module | mock.patch(...), unittest.mock.patch(...) |
| Patch helpers | patch.object / patch.dict / patch.multiple / patch.stopall |
| pytest monkeypatch | monkeypatch.setattr(...), setenv, delattr, … |
Not reported (by design): mocker (pytest-mock), bare Mock / MagicMock,
freezegun, your own functions named patch, HTTP client.patch(...).
Code: PATCH001.
Installation
pip install patch-linter
# optional flake8 plugin:
pip install "patch-linter[flake8]"
Usage
CLI
patch-linter tests/
patch-linter tests/unit tests/test_foo.py
Output (clickable in Cursor / VS Code / PyCharm):
/abs/path/to/tests/test_foo.py:12:5: PATCH001 Patch usage in tests: @patch('module.function')
Exit code 1 if problems are found.
Flake8
flake8 --select=PATCH tests/
Suppress a line
@patch("module.function") # noqa: PATCH001
def test_legacy(mock_fn):
...
Bare # noqa also suppresses the finding on that line.
Correct approaches
def process_data(repository):
return repository.get_all()
def test_process_data():
class FakeRepo:
def get_all(self):
return [1, 2, 3]
assert process_data(FakeRepo()) == [1, 2, 3]
License
MIT
Metadata
Release files for patch-linter 1.0.0
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 | |
|---|---|---|---|---|
| patch_linter-1.0.0.tar.gz | 11.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| patch_linter-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.6 kB
Release files / patch_linter-1.0.0.tar.gz
| Download URL | patch_linter-1.0.0.tar.gz |
|---|---|
| Size | 11.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0e415e518e2c412a8a6a7c60e00144c542d53a91a9ab2e0c823b8d9a9593319e
|
|
BLAKE2b-256 checksum How to use checksums |
c8ba5d859329b61a7a351f2a3e001d90355fa46fca2d16465935d55fa175e032
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / patch_linter-1.0.0-py3-none-any.whl
| Download URL | patch_linter-1.0.0-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7a489213213ef03e4313195e588d4166873a8bbe8e0d3709c3e84d7f2d59fdfe
|
|
BLAKE2b-256 checksum How to use checksums |
9df7c574f43f0daf4e47ca1da3fe3d89f3f84a4d5b9c55f03657b35799665550
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for patch-linter 1.0.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.