Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

@dephiros

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.pyfeatures/templates.py
  • pkg/features/templates.pypkg/features/templates.py

Actual: Nested file collapses into root-level file

  • features/templates.pyfeatures/templates.py
  • pkg/features/templates.pyfeatures/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

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