A pytest plugin that selectively runs tests impacted by codechanges via git introspection, ASL parsing, and dependency graph analysis.
Project description
pytest-impacted
A pytest plugin that selectively runs tests impacted by codechanges via git introspection, ASL parsing, and dependency graph analysis.
- Configurable to meet your demands for both local and CI-driven invocations. :dromedary_camel:
- Built using a modern, best-of-breed Python stack, using astroid for Python code AST, NetworkX for dependency graph analysis, and GitPython for interacting with git repositories. :rocket:
- Modular codebase with high unit-test coverage to ensure solid, reliable performance in CI and production environments. :muscle:
[!CAUTION] This project is still currently in alpha development phase. Do not use it in mission critical applications without close supervision of its output and performance. Please report bugs via the Issues tab.
Overview
Sometimes code repositories can become encumbered with a large codebase and a large unit-test codebase to match. In those cases often CI builds become slow and painful due to the need to run all the unit-tests on every CI build. Existing solutions include parallelizing or splitting the tests (e.g. via pytest-split or pytest-xdist), however these often run into trouble too when tests rely on resources such as databases that cannot be easily "shared" between concurrent runs. Moreover, when using solutions such as pytest-split or pytest-xdist, even with multiple database instances, it is often the case that each thread / split of tests takes a long time to run, on top of the overhead introduced by spawning N many databases.
An alternative solution is to try and selectively mark tests that have been affected by recent changes, e.g. as relative to a base branch when we are on a feature branch. This plugin takes this approach. It uses a combination of static analysis (parsing the AST for python modules in a package and building a dependency graph of imports) and git introspection to flag tests that should be re-run.
The philosophy is to err on the side of caution; we currently do not attempt to isolate changes on a line-by-line basis, but rather favor 'false positives' by simply following the chain of dependencies from any file that was modified in any way according to the git history, all the way to any unit-test file that imports it directly or transitively.
Why another such plugin?
We originally looked for such a plugin to already exist. For completeness we mention these here and our impression:
- pytest-testmon is probably the most popular alternative. This may be a fine choice - they are still actively maintained at the time of writing, and go beyond what
pytest-impacteddoes by isolating more granular changes to mark affected tests, based on logic used by the coverage package. In our attempts to use it we ran into various errors we could not easily figure out when using it in conjunction with other plugins such ascoverageandpytest-split, but YMMV - definitely give it a try if you want to look at other options. - pytest-affected - no homepage / repo, seems unmaintained.
- pytest-picked - seems more recently maintained, however only seems to run tests from files that were directly modified rather than perform any static analysis to transitively identify tests based on updated source.
Installation
You can install "pytest-impacted" via pipfrom PyPI:
$ pip install pytest-impacted
Usage
Local unstaged changes
Use as a pytest plugin. Examples for invocation:
$ pytest --impacted --impacted-git-mode=unstaged --impacted-module=<my_root_module_name>
This will run all unit-tests impacted by changes to files which have unstaged modifications in the current active git repository.
Changes committed to current git branch
$ pytest --impacted --impacted-git-mode=branch --impacted-base-branch=main --impacted-module=<my_root_module_name>
this will run all unit-tests impacted by changes to files which have been
modified via any existing commits to the current active branch, as compared to
the base branch passed in the --impacted-base-branch parameter.
As an added bonus, note that you can pass git expressions to the base branch parameter as would be permissible when using git diff - e.g.:
$ pytest --impacted --impacted-git-mode=branch --impacted-base-branch="HEAD~4" --impacted-module=<my_root_module_name>
This can be useful in some scenarios as well.
External tests directory
As another common use case, In some projects the tests directory exists outside of the namespace package. In those cases you can use the --impacted-tests-dir option to make sure those test files are included in the dependency tree and correctly considered for impact analysis:
$ pytest --impacted --impacted-git-mode=unstaged --impacted-module=<my_root_module_name> --impacted-tests-dir=tests/
CI Integration
When using this plugin in CI, it is sometimes desirable to generate the list of impacted test files in one stage where we have access to the git CLI (and perhaps required credentials),
and then invoke running these in a separate step later in the CI pipeline. This can be achieved with the impacted-tests CLI included with the plugin, which supports the same arguments
as the plugin itself:
$ impacted-tests --module=<my_root_module_name> --git-mode=branch --base-branch=main > impacted_tests.txt
In some later step of your CI can then run:
$ pytest @impacted_tests.txt
Testing
Invoke unit-tests with:
uv run python -m pytest
Linting, formatting, static type checks etc. are all managed via pre-commit hooks. These will run automatically on every commit. You can invoke these manually on all files with:
pre-commit run --all-files
Project details
Release history Release notifications | RSS feed
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 pytest_impacted-0.12.0.tar.gz.
File metadata
- Download URL: pytest_impacted-0.12.0.tar.gz
- Upload date:
- Size: 651.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
364c9f0241f417a091ec6b602a32b91f5098f94267c57a058c3ebbe711ea82c2
|
|
| MD5 |
cc9b8f3ed7a28155e90f36df51bd0c7f
|
|
| BLAKE2b-256 |
73a752bf0a7f11770253d9faa947a28428561c2dae47d5bd471ee446a2f58670
|
Provenance
The following attestation bundles were made for pytest_impacted-0.12.0.tar.gz:
Publisher:
publish-to-pypi.yml on promptromp/pytest-impacted
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_impacted-0.12.0.tar.gz -
Subject digest:
364c9f0241f417a091ec6b602a32b91f5098f94267c57a058c3ebbe711ea82c2 - Sigstore transparency entry: 272675820
- Sigstore integration time:
-
Permalink:
promptromp/pytest-impacted@a930823da977c52f297291966fd82bb9c42b5dc1 -
Branch / Tag:
refs/tags/0.12.0 - Owner: https://github.com/promptromp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@a930823da977c52f297291966fd82bb9c42b5dc1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pytest_impacted-0.12.0-py3-none-any.whl.
File metadata
- Download URL: pytest_impacted-0.12.0-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c0f8ae00f981edf8c5fb60a9f964ea944e118c53831e6973c35114cbee1dbaa
|
|
| MD5 |
3aa24e68e4079b394e15a819521667a0
|
|
| BLAKE2b-256 |
d05817080e93795bbcb88a3d14ce70c2fcfae4196591807822f232934d967b6e
|
Provenance
The following attestation bundles were made for pytest_impacted-0.12.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on promptromp/pytest-impacted
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_impacted-0.12.0-py3-none-any.whl -
Subject digest:
6c0f8ae00f981edf8c5fb60a9f964ea944e118c53831e6973c35114cbee1dbaa - Sigstore transparency entry: 272675821
- Sigstore integration time:
-
Permalink:
promptromp/pytest-impacted@a930823da977c52f297291966fd82bb9c42b5dc1 -
Branch / Tag:
refs/tags/0.12.0 - Owner: https://github.com/promptromp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@a930823da977c52f297291966fd82bb9c42b5dc1 -
Trigger Event:
push
-
Statement type: