pytest-cov-container 0.0.1__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.
Files changed (27) hide show
  1. pytest_cov_container-0.0.1/.github/workflows/release.yaml +132 -0
  2. pytest_cov_container-0.0.1/.gitignore +1 -0
  3. pytest_cov_container-0.0.1/LICENSE.txt +18 -0
  4. pytest_cov_container-0.0.1/PKG-INFO +153 -0
  5. pytest_cov_container-0.0.1/README.md +126 -0
  6. pytest_cov_container-0.0.1/docs/plans/2026-03-23-pytest-cov-container.md +1479 -0
  7. pytest_cov_container-0.0.1/docs/specs/2026-03-23-pytest-cov-container-design.md +387 -0
  8. pytest_cov_container-0.0.1/pyproject.toml +89 -0
  9. pytest_cov_container-0.0.1/src/pytest_cov_container/__about__.py +4 -0
  10. pytest_cov_container-0.0.1/src/pytest_cov_container/__init__.py +36 -0
  11. pytest_cov_container-0.0.1/src/pytest_cov_container/config.py +47 -0
  12. pytest_cov_container-0.0.1/src/pytest_cov_container/docker_backend.py +101 -0
  13. pytest_cov_container-0.0.1/src/pytest_cov_container/drivers/__init__.py +21 -0
  14. pytest_cov_container-0.0.1/src/pytest_cov_container/drivers/python.py +105 -0
  15. pytest_cov_container-0.0.1/src/pytest_cov_container/models.py +52 -0
  16. pytest_cov_container-0.0.1/src/pytest_cov_container/plugin.py +117 -0
  17. pytest_cov_container-0.0.1/src/pytest_cov_container/resolver.py +9 -0
  18. pytest_cov_container-0.0.1/tests/__init__.py +3 -0
  19. pytest_cov_container-0.0.1/tests/conftest.py +47 -0
  20. pytest_cov_container-0.0.1/tests/test_config.py +44 -0
  21. pytest_cov_container-0.0.1/tests/test_docker_backend.py +82 -0
  22. pytest_cov_container-0.0.1/tests/test_driver_discovery.py +26 -0
  23. pytest_cov_container-0.0.1/tests/test_plugin.py +122 -0
  24. pytest_cov_container-0.0.1/tests/test_public_api.py +21 -0
  25. pytest_cov_container-0.0.1/tests/test_python_driver.py +117 -0
  26. pytest_cov_container-0.0.1/tests/test_resolver.py +23 -0
  27. pytest_cov_container-0.0.1/uv.lock +418 -0
@@ -0,0 +1,132 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "[0-9]+.[0-9]+.[0-9]+"
7
+
8
+ env:
9
+ PACKAGE_NAME: pytest-cov-container
10
+ OWNER: tomaDev
11
+
12
+ jobs:
13
+ check_pypi:
14
+ runs-on: ubuntu-latest
15
+ outputs:
16
+ PYPI_VERSION: ${{ steps.get.outputs.PYPI_VERSION }}
17
+ steps:
18
+ - name: Fetch information from PyPI
19
+ id: get
20
+ run: |
21
+ response=$(curl -s https://pypi.org/pypi/${{ env.PACKAGE_NAME }}/json || echo "{}")
22
+ version=$(echo $response | grep -oP '"releases":\{"\K[^"]+' | sort -rV | head -n 1)
23
+ if [ -z "$version" ]; then
24
+ echo "Package not found on PyPI."
25
+ version="0.0.0"
26
+ fi
27
+ echo "Latest version on PyPI: $version"
28
+ echo "PYPI_VERSION=$version" >> $GITHUB_OUTPUT
29
+
30
+ setup_and_build:
31
+ needs: [check_pypi]
32
+ name: project setup and build
33
+ runs-on: ubuntu-latest
34
+ outputs:
35
+ NEW_VERSION: ${{ steps.get.outputs.NEW_VERSION }}
36
+ steps:
37
+ - name: Get the new project version
38
+ id: get
39
+ run: echo "NEW_VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
40
+
41
+ - name: Compare versions and exit if not newer
42
+ run: |
43
+ PYPI_VERSION=${{ needs.check_pypi.outputs.PYPI_VERSION }}
44
+ NEW_VERSION=${{ steps.get.outputs.NEW_VERSION }}
45
+ echo "New release version - $NEW_VERSION"
46
+ echo "latest PyPI version - $PYPI_VERSION"
47
+ if [ "$NEW_VERSION" == "$PYPI_VERSION" ]; then
48
+ echo "same version. No need to release"
49
+ exit 1
50
+ elif [ "$(printf '%s\n' "$PYPI_VERSION" "$NEW_VERSION" | sort -rbV | head -n 1)" != "$NEW_VERSION" ]; then
51
+ echo "The new version $NEW_VERSION is not greater than the latest version $PYPI_VERSION on PyPI"
52
+ exit 1
53
+ else
54
+ echo "The new version $NEW_VERSION is greater than the latest version $PYPI_VERSION on PyPI"
55
+ fi
56
+
57
+ - uses: actions/checkout@v4
58
+
59
+ - name: Install uv
60
+ uses: astral-sh/setup-uv@v6
61
+ with:
62
+ enable-cache: true
63
+
64
+ - name: Set up Python
65
+ uses: actions/setup-python@v5
66
+ with:
67
+ python-version-file: "pyproject.toml"
68
+
69
+ - name: Validate package version matches tag version
70
+ run: |
71
+ PACKAGE_VERSION="$(python -c 'from src.pytest_cov_container.__about__ import __version__;print(__version__)')"
72
+ TAG_VERSION="${{ steps.get.outputs.NEW_VERSION }}"
73
+ if [ "$PACKAGE_VERSION" != "$TAG_VERSION" ]; then
74
+ echo "Version mismatch: (package internal) $PACKAGE_VERSION != $TAG_VERSION (tag)"
75
+ exit 1
76
+ fi
77
+
78
+ - name: Install the project
79
+ run: uv sync --all-extras --frozen --no-editable
80
+
81
+ - name: Build the project
82
+ run: uv build
83
+
84
+ - name: Upload artifacts
85
+ uses: actions/upload-artifact@v4
86
+ with:
87
+ name: dist
88
+ path: dist/
89
+
90
+ github_release:
91
+ name: Create GitHub Release
92
+ needs: [setup_and_build]
93
+ runs-on: ubuntu-latest
94
+ permissions:
95
+ contents: write
96
+ steps:
97
+ - name: Checkout Code
98
+ uses: actions/checkout@v4
99
+ with:
100
+ fetch-depth: 0
101
+
102
+ - name: Download artifacts
103
+ uses: actions/download-artifact@v4
104
+ with:
105
+ name: dist
106
+ path: dist/
107
+
108
+ - name: Create GitHub Release
109
+ id: create_release
110
+ env:
111
+ GH_TOKEN: ${{ github.token }}
112
+ run: |
113
+ VERSION=v${{ needs.setup_and_build.outputs.NEW_VERSION }}
114
+ gh release create $VERSION dist/* --title $VERSION --generate-notes
115
+
116
+ pypi_publish:
117
+ name: Upload release to PyPI
118
+ needs: [setup_and_build]
119
+ runs-on: ubuntu-latest
120
+ environment:
121
+ name: release
122
+ permissions:
123
+ id-token: write
124
+ steps:
125
+ - name: Download artifacts
126
+ uses: actions/download-artifact@v4
127
+ with:
128
+ name: dist
129
+ path: dist/
130
+
131
+ - name: Publish distribution to PyPI
132
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1 @@
1
+ __pycache__/
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present tomaDev <genins21@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-cov-container
3
+ Version: 0.0.1
4
+ Summary: Pytest plugin to collect code coverage from applications running inside Docker containers
5
+ Project-URL: Documentation, https://github.com/tomaDev/pytest-cov-container#readme
6
+ Project-URL: Issues, https://github.com/tomaDev/pytest-cov-container/issues
7
+ Project-URL: Source, https://github.com/tomaDev/pytest-cov-container
8
+ Author-email: tomaDev <genins21@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.txt
11
+ Keywords: containers,coverage,docker,pytest,testing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: Pytest
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: coverage>=7.2
23
+ Requires-Dist: docker>=6.0
24
+ Requires-Dist: pytest-cov>=4.0
25
+ Requires-Dist: pytest>=7.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # pytest-cov-container
29
+
30
+ [![PyPI - Version](https://img.shields.io/pypi/v/pytest-cov-container.svg)](https://pypi.org/project/pytest-cov-container)
31
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pytest-cov-container.svg)](https://pypi.org/project/pytest-cov-container)
32
+ [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
33
+
34
+ Collect code coverage from Python applications running inside Docker containers during integration tests. Works alongside [pytest-cov](https://github.com/pytest-dev/pytest-cov) to combine container coverage with your local test coverage.
35
+
36
+ Built for projects using [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/) local testing, but works with any Docker-based test workflow.
37
+
38
+ ## How It Works
39
+
40
+ 1. **Before tests** — injects a coverage wrapper, `.coveragerc`, and `run.sh` into your SAM build directory
41
+ 2. **During tests** — your containerized app runs under `coverage` via the injected wrapper
42
+ 3. **After tests** — extracts `.coverage.*` files from containers and runs `coverage combine` to merge them with local results
43
+
44
+ ## Installation
45
+
46
+ ```console
47
+ pip install pytest-cov-container
48
+ ```
49
+
50
+ Requires Python 3.11+.
51
+
52
+ ## Configuration
53
+
54
+ Add to your `pyproject.toml`:
55
+
56
+ ```toml
57
+ [tool.pytest-cov-container]
58
+ image_pattern = "samcli/lambda*"
59
+ label = "pytest-cov-container"
60
+
61
+ [tool.pytest-cov-container.path_mapping]
62
+ "src/api" = "/var/task"
63
+
64
+ [tool.pytest-cov-container.python]
65
+ build_dir = ".aws-sam/build/ApiFunction"
66
+ entrypoint = "uvicorn app:app --host 0.0.0.0 --port 8080"
67
+ ```
68
+
69
+ | Key | Description |
70
+ |-----|-------------|
71
+ | `image_pattern` | Glob pattern to match container image tags |
72
+ | `label` | Docker label to filter containers |
73
+ | `path_mapping` | Maps host source paths to container paths (used by `coverage combine`) |
74
+ | `build_dir` | SAM build output directory where coverage files are injected |
75
+ | `entrypoint` | The command your app runs inside the container |
76
+ | `language` | Language driver to use (default: `"python"`) |
77
+ | `enabled` | Set to `false` to disable (default: `true`) |
78
+
79
+ ## Usage
80
+
81
+ Run your tests with `--cov` as usual:
82
+
83
+ ```console
84
+ pytest --cov=src/api tests/
85
+ ```
86
+
87
+ The plugin activates automatically when:
88
+ - pytest-cov is active (`--cov` flag present)
89
+ - `[tool.pytest-cov-container]` is configured in `pyproject.toml`
90
+
91
+ Disable it for a run with:
92
+
93
+ ```console
94
+ pytest --cov=src/api --no-cov-container tests/
95
+ ```
96
+
97
+ ### Mid-Session Collection
98
+
99
+ If you need to collect coverage before containers stop (e.g., in a session-scoped fixture teardown), use the public API:
100
+
101
+ ```python
102
+ from pytest_cov_container import collect_container_coverage
103
+
104
+ @pytest.fixture(scope="session")
105
+ def sam_api():
106
+ proc = start_sam(...)
107
+ yield SAM_URL
108
+ collect_container_coverage()
109
+ proc.terminate()
110
+ ```
111
+
112
+ This sends `SIGUSR1` to running containers to flush coverage data, then extracts the files.
113
+
114
+ ## Pluggable Drivers
115
+
116
+ Language support is pluggable via entry points. The built-in Python driver handles:
117
+
118
+ - Writing `.coveragerc` with `parallel = true` and `sigterm = true`
119
+ - Writing `_cov_wrapper.py` that starts coverage, handles `SIGTERM`/`SIGUSR1`, and runs your entrypoint
120
+ - Writing `run.sh` to bootstrap the wrapper
121
+ - Extracting `.coverage.*` files from `/tmp` in containers
122
+
123
+ To add a driver for another language, register an entry point:
124
+
125
+ ```toml
126
+ [project.entry-points."pytest_cov_container.drivers"]
127
+ node = "my_package.drivers.node:NodeDriver"
128
+ ```
129
+
130
+ Drivers must implement the `LanguageDriver` protocol from `pytest_cov_container.models`.
131
+
132
+ ## Development
133
+
134
+ ```console
135
+ # Run tests
136
+ hatch test
137
+
138
+ # Run across all Python versions
139
+ hatch test --all
140
+
141
+ # Format and lint
142
+ hatch fmt
143
+
144
+ # Type check
145
+ hatch run types:check
146
+
147
+ # Security scan
148
+ hatch run security:scan
149
+ ```
150
+
151
+ ## License
152
+
153
+ `pytest-cov-container` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
@@ -0,0 +1,126 @@
1
+ # pytest-cov-container
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/pytest-cov-container.svg)](https://pypi.org/project/pytest-cov-container)
4
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pytest-cov-container.svg)](https://pypi.org/project/pytest-cov-container)
5
+ [![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
6
+
7
+ Collect code coverage from Python applications running inside Docker containers during integration tests. Works alongside [pytest-cov](https://github.com/pytest-dev/pytest-cov) to combine container coverage with your local test coverage.
8
+
9
+ Built for projects using [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/) local testing, but works with any Docker-based test workflow.
10
+
11
+ ## How It Works
12
+
13
+ 1. **Before tests** — injects a coverage wrapper, `.coveragerc`, and `run.sh` into your SAM build directory
14
+ 2. **During tests** — your containerized app runs under `coverage` via the injected wrapper
15
+ 3. **After tests** — extracts `.coverage.*` files from containers and runs `coverage combine` to merge them with local results
16
+
17
+ ## Installation
18
+
19
+ ```console
20
+ pip install pytest-cov-container
21
+ ```
22
+
23
+ Requires Python 3.11+.
24
+
25
+ ## Configuration
26
+
27
+ Add to your `pyproject.toml`:
28
+
29
+ ```toml
30
+ [tool.pytest-cov-container]
31
+ image_pattern = "samcli/lambda*"
32
+ label = "pytest-cov-container"
33
+
34
+ [tool.pytest-cov-container.path_mapping]
35
+ "src/api" = "/var/task"
36
+
37
+ [tool.pytest-cov-container.python]
38
+ build_dir = ".aws-sam/build/ApiFunction"
39
+ entrypoint = "uvicorn app:app --host 0.0.0.0 --port 8080"
40
+ ```
41
+
42
+ | Key | Description |
43
+ |-----|-------------|
44
+ | `image_pattern` | Glob pattern to match container image tags |
45
+ | `label` | Docker label to filter containers |
46
+ | `path_mapping` | Maps host source paths to container paths (used by `coverage combine`) |
47
+ | `build_dir` | SAM build output directory where coverage files are injected |
48
+ | `entrypoint` | The command your app runs inside the container |
49
+ | `language` | Language driver to use (default: `"python"`) |
50
+ | `enabled` | Set to `false` to disable (default: `true`) |
51
+
52
+ ## Usage
53
+
54
+ Run your tests with `--cov` as usual:
55
+
56
+ ```console
57
+ pytest --cov=src/api tests/
58
+ ```
59
+
60
+ The plugin activates automatically when:
61
+ - pytest-cov is active (`--cov` flag present)
62
+ - `[tool.pytest-cov-container]` is configured in `pyproject.toml`
63
+
64
+ Disable it for a run with:
65
+
66
+ ```console
67
+ pytest --cov=src/api --no-cov-container tests/
68
+ ```
69
+
70
+ ### Mid-Session Collection
71
+
72
+ If you need to collect coverage before containers stop (e.g., in a session-scoped fixture teardown), use the public API:
73
+
74
+ ```python
75
+ from pytest_cov_container import collect_container_coverage
76
+
77
+ @pytest.fixture(scope="session")
78
+ def sam_api():
79
+ proc = start_sam(...)
80
+ yield SAM_URL
81
+ collect_container_coverage()
82
+ proc.terminate()
83
+ ```
84
+
85
+ This sends `SIGUSR1` to running containers to flush coverage data, then extracts the files.
86
+
87
+ ## Pluggable Drivers
88
+
89
+ Language support is pluggable via entry points. The built-in Python driver handles:
90
+
91
+ - Writing `.coveragerc` with `parallel = true` and `sigterm = true`
92
+ - Writing `_cov_wrapper.py` that starts coverage, handles `SIGTERM`/`SIGUSR1`, and runs your entrypoint
93
+ - Writing `run.sh` to bootstrap the wrapper
94
+ - Extracting `.coverage.*` files from `/tmp` in containers
95
+
96
+ To add a driver for another language, register an entry point:
97
+
98
+ ```toml
99
+ [project.entry-points."pytest_cov_container.drivers"]
100
+ node = "my_package.drivers.node:NodeDriver"
101
+ ```
102
+
103
+ Drivers must implement the `LanguageDriver` protocol from `pytest_cov_container.models`.
104
+
105
+ ## Development
106
+
107
+ ```console
108
+ # Run tests
109
+ hatch test
110
+
111
+ # Run across all Python versions
112
+ hatch test --all
113
+
114
+ # Format and lint
115
+ hatch fmt
116
+
117
+ # Type check
118
+ hatch run types:check
119
+
120
+ # Security scan
121
+ hatch run security:scan
122
+ ```
123
+
124
+ ## License
125
+
126
+ `pytest-cov-container` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.