Complexipy
Complexipy is an extremely fast Python library, written in Rust, designed to calculate the cognitive complexity of Python files. Unlike cyclomatic complexity, it focuses on measuring how difficult code is for humans to read and understand, identifying hard-to-maintain sections. It operates as both a command-line interface (CLI) tool and a Python API, facilitating integration into development workflows, CI/CD pipelines, and pre-commit hooks. The current version is 5.2.0, with an active release cadence, frequently adding new features and improvements.
Common errors
-
Command 'complexipy' not found
cause The `complexipy` command-line tool is not installed or is not accessible in your system's PATH. This usually happens if the package wasn't installed correctly or the Python environment is not activated.fixEnsure `complexipy` is installed with `pip install complexipy`. If using a virtual environment, activate it before running the command. Verify the Python scripts directory is in your system's PATH. -
CLI exits with code 1 (or fails CI pipeline) when complexity exceeds threshold
cause By default, `complexipy` is configured to exit with a non-zero status code (indicating failure) if any analyzed function's cognitive complexity exceeds the `--max-complexity-allowed` threshold (defaulting to 15). This behavior is intended for enforcing code quality.fixTo prevent failure on high complexity, use `complexipy . --ignore-complexity` to report all functions without failing, or set a higher threshold with `complexipy . --max-complexity-allowed <value>`. To disable the error exit entirely, use `complexipy . --max-complexity-allowed 0`. -
error: path 'non_existent_file.py' does not exist (or similar file/directory not found error)
cause The file or directory path provided to the `complexipy` command does not exist at the specified location, or there's a typo in the path.fixDouble-check the path provided to `complexipy`. Ensure it is correct and accessible from your current working directory. Use absolute paths for clarity or navigate to the correct directory before execution.
Warnings
- breaking In version 4.0.0, the calculation method for boolean operators in conditions was updated to align with the original Cognitive Complexity paper. This change may result in higher reported complexity scores for existing functions, potentially causing previously passing checks to fail.
- breaking Version 5.0.0 introduced a significant change where conditional scoring now counts each `elif` and `else` branch as an additional +1 complexity (plus its boolean test), aligning with Sonar's cognitive complexity rules. This will likely lead to higher scores for functions with multiple branching statements.
- gotcha Starting from version 5.0.0, `complexipy` introduced snapshot baselines (`--snapshot-create`) and per-target change tracking with a `.complexipy_cache` directory. If a `complexipy-snapshot.json` file exists, the tool will automatically fail CI if new functions exceed the threshold or tracked functions become more complex. It will also update the snapshot on improvements.
- deprecated With the release of version 5.0.0, legacy TOML configuration keys (e.g., `output-json = true`) and CLI flags (e.g., `--output-json`) for output format are deprecated. They are replaced by the unified `output-format` key/flag which accepts values like `json` or `csv`.
Install
-
pip install complexipy
Imports
- file_complexity
from complexipy import file_complexity
- code_complexity
from complexipy import code_complexity
Quickstart
import os
from complexipy import file_complexity, code_complexity
# Example 1: Analyze a Python string
snippet = """
def calculate_discount(price, quantity, is_member):
if is_member:
if quantity > 10:
return price * quantity * 0.8 # 20% discount
else:
return price * quantity * 0.9 # 10% discount
else:
return price * quantity
"""
print("\n--- Analyzing code snippet ---")
result_code = code_complexity(snippet)
print(f"Overall snippet complexity: {result_code.complexity}")
for func in result_code.functions:
print(f" Function '{func.name}': Complexity {func.complexity}, Line {func.line_start}-{func.line_end}")
# Example 2: Analyze a temporary Python file
file_content = """
def process_data(data):
if data.get('status') == 'active':
for item in data.get('items', []):
if item.get('value', 0) > 100:
print(f"Processing high-value item: {item['id']}")
else:
print(f"Processing regular item: {item['id']}")
elif data.get('status') == 'pending':
print("Data pending, skipping processing.")
else:
print("Unknown data status.")
"""
file_path = "example_module.py"
with open(file_path, "w") as f:
f.write(file_content)
print(f"\n--- Analyzing file: {file_path} ---")
result_file = file_complexity(file_path)
print(f"File complexity: {result_file.complexity}")
for func in result_file.functions:
print(f" Function '{func.name}': Complexity {func.complexity}, Line {func.line_start}-{func.line_end}")
# Clean up temporary file
os.remove(file_path)