Skip to main content

Code coverage enforcement tool with flake8-style reporting

Project description

LineCover

Code coverage enforcement tool with flake8-style reporting.

Overview

LineCover is a command-line tool that analyzes pytest coverage reports and enforces code quality standards. It reports violations in flake8-compatible format, making it easy to integrate into CI/CD pipelines and pre-commit hooks.

Features

  • Line Coverage Enforcement: Check that each file meets minimum line coverage thresholds
  • Function/Class Coverage: Ensure functions and classes are adequately tested
  • Total Project Coverage: Enforce overall project coverage requirements
  • Complexity Checks: Detect files with too many functions/classes or too many lines
  • Flake8-Style Output: Standard violation format for easy integration with existing tools
  • Flexible Execution: Run pytest automatically or analyze existing coverage data
  • Pre-commit Integration: Use as a pre-commit hook to enforce coverage on every commit

Installation

uv add linecover

Or install from source:

git clone https://github.com/yourusername/linecover.git
cd linecover
uv sync

Quick Start

Run linecover on your project:

# Run pytest and check that all files have 90% coverage
uv run linecover --run-pytest --line-threshold 90

# Check total project coverage is above 90%
uv run linecover --total-threshold 90

# Check for code complexity issues
uv run linecover --max-units 10 --max-lines 500

# Combine multiple checks
uv run linecover --run-pytest \
    --line-threshold 90 \
    --func-threshold 85 \
    --total-threshold 90 \
    --max-units 10 \
    --max-lines 600

Command-Line Options

Coverage Thresholds

  • --line-threshold PERCENT: Minimum line coverage percentage per file (default: none)
  • --func-threshold PERCENT: Minimum function/class coverage percentage per file (default: none)
  • --total-threshold PERCENT: Minimum total project coverage percentage (default: none)

Complexity Checks

  • --max-units N: Maximum number of functions/classes per file (default: none)
  • --max-lines N: Maximum lines per file (default: none)

Execution Options

  • --run-pytest: Execute pytest --cov before analyzing coverage (default: false)

Logging Options

  • --logfile PATH: Write logs to file (default: stderr only)
  • --loglevel LEVEL: Set log level - DEBUG, INFO, WARNING, ERROR (default: INFO)

Error Codes

LineCover reports violations using flake8-style error codes:

  • COV001: File line coverage below threshold
  • COV002: Function/class coverage below threshold
  • COV003: Too many units (functions/classes) in a file
  • COV004: File exceeds maximum line count

Output Format

Violations are reported in flake8-compatible format:

path/to/file.py:1:1: COV001 Line coverage 75.0% is below threshold 90.0%
path/to/file.py:1:1: COV002 Function coverage 60.0% is below threshold 85.0%
complex.py:1:1: COV003 File has 15 units (functions+classes), exceeds maximum 10
long_file.py:1:1: COV004 File has 650 lines, exceeds maximum 600

Pre-commit Integration

Add LineCover to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/yourusername/linecover
    rev: v0.1.0
    hooks:
      - id: linecover
        args:
          - '--run-pytest'
          - '--line-threshold'
          - '90'
          - '--total-threshold'
          - '90'

Or use as a local hook if linecover is installed in your project:

repos:
  - repo: local
    hooks:
      - id: linecover
        name: LineCover
        entry: uv run linecover
        language: system
        pass_filenames: false
        always_run: true
        args: ['--run-pytest', '--total-threshold', '90']

CI/CD Integration

GitHub Actions

name: Coverage Check
on: [push, pull_request]
jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - name: Install uv
        run: pip install uv
      - name: Install dependencies
        run: uv sync
      - name: Run linecover
        run: uv run linecover --run-pytest --line-threshold 90 --total-threshold 90

Exit Codes

  • 0: No violations found
  • 1: Violations found or error occurred

Examples

Enforcing 90% Line Coverage Per File

uv run linecover --run-pytest --line-threshold 90

Output if violations found:

src/parser.py:1:1: COV001 Line coverage 75.0% is below threshold 90.0%
src/utils.py:1:1: COV001 Line coverage 82.5% is below threshold 90.0%

Checking Project-Wide Coverage

uv run linecover --total-threshold 90

Output if project coverage is low:

<total>:1:1: COV001 Total project coverage 85.0% is below threshold 90.0%

Finding Complex Files

uv run linecover --max-units 10 --max-lines 500

Output for files that are too complex:

src/legacy.py:1:1: COV003 File has 25 units (functions+classes), exceeds maximum 10
src/monolith.py:1:1: COV004 File has 1250 lines, exceeds maximum 500

Development

Project Structure

linecover/
├── linecover/
│   ├── __init__.py
│   ├── cli.py          # Click-based CLI interface
│   ├── runner.py       # Pytest execution
│   ├── parser.py       # Coverage analysis with AST
│   ├── checker.py      # Threshold validation
│   └── reporter.py     # Flake8-style output
├── tests/
│   ├── test_cli.py
│   ├── test_runner.py
│   ├── test_parser.py
│   ├── test_checker.py
│   └── test_reporter.py
├── pyproject.toml
├── .pre-commit-config.yaml
├── .pre-commit-hooks.yaml
└── README.md

Running Tests

# Run all tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=linecover --cov-report=term-missing

# Run linecover on itself
uv run linecover --run-pytest --total-threshold 90

Technology Stack

  • Python 3.12+ with modern type hints (str | None instead of Optional)
  • uv for fast dependency management
  • click for CLI interface with automatic help generation
  • loguru for structured logging
  • coverage.py for reading pytest coverage data
  • AST parsing to count functions, classes, and code lines
  • pytest for testing framework
  • pre-commit for code quality automation

Code Quality

This project maintains high code quality standards:

  • 97%+ test coverage
  • Type hints on all functions
  • Pre-commit hooks for formatting (ruff, mypy)
  • Self-testing with linecover

License

MIT

Contributing

Contributions welcome! Please ensure:

  1. Tests pass: uv run pytest --cov
  2. Coverage stays above 90%: uv run linecover --run-pytest --total-threshold 90
  3. Pre-commit hooks pass: pre-commit run --all-files
  4. Type hints are included for all new functions
  5. Docstrings follow Google style

Development Workflow

# Clone and setup
git clone https://github.com/yourusername/linecover.git
cd linecover
uv sync

# Install pre-commit hooks
pre-commit install

# Make changes and test
uv run pytest
uv run linecover --run-pytest --total-threshold 90

# Commit (pre-commit hooks will run automatically)
git commit -m "Your changes"

Comparison with Other Tools

Feature LineCover pytest-cov coverage.py
Flake8-style output
Per-file thresholds ⚠️ (limited)
Complexity checks
Pre-commit integration ⚠️ (manual) ⚠️ (manual)
Exit code on failure
AST-based metrics

FAQ

Q: Why does linecover exist when coverage.py already exists?

A: LineCover adds enforcement capabilities with flake8-compatible output, making it easy to integrate into existing workflows. It also adds complexity checks (max units, max lines) that coverage.py doesn't provide.

Q: Can I use linecover without pytest?

A: LineCover requires a .coverage file generated by coverage.py. While pytest is the recommended way to generate this, you can use coverage.py directly with any test framework.

Q: Does linecover modify my code?

A: No, linecover only analyzes coverage data and reports violations. It never modifies source files.

Q: Can I enforce different thresholds for different files?

A: Currently, linecover enforces the same thresholds across all files. File-specific thresholds may be added in a future release.

Q: What happens if pytest fails?

A: If --run-pytest is used and pytest fails, linecover will still analyze coverage for any tests that ran. This allows you to see which files need more coverage even when tests fail.

Changelog

v0.1.0 (2025-12-23)

  • Initial release
  • Core functionality: coverage parsing, threshold checking, reporting
  • Pre-commit hook support
  • CLI with logging options
  • 97%+ test coverage
  • AST-based complexity metrics

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

linecover_hook-0.1.0.tar.gz (29.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

linecover_hook-0.1.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file linecover_hook-0.1.0.tar.gz.

File metadata

  • Download URL: linecover_hook-0.1.0.tar.gz
  • Upload date:
  • Size: 29.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for linecover_hook-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e20d72dc4ad80d6f85daafcf313d0bd55a5ccd43b9cad0d1f20ef721bbec1478
MD5 143a10806fa3d7295dbd19ff02e2c761
BLAKE2b-256 8256aee827693c1337513b9f7cdc8b842c2e9340382eb1598936dcad123f1abf

See more details on using hashes here.

File details

Details for the file linecover_hook-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: linecover_hook-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for linecover_hook-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ab91601fde588212b224f601b9971cd9921e9f5deb1e193341fb935c3340daf7
MD5 7ab0d74287da592e6635806a2137bd70
BLAKE2b-256 c0a0865282ef315748a4462501bbeee90a978f74d006d1368e4781d0911bffa8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page