From 2c79e50d6811f5e1f9670d9e276e5bef399c0eb3 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 23 Apr 2026 02:30:46 -0500 Subject: [PATCH 1/2] test: set up coverage infrastructure in CI - Add pytest-cov to dev dependencies - Add .coveragerc with branch coverage, 60% floor (current baseline), and source/omit configuration - Add coverage CI job (ubuntu/py3.13) that runs pytest with --cov, enforces the floor, and uploads coverage.xml as an artifact - Wire coverage into the required-checks-passed gate Closes #2080 --- .coveragerc | 17 +++++++++++++++++ .github/workflows/ci.yaml | 39 +++++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + uv.lock | 28 ++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..b5ff4eb40 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,17 @@ +[run] +branch = true +source = codeflash +omit = + codeflash/version.py + +[report] +sort = cover +show_missing = true +fail_under = 60 +exclude_lines = + pragma: no cover + if TYPE_CHECKING: + if __name__ == .__main__.: + +[html] +directory = htmlcov diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b5b1c74c..ba861ca0c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -151,6 +151,44 @@ jobs: - name: Unit tests run: uv run pytest tests/ + # --------------------------------------------------------------------------- + # Coverage — single run on ubuntu/py3.13 to enforce the coverage floor. + # --------------------------------------------------------------------------- + coverage: + needs: determine-changes + if: needs.determine-changes.outputs.unit_tests == 'true' + runs-on: ubuntu-latest + env: + PYTHONIOENCODING: utf-8 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + python-version: "3.13" + enable-cache: true + + - name: Install dependencies + run: uv sync + + - name: Run tests with coverage + run: uv run pytest tests/ --cov=codeflash --cov-report=xml:coverage.xml --cov-report=term-missing --cov-config=.coveragerc + + - name: Check coverage floor + run: uv run coverage report --fail-under=60 + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage.xml + retention-days: 30 + # --------------------------------------------------------------------------- # Mypy type checking # --------------------------------------------------------------------------- @@ -507,6 +545,7 @@ jobs: if: always() needs: - unit-tests + - coverage - type-check - prek - e2e-python diff --git a/pyproject.toml b/pyproject.toml index 7701725ea..3e876a0b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ dev = [ "prek>=0.2.25", "ty>=0.0.14", "uv>=0.9.29", + "pytest-cov>=7.1.0", ] tests = [ "black>=25.9.0", diff --git a/uv.lock b/uv.lock index c059d601e..e0bcacea6 100644 --- a/uv.lock +++ b/uv.lock @@ -507,6 +507,7 @@ dev = [ { name = "pandas-stubs", version = "2.2.2.240807", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "pandas-stubs", version = "2.2.2.240909", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "prek" }, + { name = "pytest-cov" }, { name = "ruff" }, { name = "ty" }, { name = "types-cffi", version = "1.17.0.20250915", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, @@ -608,6 +609,7 @@ dev = [ { name = "mypy", specifier = ">=1.13" }, { name = "pandas-stubs", specifier = ">=2.2.2.240807,<2.2.3.241009" }, { name = "prek", specifier = ">=0.2.25" }, + { name = "pytest-cov", specifier = ">=7.1.0" }, { name = "ruff", specifier = ">=0.7.0" }, { name = "ty", specifier = ">=0.0.14" }, { name = "types-cffi", specifier = ">=1.16.0.20240331" }, @@ -776,6 +778,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" }, ] +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version < '3.10'" }, +] + [[package]] name = "coverage" version = "7.13.5" @@ -904,6 +911,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version >= '3.10' and python_full_version <= '3.11'" }, +] + [[package]] name = "crosshair-tool" version = "0.0.102" @@ -4515,6 +4527,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, ] +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" }, + { name = "coverage", version = "7.13.5", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" }, + { name = "pluggy" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + [[package]] name = "pytest-memray" version = "1.8.0" From 0232d84a7d043a9b1cb7ab49f106c39ce6e12b67 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 23 Apr 2026 03:04:49 -0500 Subject: [PATCH 2/2] fix: exclude test_tracer.py from coverage run and lower floor to 58% pytest-cov's trace function conflicts with the Tracer class under test, causing it to self-disable in CI. Linux also reports ~1% lower coverage than macOS due to platform-specific branches. --- .coveragerc | 2 +- .github/workflows/ci.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.coveragerc b/.coveragerc index b5ff4eb40..47abc2120 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,7 +7,7 @@ omit = [report] sort = cover show_missing = true -fail_under = 60 +fail_under = 58 exclude_lines = pragma: no cover if TYPE_CHECKING: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ba861ca0c..e9c978915 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -176,10 +176,10 @@ jobs: run: uv sync - name: Run tests with coverage - run: uv run pytest tests/ --cov=codeflash --cov-report=xml:coverage.xml --cov-report=term-missing --cov-config=.coveragerc + run: uv run pytest tests/ --ignore=tests/test_tracer.py --cov=codeflash --cov-report=xml:coverage.xml --cov-report=term-missing --cov-config=.coveragerc - name: Check coverage floor - run: uv run coverage report --fail-under=60 + run: uv run coverage report --fail-under=58 - name: Upload coverage report if: always()