Skip to content

coverage combine with relative_files=true collapses nested directories with duplicate names, causing data loss #2072

Description

@dephiros

Title

coverage combine with relative_files=true collapses nested directories with duplicate names, causing data loss


Description

Summary

When using relative_files=true, coverage combine generates overly broad path mapping rules that collapse files from nested directories sharing the same name. For example, both features/templates.py and pkg/features/templates.py map to features/templates.py, causing coverage data loss.

Expected vs Actual

Expected: Both files tracked separately

  • features/templates.py → features/templates.py
  • pkg/features/templates.py → pkg/features/templates.py

Actual: Nested file collapses into root-level file

  • features/templates.py → features/templates.py ✓
  • pkg/features/templates.py → features/templates.py ❌ (data lost)

Reproducer

Minimal reproduction: https://github.com/dephiros/pytest-coverage-path-bug

# Clone and setup
git clone https://github.com/dephiros/pytest-coverage-path-bug.git
cd pytest-coverage-path-bug
uv sync

# Run workflow
uv run coverage erase
COVERAGE_DEBUG=pathmap uv run coverage run --parallel-mode -m pytest
COVERAGE_DEBUG=pathmap uv run coverage combine
uv run coverage report

Result: Report shows 44 statements instead of 48. pkg/features/templates.py is missing.

Without combine (for comparison):

uv run coverage erase
uv run coverage run -m pytest  # No --parallel-mode
uv run coverage report

Result: Report correctly shows 48 statements with all files.

Debug Output

coverage combine shows the collision:

Generating rule: '*/features' -> 'features/' using regex '^(.*[\\\\/])?features[\\\\/]'
Matched path 'features/templates.py' to rule '*/features' -> 'features/', producing 'features/templates.py'
Matched path 'pkg/features/templates.py' to rule '*/features' -> 'features/', producing 'features/templates.py'

The */features rule matches any path ending with /features/, causing the collision.

Versions

  • Python: 3.11.10
  • coverage.py: 7.11.0
  • pytest: 8.4.2
  • pytest-cov: 7.0.0

Config

[tool.coverage.run]
relative_files = true
branch = true
source = ["."]

Repository Structure

.
├── features/
│   └── templates.py          # 4 statements
├── pkg/
│   └── features/
│       └── templates.py      # 4 statements - GETS COLLAPSED
└── pyproject.toml

Related Issues

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions