CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-radon

Code Metrics in Python - comprehensive tool for computing various software metrics

Pending
Overview
Eval results
Files

cli.mddocs/

Command Line Interface

Comprehensive CLI with four analysis commands (cc, raw, mi, hal) supporting multiple output formats, configuration files, and batch processing capabilities. Designed for integration with CI/CD pipelines, code quality tools, and automated analysis workflows.

Capabilities

Main CLI Program

Central program instance and configuration management for all radon commands.

# Main program instance (mando.Program)
program = Program(version=radon.__version__)

class Config:
    """
    Configuration object for analysis parameters.
    
    Stores analysis settings and provides access to configuration values
    through attribute access and keyword parameters.
    """
    
    def __init__(self, **kwargs):
        """
        Create configuration with keyword parameters.
        
        Parameters:
        - **kwargs: Configuration values as keyword arguments
        """
    
    @classmethod
    def from_function(cls, func):
        """
        Create Config object from function defaults.
        
        Extracts default parameter values from a function's signature
        to create a configuration object.
        
        Parameters:
        - func: Function with default parameters
        
        Returns:
        Config: Configuration object with function defaults
        """

class FileConfig:
    """
    File-based configuration reader supporting multiple formats.
    
    Reads configuration from setup.cfg, radon.cfg, pyproject.toml,
    and environment variables.
    """
    
    def get_value(self, key, type, default):
        """
        Get configuration value with type conversion.
        
        Parameters:
        - key (str): Configuration key name
        - type: Target type (int, bool, str)
        - default: Default value if key not found
        
        Returns:
        Converted configuration value or default
        """
    
    @staticmethod
    def file_config():
        """
        Read configuration from various file sources.
        
        Checks for configuration in:
        - Environment variable RADONCFG
        - radon.cfg in current directory
        - pyproject.toml [tool.radon] section
        - setup.cfg [radon] section
        - ~/.radon.cfg in user home directory
        
        Returns:
        configparser.ConfigParser: Merged configuration
        """
    
    @staticmethod  
    def toml_config():
        """
        Read configuration from pyproject.toml file.
        
        Returns:
        dict: Configuration dictionary from TOML file
        """

Analysis Commands

Core commands for different types of code analysis.

@program.command
def cc(paths, min='A', max='F', show_complexity=False, average=False, 
       exclude=None, ignore=None, order='SCORE', json=False, 
       no_assert=False, show_closures=False, total_average=False,
       xml=False, md=False, codeclimate=False, output_file=None,
       include_ipynb=False, ipynb_cells=False):
    """
    Analyze cyclomatic complexity (CC) of Python modules.
    
    Computes McCabe's cyclomatic complexity and provides A-F rankings
    for functions, methods, and classes.
    
    Parameters:
    - paths (list): Paths to Python files or directories to analyze
    - min (str): Minimum complexity grade to display ('A'-'F')
    - max (str): Maximum complexity grade to display ('A'-'F')  
    - show_complexity (bool): Show numeric complexity scores
    - average (bool): Display average complexity at end
    - exclude (str): Glob patterns for files to exclude
    - ignore (str): Glob patterns for directories to ignore
    - order (str): Sort order ('SCORE', 'LINES', 'ALPHA')
    - json (bool): Output results as JSON
    - no_assert (bool): Don't count assert statements
    - show_closures (bool): Include nested functions/classes
    - total_average (bool): Average unfiltered by min/max
    - xml (bool): Output results as XML (CCM compatible)
    - md (bool): Output results as Markdown
    - codeclimate (bool): Output Code Climate format
    - output_file (str): Write output to file instead of stdout
    - include_ipynb (bool): Include Jupyter notebook files
    - ipynb_cells (bool): Report individual notebook cells
    """

@program.command  
def raw(paths, exclude=None, ignore=None, summary=False, json=False,
        output_file=None, include_ipynb=False, ipynb_cells=False):
    """
    Analyze raw code metrics (LOC, LLOC, comments, etc.).
    
    Computes lines of code, logical lines, comments, blank lines,
    and other basic code statistics.
    
    Parameters:
    - paths (list): Paths to Python files or directories to analyze
    - exclude (str): Glob patterns for files to exclude
    - ignore (str): Glob patterns for directories to ignore
    - summary (bool): Display summary statistics
    - json (bool): Output results as JSON
    - output_file (str): Write output to file instead of stdout
    - include_ipynb (bool): Include Jupyter notebook files
    - ipynb_cells (bool): Report individual notebook cells
    """

@program.command
def mi(paths, min='A', max='C', multi=True, exclude=None, ignore=None,
       show=False, json=False, sort=False, output_file=None,
       include_ipynb=False, ipynb_cells=False):
    """
    Analyze Maintainability Index of Python modules.
    
    Computes compound maintainability metric combining Halstead volume,
    cyclomatic complexity, and lines of code.
    
    Parameters:
    - paths (list): Paths to Python files or directories to analyze
    - min (str): Minimum MI grade to display ('A', 'B', 'C')
    - max (str): Maximum MI grade to display ('A', 'B', 'C')
    - multi (bool): Count multi-line strings as comments
    - exclude (str): Glob patterns for files to exclude
    - ignore (str): Glob patterns for directories to ignore
    - show (bool): Show actual MI numeric values
    - json (bool): Output results as JSON
    - sort (bool): Sort results in ascending order
    - output_file (str): Write output to file instead of stdout
    - include_ipynb (bool): Include Jupyter notebook files
    - ipynb_cells (bool): Report individual notebook cells
    """

@program.command
def hal(paths, exclude=None, ignore=None, json=False, functions=False,
        output_file=None, include_ipynb=False, ipynb_cells=False):
    """
    Analyze Halstead complexity metrics of Python modules.
    
    Computes software science metrics including volume, difficulty,
    effort, time estimates, and bug predictions.
    
    Parameters:
    - paths (list): Paths to Python files or directories to analyze
    - exclude (str): Glob patterns for files to exclude
    - ignore (str): Glob patterns for directories to ignore
    - json (bool): Output results as JSON
    - functions (bool): Analyze by top-level functions instead of files
    - output_file (str): Write output to file instead of stdout
    - include_ipynb (bool): Include Jupyter notebook files
    - ipynb_cells (bool): Report individual notebook cells
    """

Output and Logging Functions

Functions for formatting and displaying analysis results.

def log_result(harvester, **kwargs):
    """
    Log results from a Harvester object with format selection.
    
    Automatically selects output format based on keyword arguments
    and delegates to appropriate formatter.
    
    Parameters:
    - harvester: Harvester instance with analysis results
    - json (bool): Format as JSON
    - xml (bool): Format as XML  
    - md (bool): Format as Markdown
    - codeclimate (bool): Format for Code Climate
    - stream: Output stream (default stdout)
    - **kwargs: Additional formatting options
    """

def log(msg, *args, **kwargs):
    """
    Log a message with formatting and indentation support.
    
    Parameters:
    - msg (str): Message template
    - *args: Arguments for message formatting
    - indent (int): Indentation level (4 spaces per level)
    - delimiter (str): Line delimiter (default newline)
    - noformat (bool): Skip string formatting
    - stream: Output stream (default stdout)
    """

def log_list(lst, *args, **kwargs):
    """
    Log a list of messages line by line.
    
    Parameters:
    - lst (list): List of messages to log
    - *args, **kwargs: Passed to log() function
    """

def log_error(msg, *args, **kwargs):
    """
    Log an error message with colored formatting.
    
    Parameters:
    - msg (str): Error message
    - *args, **kwargs: Passed to log() function
    """

@contextmanager  
def outstream(outfile=None):
    """
    Context manager for output stream management.
    
    Parameters:
    - outfile (str): Output filename, or None for stdout
    
    Yields:
    file: Open file handle or stdout
    """

Command-Line Usage Examples

Cyclomatic Complexity Analysis

# Basic complexity analysis
radon cc src/

# Show numeric complexity scores
radon cc --show-complexity src/

# Filter by complexity range
radon cc --min B --max F src/

# Include average complexity
radon cc --average src/

# Sort by different criteria
radon cc --order LINES src/     # Sort by line number
radon cc --order ALPHA src/     # Sort alphabetically  

# Different output formats
radon cc --json src/            # JSON output
radon cc --xml src/             # XML output (CCM compatible)
radon cc --md src/              # Markdown output
radon cc --codeclimate src/     # Code Climate format

# Save to file
radon cc --output-file complexity.json --json src/

# Include Jupyter notebooks
radon cc --include-ipynb --ipynb-cells notebooks/

Raw Metrics Analysis

# Basic raw metrics
radon raw src/

# Show summary statistics
radon raw --summary src/

# JSON output for processing
radon raw --json src/

# Exclude test files
radon raw --exclude "*/tests/*" src/

# Ignore specific directories
radon raw --ignore "__pycache__,*.egg-info" src/

# Include Jupyter notebooks
radon raw --include-ipynb notebooks/

Maintainability Index

# Basic MI analysis
radon mi src/

# Show numeric MI values
radon mi --show src/

# Filter by maintainability grade
radon mi --min B --max A src/    # Only high maintainability

# Sort results
radon mi --sort src/

# Don't count docstrings as comments
radon mi --no-multi src/

# JSON output
radon mi --json src/

Halstead Metrics

# Basic Halstead analysis
radon hal src/

# Analyze by functions instead of files
radon hal --functions src/

# JSON output for detailed metrics
radon hal --json src/

# Save detailed analysis
radon hal --output-file halstead.json --json src/

Configuration Files

Radon supports configuration through multiple file formats:

setup.cfg

[radon]
exclude = */tests/*,*/migrations/*
ignore = __pycache__,.git
cc_min = B
cc_max = F
show_complexity = true
average = true

pyproject.toml

[tool.radon]
exclude = "*/tests/*"
ignore = "__pycache__"
cc_min = "B"
show_complexity = true
average = true

radon.cfg

[radon]
exclude = build/*,dist/*
cc_min = A
cc_max = F
show_complexity = true

Programmatic CLI Usage

Using the CLI components from Python code:

from radon.cli import Config, program
from radon.cli.harvest import CCHarvester
from radon.cli.tools import iter_filenames
import sys

# Create configuration
config = Config(
    min='B',
    max='F',
    show_complexity=True,
    exclude='*/tests/*',
    order='SCORE'
)

# Use file discovery
paths = ['src/']
filenames = list(iter_filenames(paths, exclude=config.exclude))
print(f"Found {len(filenames)} Python files")

# Run complexity analysis
harvester = CCHarvester(paths, config)
harvester.run()

# Get results programmatically
results = harvester.results
for filename, analysis in results.items():
    print(f"{filename}: {len(analysis)} blocks analyzed")

# Format as JSON
json_output = harvester.as_json()
print("JSON output generated")

# Format for terminal
for msg, args, kwargs in harvester.to_terminal():
    if not kwargs.get('error', False):
        print(msg.format(*args) if args else msg)

Custom Harvester Usage

from radon.cli.harvest import RawHarvester, MIHarvester, HCHarvester
from radon.cli import Config

config = Config(summary=True, exclude='*/tests/*')

# Raw metrics harvester
raw_harvester = RawHarvester(['src/'], config)
raw_harvester.run()

print("Raw metrics summary:")
raw_results = raw_harvester.results
total_loc = sum(metrics.loc for metrics in raw_results.values())
total_sloc = sum(metrics.sloc for metrics in raw_results.values())
print(f"Total LOC: {total_loc}")
print(f"Total SLOC: {total_sloc}")

# Maintainability index harvester  
mi_config = Config(show=True, sort=True)
mi_harvester = MIHarvester(['src/'], mi_config)
mi_harvester.run()

# Halstead harvester
hal_config = Config(by_function=True)
hal_harvester = HCHarvester(['src/'], hal_config)
hal_harvester.run()

Integration Examples

CI/CD Pipeline Integration

#!/bin/bash
# ci-quality-check.sh

# Check complexity - fail if any function/class has F grade
if radon cc --min F --json src/ | grep -q '"rank": "F"'; then
    echo "Error: Code contains F-grade complexity"
    exit 1
fi

# Check maintainability - fail if average MI is too low
MI_SCORE=$(radon mi --json src/ | jq '.[] | .mi' | awk '{sum+=$1; count++} END {print sum/count}')
if (( $(echo "$MI_SCORE < 20" | bc -l) )); then
    echo "Error: Maintainability index too low: $MI_SCORE"
    exit 1
fi

echo "Code quality checks passed"

Code Quality Reports

import json
import subprocess
from pathlib import Path

def generate_quality_report(src_path):
    """Generate comprehensive code quality report."""
    
    # Run all radon analyses
    analyses = {}
    
    # Complexity analysis
    cc_result = subprocess.run(
        ['radon', 'cc', '--json', src_path], 
        capture_output=True, text=True
    )
    analyses['complexity'] = json.loads(cc_result.stdout)
    
    # Raw metrics
    raw_result = subprocess.run(
        ['radon', 'raw', '--json', src_path],
        capture_output=True, text=True
    )
    analyses['raw'] = json.loads(raw_result.stdout)
    
    # Maintainability index
    mi_result = subprocess.run(
        ['radon', 'mi', '--json', src_path],
        capture_output=True, text=True
    )
    analyses['maintainability'] = json.loads(mi_result.stdout)
    
    # Generate summary report
    report = {
        'total_files': len(analyses['raw']),
        'total_loc': sum(m['loc'] for m in analyses['raw'].values()),
        'total_sloc': sum(m['sloc'] for m in analyses['raw'].values()),
        'avg_complexity': calculate_avg_complexity(analyses['complexity']),
        'avg_maintainability': calculate_avg_mi(analyses['maintainability']),
        'quality_grade': determine_quality_grade(analyses)
    }
    
    return report

def calculate_avg_complexity(cc_data):
    """Calculate average complexity across all functions."""
    total_complexity = 0
    total_functions = 0
    
    for file_data in cc_data.values():
        for block in file_data:
            total_complexity += block['complexity']
            total_functions += 1
    
    return total_complexity / total_functions if total_functions > 0 else 0

def calculate_avg_mi(mi_data):
    """Calculate average maintainability index."""
    scores = [data['mi'] for data in mi_data.values()]
    return sum(scores) / len(scores) if scores else 0

def determine_quality_grade(analyses):
    """Determine overall quality grade."""
    avg_complexity = calculate_avg_complexity(analyses['complexity'])
    avg_mi = calculate_avg_mi(analyses['maintainability'])
    
    if avg_complexity <= 5 and avg_mi >= 20:
        return 'A'
    elif avg_complexity <= 10 and avg_mi >= 15:
        return 'B'
    elif avg_complexity <= 20 and avg_mi >= 10:
        return 'C'
    else:
        return 'D'

# Usage
# report = generate_quality_report('src/')
# print(f"Quality Grade: {report['quality_grade']}")

Error Handling and Debugging

The CLI handles various error conditions gracefully:

  • File not found: Clear error messages for missing files/directories
  • Syntax errors: Reports files with parsing errors and continues
  • Permission errors: Handles files that cannot be read
  • Configuration errors: Validates configuration values and provides defaults
  • Output errors: Handles file write permissions and disk space issues

Debug Mode

# Enable verbose output for troubleshooting
RADON_DEBUG=1 radon cc src/

# Check configuration loading
radon cc --help  # Shows all available options and defaults

Performance Considerations

  • Large codebases: Use --exclude and --ignore to skip unnecessary files
  • Parallel processing: Radon processes files sequentially; use shell scripting for parallelization
  • Memory usage: JSON output can be memory-intensive for very large projects
  • Network filesystems: Local analysis is faster than network-mounted directories

The CLI provides a comprehensive interface for all radon analysis capabilities while maintaining compatibility with automated workflows and integration tools.

Install with Tessl CLI

npx tessl i tessl/pypi-radon

docs

cli.md

complexity.md

halstead.md

index.md

maintainability.md

raw-metrics.md

visitors.md

tile.json