Usage Guide¶
This guide covers everything you need to know to effectively use complexipy in your Python projects.
Installation¶
Command Line Usage¶
Basic Analysis¶
Analyze your entire project:
Analyze specific files or directories:
Setting Complexity Threshold¶
The default threshold is 15. Functions exceeding this value will be highlighted:
Filtering Results¶
Show only functions that exceed the threshold:
Suppress all output (useful for CI pipelines):
Sorting Results¶
Sort by complexity score:
complexipy . --sort asc # Ascending (default)
complexipy . --sort desc # Descending
complexipy . --sort name # Alphabetically by function name
Excluding Files and Directories¶
Exclude specific paths from analysis:
# Exclude a directory
complexipy . --exclude tests
# Exclude multiple paths
complexipy . --exclude tests --exclude migrations --exclude build
# Exclude specific files
complexipy . --exclude src/legacy/old_code.py
How exclusion works
- Entries resolve to existing directories (prefix match) or files (exact match)
- Non-existent entries are silently ignored
- Paths are relative to each provided root path
Output Formats¶
Save results to JSON or CSV:
# JSON output (saved to complexipy-results.json)
complexipy . --output-json
# CSV output (saved to complexipy-results.csv)
complexipy . --output-csv
# Both
complexipy . --output-json --output-csv
JSON Output Structure:
{
"files": [
{
"path": "src/main.py",
"complexity": 42,
"functions": [
{
"name": "process_data",
"complexity": 18,
"line_start": 10,
"line_end": 45
}
]
}
],
"total_complexity": 42
}
Color Output¶
Control color output:
complexipy . --color auto # Default: auto-detect terminal support
complexipy . --color yes # Force colors
complexipy . --color no # Disable colors
Configuration Files¶
Configuration Priority¶
complexipy loads configuration in this order (highest to lowest priority):
- Command-line arguments
complexipy.toml.complexipy.tomlpyproject.toml(under[tool.complexipy])
Example Configurations¶
Python API¶
Analyzing Files¶
from complexipy import file_complexity
# Analyze a file
result = file_complexity("src/main.py")
print(f"Total complexity: {result.complexity}")
print(f"File path: {result.path}")
# Iterate over functions
for func in result.functions:
print(f"{func.name}:")
print(f" Complexity: {func.complexity}")
print(f" Lines: {func.line_start}-{func.line_end}")
Analyzing Code Strings¶
from complexipy import code_complexity
# Analyze code snippet
code = """
def calculate_discount(price, customer):
if customer.is_premium:
if price > 100:
return price * 0.8
else:
return price * 0.9
return price
"""
result = code_complexity(code)
print(f"Complexity: {result.complexity}")
for func in result.functions:
print(f"{func.name}: {func.complexity}")
Practical API Usage¶
Example: Pre-commit Hook
#!/usr/bin/env python3
"""Check complexity of staged Python files."""
import sys
from pathlib import Path
from complexipy import file_complexity
MAX_COMPLEXITY = 15
def main():
# Get staged Python files (integrate with git)
staged_files = get_staged_python_files()
violations = []
for filepath in staged_files:
result = file_complexity(str(filepath))
for func in result.functions:
if func.complexity > MAX_COMPLEXITY:
violations.append({
'file': filepath,
'function': func.name,
'complexity': func.complexity,
'line': func.line_start
})
if violations:
print("Complexity violations found:")
for v in violations:
print(f" {v['file']}:{v['line']} - "
f"{v['function']} (complexity: {v['complexity']})")
sys.exit(1)
print("All functions pass complexity check!")
sys.exit(0)
if __name__ == "__main__":
main()
Example: Code Quality Dashboard
from pathlib import Path
from complexipy import file_complexity
import json
def analyze_project(root_path: str):
"""Generate complexity report for entire project."""
project = Path(root_path)
results = []
for py_file in project.rglob("*.py"):
if "venv" in str(py_file) or ".venv" in str(py_file):
continue
try:
result = file_complexity(str(py_file))
results.append({
'file': str(py_file),
'complexity': result.complexity,
'functions': [
{
'name': f.name,
'complexity': f.complexity,
'line_start': f.line_start,
'line_end': f.line_end
}
for f in result.functions
]
})
except Exception as e:
print(f"Error analyzing {py_file}: {e}")
# Sort by complexity
results.sort(key=lambda x: x['complexity'], reverse=True)
# Save report
with open("complexity-report.json", "w") as f:
json.dump(results, f, indent=2)
# Print summary
total_files = len(results)
total_complexity = sum(r['complexity'] for r in results)
avg_complexity = total_complexity / total_files if total_files else 0
print(f"Analyzed {total_files} files")
print(f"Total complexity: {total_complexity}")
print(f"Average complexity: {avg_complexity:.2f}")
# Top 10 most complex files
print("\nTop 10 most complex files:")
for r in results[:10]:
print(f" {r['file']}: {r['complexity']}")
if __name__ == "__main__":
analyze_project("./src")
Snapshot Baselines¶
Snapshots allow you to adopt complexipy gradually in large, existing codebases.
Creating a Snapshot¶
This creates complexipy-snapshot.json in your working directory, recording all functions that currently exceed the threshold.
How Snapshots Work¶
Once a snapshot exists, complexipy will:
- ✅ Pass: Functions that were already in the snapshot and haven't gotten worse
- ✅ Pass: Functions that improved (automatically removed from snapshot)
- ❌ Fail: New functions that exceed the threshold
- ❌ Fail: Tracked functions that got more complex
Using Snapshots in CI¶
# .github/workflows/complexity.yml
name: Complexity Check
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install complexipy
run: pip install complexipy
- name: Check complexity
run: complexipy . --max-complexity-allowed 15
The snapshot file (complexipy-snapshot.json) should be committed to version control.
Ignoring Snapshots¶
Temporarily disable snapshot checking:
Use this when: - Refactoring multiple files at once - Regenerating the baseline - Testing different thresholds
Snapshot File Format¶
{
"version": "1.0",
"threshold": 15,
"functions": {
"src/legacy.py::old_function": {
"complexity": 23,
"line_start": 10,
"line_end": 50
}
}
}
Inline Ignores¶
Suppress complexity warnings for specific functions:
def complex_legacy_function(): # noqa: complexipy
# Complex logic that can't be refactored yet
pass
# Or with a reason
def another_complex_function(): # noqa: complexipy (technical debt: issue #123)
pass
The ignore comment can also be on the line above:
Use Sparingly
Inline ignores should be temporary. Document why the complexity is necessary and track technical debt.
CI/CD Integration¶
GitHub Actions¶
Use the official action:
- uses: rohaquinlop/complexipy-action@v2
with:
paths: src tests
max_complexity_allowed: 15
output_json: true
Or run directly:
Pre-commit Hook¶
Add to .pre-commit-config.yaml:
repos:
- repo: https://github.com/rohaquinlop/complexipy-pre-commit
rev: v4.2.0
hooks:
- id: complexipy
args: [--max-complexity-allowed=15]
GitLab CI¶
complexity:
image: python:3.11
script:
- pip install complexipy
- complexipy . --max-complexity-allowed 15
only:
- merge_requests
- main
VS Code Integration¶
Install the complexipy extension for real-time complexity analysis:
- Inline complexity scores
- Hover tooltips with details
- Color-coded indicators
- Quick-fix suggestions
Tips and Best Practices¶
1. Start with High Thresholds¶
When introducing complexipy to an existing codebase:
# Create baseline
complexipy . --snapshot-create --max-complexity-allowed 25
# Gradually lower threshold over time
complexipy . --max-complexity-allowed 20
complexipy . --max-complexity-allowed 15
2. Focus on High-Traffic Code¶
Not all complex code needs immediate refactoring:
# Focus on frequently changed files
complexipy src/core/ --max-complexity-allowed 10
complexipy src/legacy/ --max-complexity-allowed 25
3. Use with Code Reviews¶
4. Combine with Test Coverage¶
High complexity + low coverage = high risk
# Check coverage for complex functions
pytest --cov=src --cov-report=term-missing
complexipy src/ --failed
5. Track Trends¶
# Generate historical data
complexipy . --output-json
# Commit complexipy-results.json to track changes over time
Troubleshooting¶
No Python files found¶
Ensure you're in the correct directory and your files have .py extensions.
Syntax errors in analyzed files¶
complexipy requires valid Python syntax. Fix syntax errors first:
Performance issues on large codebases¶
Exclude unnecessary directories:
Different results than expected¶
Check configuration file precedence. Use --help to see active configuration:
Next Steps¶
- Read Understanding Complexity Scores to interpret results
- See Comparison with Ruff for complementary tooling
- Check out About complexipy to learn more about the project