A strict CLI + library API to report untyped variables, arguments, and function returns in Python code
Typecoverage is a comprehensive Python static analysis tool that identifies missing type annotations in your codebase. Unlike other type checkers that focus on type correctness, Typecoverage specifically targets type annotation coverage - ensuring your code has complete type hints for maintainability and clarity.
- π Comprehensive Detection - Finds missing annotations in functions, methods, variables, and returns
- π― Multiple Input Types - Analyze files, directories, code strings, live Python objects, and more
- π Rich Output Formats - Human-readable text with colors or machine-readable JSON
- βοΈ Flexible Filtering - Smart defaults with configurable rules for different coding patterns
- π« Comment Suppression - Standard
# type: ignore
and# noqa
support - π High Performance - Parallel processing for large codebases
- π οΈ CI/CD Ready - Exit codes and JSON output for continuous integration
- π Detailed Context - Source code snippets around issues for easy fixing
from typecoverage import detect_untyped
# Analyze code string
code = """
def calculate_total(items, tax_rate):
subtotal = sum(item.price for item in items)
return subtotal * (1 + tax_rate)
"""
result = detect_untyped(code, statistics=True)
print(result)
Output:
Found 3 type annotation issues
π <string>
<string>:2:20 - Missing type annotation for argument "items"
1 β
βΊ 2 β def calculate_total(items, tax_rate):
3 β subtotal = sum(item.price for item in items)
<string>:2:27 - Missing type annotation for argument "tax_rate"
1 β
βΊ 2 β def calculate_total(items, tax_rate):
3 β subtotal = sum(item.price for item in items)
<string>:2:1 - Missing return type annotation "calculate_total"
1 β
βΊ 2 β def calculate_total(items, tax_rate):
3 β subtotal = sum(item.price for item in items)
π Summary
Total issues: 3
π΄ Missing argument types: 2
π‘ Missing return types: 1
git clone <repository-url>
cd typecoverage-project
pip install -r requirements.txt
# Install in development mode
pip install -e .
# Or install directly
python setup.py install
# Using the module
python -m typecoverage myfile.py
# Using the installed command
typecoverage myfile.py
# Analyze entire project with statistics
typecoverage --recursive --statistics src/
# JSON output for CI/CD
typecoverage --format json --exit-nonzero-on-issues src/ > report.json
# Include context lines for easier fixing
typecoverage --context-lines 3 src/main.py
from typecoverage import TypeCoverage, detect_untyped
# Simple analysis
result = detect_untyped("def func(x): return x", statistics=True)
print(result)
# Advanced analysis
checker = TypeCoverage()
issues, errors = checker.analyze_targets(
"src/",
recursive=True,
context_lines=2,
exclude=["__pycache__", "tests"],
)
stats = checker.compute_stats(issues)
print(f"Found {stats.total} issues across {len(set(i.file for i in issues))} files")
Typecoverage can analyze various types of targets:
Input Type | Example | Description |
---|---|---|
Files | main.py |
Individual Python files |
Directories | src/ |
Directory trees (with --recursive ) |
Glob Patterns | **/*.py |
Wildcard file matching |
Code Strings | "def func(x): pass" |
Direct Python code |
Live Functions | my_function |
Runtime function objects |
Classes | MyClass |
Class objects |
Modules | import mymodule; mymodule |
Module objects |
Paths | Path("src/main.py") |
pathlib.Path objects |
# Analysis options
--recursive # Recurse into subdirectories
--context-lines N # Show N lines of context around issues
--statistics # Include summary statistics
# Output options
--format json # JSON output instead of text
--output FILE # Write to file instead of stdout
--force-color # Force ANSI colors even when piped
# File filtering
--extensions .py,.pyx # File extensions to analyze
--exclude tests,docs # Exclude paths containing substrings
# Variable filtering (default: ignore these)
--no-ignore-underscore-vars # Include _private variables
--no-ignore-for-targets # Include for loop variables
--no-ignore-except-vars # Include exception variables
--no-ignore-context-vars # Include with statement variables
--no-ignore-comprehensions # Include list/dict comprehension vars
# Exit behavior
--exit-nonzero-on-issues # Exit 1 if any issues found
--fail-under N # Exit 1 if >= N issues found
Create pyproject.toml
configuration:
[tool.typecoverage]
recursive = true
statistics = true
context-lines = 2
exclude = ["tests", "__pycache__", "build"]
ignore-underscore-vars = true
exit-nonzero-on-issues = true
fail-under = 50
Use standard Python suppression comments:
# Suppress all issues on this line
def my_function(x, y): # type: ignore
return x + y
# Suppress specific issue types
def another_function(x, y): # noqa: ANN001,ANN201
return x + y
# Suppress on previous line
# type: ignore
def third_function(x, y):
return x + y
Supported patterns:
# type: ignore
- Suppress all type checking issues# type: ignore[code]
- Suppress specific error codes# noqa
/# noqa: code
- Flake8-style suppression# mypy: ignore
/# pyright: ignore
- Tool-specific suppression
Found 5 type annotation issues
π src/calculator.py
src/calculator.py:15:8 - Missing type annotation for argument "value"
14 β def process_value(self, value, multiplier=1):
βΊ 15 β result = value * multiplier
16 β return result
π Summary
Total issues: 5
π΄ Missing argument types: 3
π‘ Missing return types: 1
π΅ Missing variable types: 1
{
"version": "0.1.8",
"issues": [
{
"file": "src/calculator.py",
"line": 15,
"column": 8,
"type": "untyped-argument",
"name": "value",
"context": [" def process_value(self, value, multiplier=1):", " result = value * multiplier"]
}
],
"statistics": {
"total": 5,
"untyped-argument": 3,
"untyped-return": 1,
"untyped-variable": 1
}
}
from typecoverage import TypeCoverage
def my_function(x, y):
return x + y
class MyClass:
def method(self, value):
return value * 2
checker = TypeCoverage()
# Analyze function
issues, _ = checker.analyze_object(my_function, context_lines=1)
print(f"Function issues: {len(issues)}")
# Analyze class
issues, _ = checker.analyze_object(MyClass, context_lines=1)
print(f"Class issues: {len(issues)}")
from pathlib import Path
from typecoverage import analyze_targets
# Analyze multiple targets
issues, errors = analyze_targets(
"src/main.py", # Specific file
Path("lib/"), # Directory path
"utils/**/*.py", # Glob pattern
my_function, # Live object
recursive=True,
exclude=["test_", "__pycache__"],
context_lines=1,
)
print(f"Total issues: {len(issues)}")
print(f"Errors: {len(errors)}")
name: Type Annotation Coverage
on: [push, pull_request]
jobs:
typecoverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run typecoverage
run: |
typecoverage \
--format json \
--exit-nonzero-on-issues \
--recursive \
--output typecoverage-report.json \
src/
- name: Upload results
uses: actions/upload-artifact@v3
if: always()
with:
name: typecoverage-report
path: typecoverage-report.json
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: typecoverage
name: typecoverage
entry: typecoverage
language: system
args: [--exit-nonzero-on-issues, --recursive, src/]
files: \.py$
python demos/basic_usage.py
python demos/advanced_usage.py
python demos/cli_examples.py
# Run comprehensive test suite
pytest tests/ -v --cov=typecoverage --cov-report=term-missing
# Test specific functionality
pytest tests/test_core.py::TestTypeCoverage -v
βββ typecoverage/
β βββ __init__.py # Public API exports
β βββ __main__.py # CLI entry point
β βββ core.py # Main typecoverage implementation
βββ src/
β βββ core.py # Development version
βββ tests/
β βββ test_core.py # Comprehensive test suite
β βββ test_suppressions.py # Suppression functionality tests
βββ demos/
β βββ basic_usage.py # Basic usage examples
β βββ advanced_usage.py # Advanced features demo
β βββ cli_examples.py # CLI usage examples
βββ docs/
β βββ wiki/ # Comprehensive documentation
β βββ Home.md # Wiki home page
β βββ Quick-Start.md # Getting started guide
β βββ API-Reference.md# Complete API docs
β βββ CLI-Guide.md # Command-line reference
βββ scripts/ # Development utilities
βββ logs/ # Analysis logs
βββ setup.py # Package setup
βββ pyproject.toml # Project configuration
βββ README.md # This file
We welcome contributions! Here's how to get started:
- Fork the repository and clone your fork
- Install development dependencies:
pip install -r requirements.txt
- Run tests:
pytest tests/ -v
- Check code style:
ruff check . && black . --check
- Make your changes and add tests
- Run the full test suite:
pytest tests/ --cov=typecoverage
- Submit a pull request with a clear description
# Set up development environment
pip install -r requirements.txt
# Run code formatting
black . --line-length 79
isort . -l 79 -m 1
ruff format . --line-length 79
# Run linting
ruff check .
pyright
# Run tests with coverage
pytest tests/ --cov=typecoverage --cov-report=term-missing
- Core Analysis Engine - AST-based type annotation detection
- CLI Interface - Full command-line interface
- Python API - Programmatic access
- Multiple Input Types - Files, directories, code strings, live objects
- Output Formats - Text and JSON with statistics
- Comment Suppression - Standard suppression patterns
- Configuration Files - pyproject.toml support
- IDE Extensions - VS Code, PyCharm plugin support
- Type Hint Suggestions - Automated type annotation suggestions
- Incremental Analysis - Only check changed files
- Custom Rules - User-defined annotation requirements
- HTML Reports - Rich web-based reporting
Q: How does this differ from mypy or pyright? A: Mypy and pyright focus on type correctness (catching type errors). Typecoverage focuses on type coverage (ensuring annotations exist). Use them together for comprehensive type safety.
Q: Can I use this with existing type checkers?
A: Absolutely! Typecoverage complements mypy, pyright, and other type checkers. Run typecoverage first to ensure annotations exist, then use other tools to verify type correctness.
Q: What about performance on large codebases?
A: Typecoverage uses parallel processing and is optimized for speed. For very large projects, use --exclude
to skip unnecessary directories and --extensions
to limit file types.
Q: How do I handle legacy code with many issues?
A: Start with --fail-under
set to your current issue count, then gradually reduce it. Use suppression comments for intentionally untyped code.
MIT License - see LICENSE file for details.
- Built with Python's
ast
module for accurate source code analysis - Inspired by flake8, mypy, and other Python code quality tools
- Uses parallel processing for performance on large codebases
- Follows Google-style docstrings and modern Python practices
Made with β€οΈ for the Python community
π Documentation β’ π― Examples β’ π Report Issues β’ π¬ Discussions