A pragmatic pytest plugin that runs only the tests that matter, and ship faster
Project description
pytest-gitscope
Smart test filtering based on Git revisions
pytest-gitscope is a pragmatic pytest plugin that runs only the tests that matter. By analyzing your Git history, it intelligently determines which tests are affected by your changes, helping you ship faster.
Features
Testing everything on every change is thorough but impractical. pytest-gitscope follows the principle of "test what changed" โ giving you confidence in your modifications while respecting your time.
- ๐ฏ Targeted Testing - Run only tests related to modified files
- โก Fast Execution - Dramatically reduce test execution time
- ๐ Git Integration - Seamlessly works with your Git workflow
- ๐ Smart Detection - Automatically detects affected test files and dependencies
- ๐ ๏ธ Flexible Filtering - Support for commit ranges, branches, and specific revisions
Quick Start
pip install pytest-gitscope
# Run tests affected by changes in the last commit
pytest --gitscope HEAD~1
# Run tests affected by changes between two commits
pytest --gitscope main..feature-branch
Perfect for CI/CD pipelines and local development to focus on what matters most.
Understanding pytest-gitscope with a complete example
Let's walk through a real-world example to see exactly how pytest-gitscope works.
Initial Project Structure
myproject/
โโโ src/
โ โโโ calculator.py
โ โโโ user_manager.py
โ โโโ utils.py
โโโ tests/
โ โโโ test_calculator.py
โ โโโ test_user_manager.py
โ โโโ test_utils.py
โ โโโ test_integration.py
โโโ docs/
โโโ README.md
Step 1: Initial State
Your project has 15 tests total:
$ pytest --collect-only -q
15 tests collected
Running all tests takes 45 seconds:
$ pytest
================ 15 passed in 45.23s ================
Step 2: Making Changes
You're working on a new feature and modify two files:
Changes to src/calculator.py:
def add(a, b):
return a + b
def multiply(a, b): # โ NEW FUNCTION
return a * b
Changes to docs/README.md:
# MyProject
Updated documentation with new examples...
Step 3: See What Git Detects
$ git diff --name-only HEAD~1
src/calculator.py
docs/README.md
Step 4: Run pytest-gitscope
Instead of running all 15 tests, use pytest-gitscope:
$ pytest --gitscope HEAD~1
What happens internally:
-
File Analysis: pytest-gitscope runs
git diff --name-only HEAD~1Changed files: ['src/calculator.py', 'docs/README.md'] -
Test Mapping: It identifies which tests are affected:
src/calculator.py โ tests/test_calculator.py docs/README.md โ (no tests affected) -
Dependency Detection: It scans for imports and finds:
tests/test_integration.py imports calculator.py -
Final Test Selection:
Selected tests: โ tests/test_calculator.py (directly affected) โ tests/test_integration.py (imports calculator.py) โ tests/test_user_manager.py (not affected) โ tests/test_utils.py (not affected)
Output:
$ pytest --gitscope HEAD~1
========================== test session starts ==========================
gitscope: Analyzing changes from HEAD~1
collected 15 items / 7 deselected / 8 selected
Some tests have been deselected by pytest-gitscope plugin, because they have not been affected by the changes from HEAD~1
tests/test_calculator.py โโโโโ
tests/test_integration.py โโโ
=================== 8 passed, 7 deselected in 12.34s ====================
Step 5: Compare the Results
| Method | Tests Run | Time |
|---|---|---|
| Regular pytest | 15 tests | 45.23s |
| pytest --gitscope | 8 tests | 12.34s |
| Savings | 7 tests skipped | 73% faster |
Real-World Scenarios
Scenario 1: Feature Branch
# Test only changes in your feature branch
$ pytest --gitscope main..feature/new-auth
gitscope: Selected 12 tests from 4 test files (28 tests skipped)
Scenario 2: Last 3 Commits
# Test changes from last 3 commits
$ pytest --gitscope HEAD~3
gitscope: Selected 6 tests from 2 test files (34 tests skipped)
Scenario 3: Specific Files Only
# Test only your calculator changes
$ pytest --gitscope HEAD~1 tests/test_calculator.py
gitscope: Selected 5 tests from 1 test file (35 tests skipped)
What Gets Detected
โ
Direct matches: src/calculator.py โ tests/test_calculator.py
โ
Import dependencies: Files that import changed modules
โ
Test utilities: Shared test fixtures and utilities
โ
Configuration changes: pytest.ini, conftest.py
โ Documentation only: README.md, *.md files (configurable)
โ Unrelated modules: Files with no test connections
Important Note: Dependency Management
โ ๏ธ pytest-gitscope works best with projects using package managers like Poetry or uv.
Without a proper dependency manager, pytest-gitscope might miss some test dependencies. Here's why:
With Poetry/uv (Recommended):
# pytest-gitscope can analyze pyproject.toml and lock files
# to understand the full dependency graph
src/calculator.py โ tests/test_calculator.py โ
src/calculator.py โ tests/test_math_integration.py โ (detected via deps)
Without package manager:
# pytest-gitscope relies only on direct imports scanning
src/calculator.py โ tests/test_calculator.py โ
src/calculator.py โ tests/test_math_integration.py ? (might be missed)
Recommendation: For best results, use pytest-gitscope in projects with:
pyproject.toml(Poetry, uv, setuptools)requirements.txtwith proper dependency tracking- Clear import patterns
Integration with CI/CD
Perfect for speeding up your CI pipeline:
# .github/workflows/test.yml
- name: Run targeted tests
run: pytest --gitscope origin/main..HEAD
This way, pull requests only run tests affected by the changes, dramatically reducing build times while maintaining confidence in your code quality.
Cookbook
Disable short-circuiting on git push with gitlab-ci
Sometimes you want to disable short-circuiting because updating your pyproject.toml file does not change dependencies.
Gitlab allows to provide CI/CD variables to the CI/CD pipeline, if one is created due to the push. Passes variables only to branch pipelines and not merge request pipelines.
git push -o ci.variable="PYTEST_ADDOPTS=--gitscope-no-short-circuits"
Always include tests that depends on a module
The option --gitscope-include-module let you include tests that depends on this module โ and its submodules too, due to the way modules are imported in python.
pytest --gitscope-include-module x.y.z tests/
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_gitscope-0.7.0.tar.gz.
File metadata
- Download URL: pytest_gitscope-0.7.0.tar.gz
- Upload date:
- Size: 16.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24a84fce3b3743d92af461ccf76fa999e4fa4882ba27df812d19331ebbedb549
|
|
| MD5 |
7e69e009a900c07134f5eba001a4bd6b
|
|
| BLAKE2b-256 |
2a433fbfa9dc0d2285b6f9ef15e7dde97b684785aacd59a69835103207ad2d64
|
File details
Details for the file pytest_gitscope-0.7.0-py3-none-any.whl.
File metadata
- Download URL: pytest_gitscope-0.7.0-py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f97ad4d50c760073eaee652431267a0a1df399b7ceeaac61ee0d3d1f70ce3b79
|
|
| MD5 |
de4792e65eddee24fc6070b6bfdcbe03
|
|
| BLAKE2b-256 |
7193e6276371591caa21e93334b2fa7cdd2b3d40efb2cc9f5bf4cc9ab9909813
|