or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-mccabe

McCabe cyclomatic complexity checker that functions as a plugin for flake8

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/mccabe@0.7.x

To install, run

npx @tessl/cli install tessl/pypi-mccabe@0.7.0

index.mddocs/

McCabe

A McCabe cyclomatic complexity checker that functions as a plugin for flake8, the Python code quality tool. This package analyzes Python code to measure cyclomatic complexity, helping developers identify overly complex functions that may be difficult to maintain and test.

Package Information

  • Package Name: mccabe
  • Language: Python
  • Installation: pip install mccabe

Core Imports

import mccabe

For specific functionality:

from mccabe import get_code_complexity, get_module_complexity, McCabeChecker

Basic Usage

Analyzing Code Complexity

from mccabe import get_code_complexity

# Analyze a code string
code = '''
def complex_function(x):
    if x > 10:
        if x > 20:
            return "very high"
        else:
            return "high"
    elif x > 5:
        return "medium"
    else:
        return "low"
'''

# Check complexity with threshold of 5
violations = get_code_complexity(code, threshold=5)
print(f"Found {violations} complexity violations")

Analyzing Python Files

from mccabe import get_module_complexity

# Analyze a Python file
violations = get_module_complexity("my_module.py", threshold=7)
print(f"Found {violations} complexity violations in my_module.py")

Using as Flake8 Plugin

The package integrates seamlessly with flake8:

# Enable McCabe checking with max complexity threshold
flake8 --max-complexity 10 my_project/

# Example output:
# my_project/complex_module.py:15:1: C901 'complex_function' is too complex (12)

Capabilities

Code Complexity Analysis

Analyzes Python source code strings for McCabe cyclomatic complexity violations.

def get_code_complexity(code, threshold=7, filename='stdin'):
    """
    Analyze code string for McCabe complexity violations.
    
    Parameters:
    - code (str): Python source code to analyze
    - threshold (int): Complexity threshold, default 7
    - filename (str): Filename for error reporting, default 'stdin'
    
    Returns:
    int: Number of complexity violations found
    
    Side effects:
    Prints violations to stdout in format:
    "filename:line:col: C901 'function_name' is too complex (N)"
    """

Module Complexity Analysis

Analyzes Python module files for McCabe cyclomatic complexity violations.

def get_module_complexity(module_path, threshold=7):
    """
    Analyze Python module file for McCabe complexity violations.
    
    Parameters:
    - module_path (str): Path to Python module file
    - threshold (int): Complexity threshold, default 7
    
    Returns:
    int: Number of complexity violations found
    """

Command Line Interface

Provides standalone command-line complexity analysis with optional Graphviz output.

def main(argv=None):
    """
    Command-line interface for standalone complexity analysis.
    
    Parameters:
    - argv (list): Command-line arguments, default sys.argv[1:]
    
    Command-line options:
    --dot, -d: Output Graphviz DOT format for visualization
    --min, -m: Minimum complexity threshold for output (default 1)
    
    Side effects:
    Prints analysis results or DOT graph to stdout
    """

Flake8 Plugin Integration

McCabe checker class that integrates with flake8 for automated code quality checking.

class McCabeChecker:
    """
    McCabe cyclomatic complexity checker for flake8 integration.
    
    Class attributes:
    - name (str): Plugin name 'mccabe'
    - version (str): Plugin version
    - max_complexity (int): Complexity threshold (-1 = disabled)
    """
    
    def __init__(self, tree, filename):
        """
        Initialize checker with AST and filename.
        
        Parameters:
        - tree: Python AST tree to analyze
        - filename (str): Source filename
        """
    
    @classmethod
    def add_options(cls, parser):
        """
        Add command-line options to flake8 parser.
        
        Parameters:
        - parser: Flake8 option parser
        
        Adds --max-complexity option with config file support
        """
    
    @classmethod
    def parse_options(cls, options):
        """
        Parse and store flake8 options.
        
        Parameters:
        - options: Parsed options object
        
        Sets cls.max_complexity from options.max_complexity
        """
    
    def run(self):
        """
        Run complexity check and yield violations.
        
        Yields:
        tuple: (line_number, column, message, checker_class)
        
        Message format: "C901 'function_name' is too complex (N)"
        Only yields if complexity > max_complexity threshold
        """

Control Flow Graph Classes

Core classes for building and analyzing control flow graphs used in complexity calculation.

class ASTVisitor:
    """
    Base class for performing depth-first walk of Python AST.
    """
    
    def __init__(self):
        """Initialize visitor with empty cache."""
    
    def default(self, node, *args):
        """
        Default visit method that dispatches to child nodes.
        
        Parameters:
        - node: AST node to visit
        - *args: Additional arguments passed to visitor methods
        """
    
    def dispatch(self, node, *args):
        """
        Dispatch to appropriate visitor method based on node type.
        
        Parameters:
        - node: AST node to dispatch
        - *args: Additional arguments
        
        Returns:
        Result of visitor method call
        """
    
    def preorder(self, tree, visitor, *args):
        """
        Perform preorder walk of AST tree using visitor.
        
        Parameters:
        - tree: AST tree to walk
        - visitor: Visitor object with visit methods
        - *args: Additional arguments passed to visitor methods
        """

class PathNode:
    """
    Represents a node in the control flow graph.
    """
    
    def __init__(self, name, look="circle"):
        """
        Initialize node with name and optional shape.
        
        Parameters:
        - name (str): Node name/label
        - look (str): Node shape for DOT output, default "circle"
        """
    
    def to_dot(self):
        """Output node in Graphviz DOT format to stdout."""
    
    def dot_id(self):
        """
        Return unique ID for DOT output.
        
        Returns:
        int: Unique node identifier
        """

class PathGraph:
    """
    Represents a control flow graph for complexity calculation.
    """
    
    def __init__(self, name, entity, lineno, column=0):
        """
        Initialize graph with metadata.
        
        Parameters:
        - name (str): Graph name
        - entity (str): Associated code entity (function/class name)
        - lineno (int): Line number in source
        - column (int): Column number in source, default 0
        """
    
    def connect(self, n1, n2):
        """
        Connect two nodes in the graph.
        
        Parameters:
        - n1 (PathNode): Source node
        - n2 (PathNode): Destination node
        """
    
    def to_dot(self):
        """Output graph in Graphviz DOT format to stdout."""
    
    def complexity(self):
        """
        Calculate McCabe complexity using V-E+2 formula.
        
        Returns:
        int: McCabe complexity score
        """

class PathGraphingAstVisitor(ASTVisitor):
    """
    AST visitor that builds control flow graphs for complexity analysis.
    Inherits from ASTVisitor.
    """
    
    def __init__(self):
        """Initialize visitor with empty state and graphs dictionary."""
    
    def reset(self):
        """Reset visitor state for new analysis."""
    
    def dispatch_list(self, node_list):
        """
        Process list of AST nodes.
        
        Parameters:
        - node_list (list): List of AST nodes to process
        """
    
    def visitFunctionDef(self, node):
        """
        Process function definitions to build control flow graphs.
        
        Parameters:
        - node: FunctionDef AST node
        """
    
    def visitAsyncFunctionDef(self, node):
        """
        Process async function definitions.
        
        Parameters:
        - node: AsyncFunctionDef AST node
        """
    
    def visitClassDef(self, node):
        """
        Process class definitions.
        
        Parameters:
        - node: ClassDef AST node
        """
    
    def visitIf(self, node):
        """
        Process if statements for branching complexity.
        
        Parameters:
        - node: If AST node
        """
    
    def visitLoop(self, node):
        """
        Process loop constructs for cyclomatic complexity.
        
        Parameters:
        - node: Loop AST node (For, While, AsyncFor)
        """
    
    def visitFor(self, node):
        """Process for loops. Alias for visitLoop."""
    
    def visitAsyncFor(self, node):
        """Process async for loops. Alias for visitLoop."""
    
    def visitWhile(self, node):
        """Process while loops. Alias for visitLoop."""
    
    def visitTryExcept(self, node):
        """
        Process try/except blocks for exception handling complexity.
        
        Parameters:
        - node: Try AST node
        """
    
    def visitTry(self, node):
        """Process try blocks. Alias for visitTryExcept."""
    
    def visitWith(self, node):
        """
        Process with statements.
        
        Parameters:
        - node: With AST node
        """
    
    def visitAsyncWith(self, node):
        """
        Process async with statements.
        
        Parameters:
        - node: AsyncWith AST node
        """

Constants

__version__ = '0.7.0'  # Package version string

Error Codes

  • C901: McCabe complexity violation - function exceeds complexity threshold
    • Format: "C901 'function_name' is too complex (N)"
    • Reported at function definition line
    • Can be suppressed with # noqa: C901 comment

Usage Patterns

McCabe Complexity Guidelines

According to McCabe's original research:

  • 1-10: Simple, well-structured code
  • 11-20: Moderately complex, may need refactoring
  • 21-50: Complex, difficult to test and maintain
  • >50: Extremely complex, high risk of defects

Standalone Script Usage

# Basic complexity analysis
python -m mccabe my_script.py

# Set minimum complexity threshold
python -m mccabe --min 5 my_script.py

# Generate Graphviz DOT output for visualization
python -m mccabe --dot --min 3 my_script.py > complexity.dot
dot -Tpng complexity.dot -o complexity.png

Integration with Development Workflow

# Add to pre-commit hooks
flake8 --max-complexity 10 src/

# Configure in setup.cfg or tox.ini
[flake8]
max-complexity = 10

# Configure in pyproject.toml (for flake8 5.0+)
[tool.flake8]
max-complexity = 10