pytest-portion 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ github: mgaitan
@@ -0,0 +1,45 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ pypi-publish:
15
+ name: upload release to PyPI
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ id-token: write
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v7
22
+ - run: uv build
23
+ - if: github.event_name == 'release'
24
+ run: uv publish
25
+
26
+ docs-publish:
27
+ name: Publish documentation to GitHub Pages
28
+ runs-on: ubuntu-latest
29
+ needs: pypi-publish
30
+ environment:
31
+ name: github-pages
32
+ url: ${{ steps.deployment.outputs.page_url }}
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/configure-pages@v5
36
+ - uses: astral-sh/setup-uv@v7
37
+ - run: make docs
38
+ - uses: actions/upload-pages-artifact@v4
39
+ with:
40
+ path: docs/_build/html
41
+ - id: deployment
42
+ uses: actions/deploy-pages@v4
43
+ - name: Summarize documentation URL
44
+ run: |
45
+ echo "Documentation published at: ${{ steps.deployment.outputs.page_url }}" >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,40 @@
1
+ name: CI
2
+ on:
3
+ pull_request:
4
+ branches:
5
+ - main
6
+ push:
7
+ branches:
8
+ - main
9
+
10
+ jobs:
11
+ qa:
12
+ runs-on: ubuntu-latest
13
+ env:
14
+ UV_PYTHON: "3.13"
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v7
18
+
19
+ - name: Ruff check
20
+ run: uv run ruff check --output-format=github
21
+
22
+ - name: Ruff format
23
+ run: uv run ruff format --check
24
+
25
+ - name: Ty check
26
+ run: uv run ty check --output-format=github
27
+
28
+
29
+ test:
30
+ needs: qa
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ matrix:
34
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
35
+
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: astral-sh/setup-uv@v7
39
+ - name: Run pytest
40
+ run: uv run -p ${{ matrix.python-version }} pytest
@@ -0,0 +1,76 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ # Usually these files are written by a python script from a template
29
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
30
+ *.manifest
31
+ *.spec
32
+
33
+ # Installer logs
34
+ pip-log.txt
35
+ pip-delete-this-directory.txt
36
+
37
+ # Unit test / coverage reports
38
+ htmlcov/
39
+ .tox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ nosetests.xml
44
+ coverage.xml
45
+ *,cover
46
+ .hypothesis/
47
+ .pytest_cache
48
+
49
+ # Translations
50
+ *.mo
51
+ *.pot
52
+
53
+ # Django stuff:
54
+ *.log
55
+ local_settings.py
56
+
57
+ # Flask instance folder
58
+ instance/
59
+
60
+ # Sphinx documentation
61
+ docs/_build/
62
+
63
+ # MkDocs documentation
64
+ /site/
65
+
66
+ # PyBuilder
67
+ target/
68
+
69
+ # IPython Notebook
70
+ .ipynb_checkpoints
71
+
72
+ # pyenv
73
+ .python-version
74
+
75
+ # IDE
76
+ .idea/
@@ -0,0 +1,24 @@
1
+ # Config file for automatic testing at travis-ci.org
2
+
3
+ language: python
4
+ python:
5
+ - "3.6"
6
+ - "3.7"
7
+ - "3.8"
8
+ - "3.9"
9
+ - "3.9-dev" # 3.9 development branch
10
+
11
+ # command to install dependencies
12
+ install:
13
+ - pip install -e .
14
+
15
+ # command to run tests
16
+ script:
17
+ - pytest
18
+
19
+ before_cache:
20
+ - rm -rf $HOME/.cache/pip/log
21
+
22
+ cache:
23
+ directories:
24
+ - $HOME/.cache/pip
@@ -0,0 +1,28 @@
1
+
2
+ Copyright (c) 2021, Martín Gaitán
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ * Neither the name of pytest-portion nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.rst
3
+
4
+ recursive-exclude * __pycache__
5
+ recursive-exclude * *.py[co]
@@ -0,0 +1,58 @@
1
+ .PHONY: install
2
+ install: ## Install the virtual environment and install the pre-commit hooks
3
+ @echo "🚀 Creating virtual environment using uv"
4
+ @uv sync
5
+
6
+ .PHONY: test qa
7
+ test: ## Run tests with coverage
8
+ @echo "🧪 Running tests with coverage"
9
+ @uv run pytest
10
+
11
+ qa: ## Run local QA checks (Ruff + Ty)
12
+ @echo "🔍 Running Ruff lint checks"
13
+ @uv run ruff check --fix
14
+ @echo "✨ Verifying Ruff formatting"
15
+ @uv run ruff format --check
16
+ @echo "🧹 Running Ty checks"
17
+ @uv run ty check
18
+
19
+ .PHONY: bump
20
+ bump:
21
+ uv version --bump minor
22
+
23
+ .PHONY: release
24
+ release: ## Create a GitHub release for the current version
25
+ @version=$$(uv version --short); \
26
+ git commit -m "Bump $$version"; \
27
+ git push origin main; \
28
+ gh release create "$$version" --generate-notes
29
+
30
+ .PHONY: docs docs-html docs-epub docs-open html epub open
31
+
32
+ DOCS_SOURCE := docs
33
+ DOCS_BUILD := $(DOCS_SOURCE)/_build
34
+
35
+ docs: ## Build HTML documentation (default).
36
+ @$(MAKE) docs-html
37
+
38
+ html: docs-html
39
+
40
+ docs-html: ## Build documentation as static HTML.
41
+ @echo "📖 Building HTML documentation"
42
+ @uv run --group docs sphinx-build $(DOCS_SOURCE) $(DOCS_BUILD)/html -b html -W
43
+
44
+ epub: docs-epub
45
+
46
+ docs-epub: ## Build documentation as EPUB.
47
+ @echo "📖 Building EPUB documentation"
48
+ @uv run --group docs sphinx-build $(DOCS_SOURCE) $(DOCS_BUILD)/epub -b epub -W
49
+
50
+ docs-open open: docs-html ## Build docs and open them in the browser.
51
+ @uv run -m webbrowser docs/_build/html/index.html
52
+
53
+ .PHONY: help
54
+ help:
55
+ @uv run python -c "import re; \
56
+ [[print(f'\033[36m{m[0]:<20}\033[0m {m[1]}') for m in re.findall(r'^([a-zA-Z_.-]+):.*?## (.*)$$', open(makefile).read(), re.M)] for makefile in ('$(MAKEFILE_LIST)').strip().split()]"
57
+
58
+ .DEFAULT_GOAL := help
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-portion
3
+ Version: 0.2.0
4
+ Summary: Select a portion of the collected tests
5
+ Project-URL: homepage, https://github.com/mgaitan/pytest-portion
6
+ Author-email: Martín Gaitán <gaitan@gmail.com>
7
+ License: BSD-3-Clause
8
+ License-File: LICENSE
9
+ Keywords: pytest,testing
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Framework :: Pytest
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: BSD License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
+ Classifier: Topic :: Software Development :: Testing
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: pytest>=3.5.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # pytest-portion
31
+
32
+ [![CI](https://github.com/mgaitan/pytest-portion/actions/workflows/ci.yml/badge.svg)](https://github.com/mgaitan/pytest-portion/actions/workflows/ci.yml)
33
+ [![PyPI version](https://img.shields.io/pypi/v/pytest-portion.svg)](https://pypi.org/project/pytest-portion)
34
+ [![Python versions](https://img.shields.io/pypi/pyversions/pytest-portion.svg)](https://pypi.org/project/pytest-portion)
35
+ [![Changelog](https://img.shields.io/github/v/release/mgaitan/pytest-portion?include_prereleases&label=changelog)](https://github.com/mgaitan/pytest-portion/releases)
36
+ [![docs](https://img.shields.io/badge/docs-blue.svg?style=flat)](https://mgaitan.github.io/pytest-portion/)
37
+
38
+
39
+ Select a portion of the collected tests, so you can run different parts of your test suite
40
+ in different instances to scale horizontally.
41
+
42
+ ## Use case
43
+
44
+ Suppose you have a big, slow test suite, but you can trigger several CI workers
45
+ to run different portions of it, in a sake lazy/simple way to parallelize it.
46
+
47
+ A basic, obvious way to do that is to explictily
48
+ collect from different directories/modules:
49
+
50
+ - worker1: `pytest tests/a` (100 tests, ~4 minutes to finish)
51
+ - worker2: `pytest tests/b` (20 tests, ~1 minute to finish)
52
+ - worker3: `pytest tests/c tests/d` (30 tests, ~1 minute to finish)
53
+
54
+ The problem is that directory `tests/a` may have a lot more tests that `tests/c` plus `test/d`,
55
+ so `worker1` takes a lot more to finish.
56
+
57
+ With `pytest-portion` you can still split the tests in different instances, but letting
58
+ the extension makes the selection in a more balanced way.
59
+
60
+ - worker1: `pytest --portion 1/3 tests` (first 50 tests, ~2 minutes)
61
+ - worker2: `pytest --portion 2/3 tests` (next 50 tests, ~2 minutes)
62
+ - worker3: `pytest --portion 3/3 tests` (last 50 tests, ~2 minutes)
63
+
64
+ In this case, the tests of all the directories are collected, but only a third (a different one!) of them will
65
+ be actually executed on each worker.
66
+
67
+ Note this balance is **by number of tests**, so if there is very slow tests in a particular portion,
68
+ the duration may not be expected.
69
+
70
+ For a fine tuning, you could pass the portion in a more explicit way:
71
+
72
+ - worker1: `pytest --portion 0:0.5 tests` (first half, 1st to 75th test)
73
+ - worker2: `pytest --portion 0.5:0.8 tests` (next 30%, from 76th to 125th)
74
+ - worker3: `pytest --portion 0.8:1 tests` (last 20%)
75
+
76
+ ## Installation
77
+
78
+ You can add "pytest-portion" to your project from [PyPI](https://pypi.org/project/pytest-portion/) with [uv](https://docs.astral.sh/uv/).
79
+
80
+ ```bash
81
+ uv add --dev pytetest-portion
82
+ ```
83
+
84
+ Or via [pip]
85
+
86
+ ```bash
87
+ pip install pytest-portion
88
+ ```
89
+
90
+ ## Usage
91
+
92
+ There are two modes of operation: **Test-level** (default) and **File-level**.
93
+
94
+ ### 1. Test-level Slicing (Default)
95
+
96
+ Pytest collects all tests first, then `pytest-portion` filters them.
97
+
98
+ Pass `--portion <i/n>` where:
99
+
100
+ - `n` is the total number of portions.
101
+ - `i` is the i-th portion to select (`1 <= i <= n`).
102
+
103
+ > **Note:**
104
+ > If the number of tests collected is not divisible by `n`, the last portion will contain the rest.
105
+ > For instance, if you have `test_1`, `test_2` and `test_3`, `--portion 1/2` will run the first one,
106
+ > and `--portion 2/2` the last 2.
107
+
108
+ Alternatively, use `--portion start:end` where `start` and `end` are coefficients between 0 and 1.
109
+
110
+ ### 2. File-level Slicing
111
+
112
+ For very large projects, collection itself can be slow. Use `--portion-files` to slice the list of
113
+ discovered files **before** pytest starts collecting tests from within them. This can significantly
114
+ reduce collection time in large repositories.
115
+
116
+ ```bash
117
+ # Collect and run only the files belonging to the first half of the suite
118
+ pytest --portion 1/2 --portion-files tests/
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Contributions are very welcome. Please ensure the coverage at least stays
124
+ the same before you submit a pull request.
125
+
126
+ ## License
127
+
128
+ Distributed under the terms of the [BSD-3] license, "pytest-portion" is free and open source software.
129
+
130
+ ## Issues
131
+
132
+ If you encounter any problems, please [file an issue] along with a detailed description.
133
+
134
+ ## Acknowledgements
135
+
136
+ I used [cookiecutter] along with [@hackebrot]'s [cookiecutter-pytest-plugin] template for the boilerplate code of this package. Thanks!
137
+
138
+ [cookiecutter]: https://github.com/audreyr/cookiecutter
139
+ [@hackebrot]: https://github.com/hackebrot
140
+ [MIT]: http://opensource.org/licenses/MIT
141
+ [BSD-3]: http://opensource.org/licenses/BSD-3-Clause
142
+ [GNU GPL v3.0]: http://www.gnu.org/licenses/gpl-3.0.txt
143
+ [Apache Software License 2.0]: http://www.apache.org/licenses/LICENSE-2.0
144
+ [cookiecutter-pytest-plugin]: https://github.com/pytest-dev/cookiecutter-pytest-plugin
145
+ [file an issue]: https://github.com/mgaitan/pytest-portion/issues
146
+ [pytest]: https://github.com/pytest-dev/pytest
147
+ [pip]: https://pypi.org/project/pip/
148
+ [PyPI]: https://pypi.org/project
@@ -0,0 +1,119 @@
1
+ # pytest-portion
2
+
3
+ [![CI](https://github.com/mgaitan/pytest-portion/actions/workflows/ci.yml/badge.svg)](https://github.com/mgaitan/pytest-portion/actions/workflows/ci.yml)
4
+ [![PyPI version](https://img.shields.io/pypi/v/pytest-portion.svg)](https://pypi.org/project/pytest-portion)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/pytest-portion.svg)](https://pypi.org/project/pytest-portion)
6
+ [![Changelog](https://img.shields.io/github/v/release/mgaitan/pytest-portion?include_prereleases&label=changelog)](https://github.com/mgaitan/pytest-portion/releases)
7
+ [![docs](https://img.shields.io/badge/docs-blue.svg?style=flat)](https://mgaitan.github.io/pytest-portion/)
8
+
9
+
10
+ Select a portion of the collected tests, so you can run different parts of your test suite
11
+ in different instances to scale horizontally.
12
+
13
+ ## Use case
14
+
15
+ Suppose you have a big, slow test suite, but you can trigger several CI workers
16
+ to run different portions of it, in a sake lazy/simple way to parallelize it.
17
+
18
+ A basic, obvious way to do that is to explictily
19
+ collect from different directories/modules:
20
+
21
+ - worker1: `pytest tests/a` (100 tests, ~4 minutes to finish)
22
+ - worker2: `pytest tests/b` (20 tests, ~1 minute to finish)
23
+ - worker3: `pytest tests/c tests/d` (30 tests, ~1 minute to finish)
24
+
25
+ The problem is that directory `tests/a` may have a lot more tests that `tests/c` plus `test/d`,
26
+ so `worker1` takes a lot more to finish.
27
+
28
+ With `pytest-portion` you can still split the tests in different instances, but letting
29
+ the extension makes the selection in a more balanced way.
30
+
31
+ - worker1: `pytest --portion 1/3 tests` (first 50 tests, ~2 minutes)
32
+ - worker2: `pytest --portion 2/3 tests` (next 50 tests, ~2 minutes)
33
+ - worker3: `pytest --portion 3/3 tests` (last 50 tests, ~2 minutes)
34
+
35
+ In this case, the tests of all the directories are collected, but only a third (a different one!) of them will
36
+ be actually executed on each worker.
37
+
38
+ Note this balance is **by number of tests**, so if there is very slow tests in a particular portion,
39
+ the duration may not be expected.
40
+
41
+ For a fine tuning, you could pass the portion in a more explicit way:
42
+
43
+ - worker1: `pytest --portion 0:0.5 tests` (first half, 1st to 75th test)
44
+ - worker2: `pytest --portion 0.5:0.8 tests` (next 30%, from 76th to 125th)
45
+ - worker3: `pytest --portion 0.8:1 tests` (last 20%)
46
+
47
+ ## Installation
48
+
49
+ You can add "pytest-portion" to your project from [PyPI](https://pypi.org/project/pytest-portion/) with [uv](https://docs.astral.sh/uv/).
50
+
51
+ ```bash
52
+ uv add --dev pytetest-portion
53
+ ```
54
+
55
+ Or via [pip]
56
+
57
+ ```bash
58
+ pip install pytest-portion
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ There are two modes of operation: **Test-level** (default) and **File-level**.
64
+
65
+ ### 1. Test-level Slicing (Default)
66
+
67
+ Pytest collects all tests first, then `pytest-portion` filters them.
68
+
69
+ Pass `--portion <i/n>` where:
70
+
71
+ - `n` is the total number of portions.
72
+ - `i` is the i-th portion to select (`1 <= i <= n`).
73
+
74
+ > **Note:**
75
+ > If the number of tests collected is not divisible by `n`, the last portion will contain the rest.
76
+ > For instance, if you have `test_1`, `test_2` and `test_3`, `--portion 1/2` will run the first one,
77
+ > and `--portion 2/2` the last 2.
78
+
79
+ Alternatively, use `--portion start:end` where `start` and `end` are coefficients between 0 and 1.
80
+
81
+ ### 2. File-level Slicing
82
+
83
+ For very large projects, collection itself can be slow. Use `--portion-files` to slice the list of
84
+ discovered files **before** pytest starts collecting tests from within them. This can significantly
85
+ reduce collection time in large repositories.
86
+
87
+ ```bash
88
+ # Collect and run only the files belonging to the first half of the suite
89
+ pytest --portion 1/2 --portion-files tests/
90
+ ```
91
+
92
+ ## Contributing
93
+
94
+ Contributions are very welcome. Please ensure the coverage at least stays
95
+ the same before you submit a pull request.
96
+
97
+ ## License
98
+
99
+ Distributed under the terms of the [BSD-3] license, "pytest-portion" is free and open source software.
100
+
101
+ ## Issues
102
+
103
+ If you encounter any problems, please [file an issue] along with a detailed description.
104
+
105
+ ## Acknowledgements
106
+
107
+ I used [cookiecutter] along with [@hackebrot]'s [cookiecutter-pytest-plugin] template for the boilerplate code of this package. Thanks!
108
+
109
+ [cookiecutter]: https://github.com/audreyr/cookiecutter
110
+ [@hackebrot]: https://github.com/hackebrot
111
+ [MIT]: http://opensource.org/licenses/MIT
112
+ [BSD-3]: http://opensource.org/licenses/BSD-3-Clause
113
+ [GNU GPL v3.0]: http://www.gnu.org/licenses/gpl-3.0.txt
114
+ [Apache Software License 2.0]: http://www.apache.org/licenses/LICENSE-2.0
115
+ [cookiecutter-pytest-plugin]: https://github.com/pytest-dev/cookiecutter-pytest-plugin
116
+ [file an issue]: https://github.com/mgaitan/pytest-portion/issues
117
+ [pytest]: https://github.com/pytest-dev/pytest
118
+ [pip]: https://pypi.org/project/pip/
119
+ [PyPI]: https://pypi.org/project