An extensible cyclomatic complexity analyzer for many programming languages including C/C++, Java, JavaScript, Python, Ruby, Swift, and more.
—
Core data structures representing analysis results including function information, file statistics, and complexity metrics. These classes provide structured access to all code analysis data.
Represents detailed information about individual functions with complexity metrics and location data.
class FunctionInfo(Nesting):
"""
Represents function information with complexity metrics.
Attributes:
name (str): Function name
cyclomatic_complexity (int): McCabe cyclomatic complexity number
nloc (int): Number of lines of code without comments
token_count (int): Number of tokens in the function
parameter_count (int): Number of function parameters
parameters (list): List of parameter names extracted from full_parameters
length (int): Total lines including comments and blank lines
location (str): File path and line number (e.g., "file.py:25")
start_line (int): Starting line number of the function
end_line (int): Ending line number of the function
filename (str): File containing the function
long_name (str): Full qualified name with namespace
full_parameters (str): Raw parameter list as string
fan_in (int): Number of functions calling this function
fan_out (int): Number of functions called by this function
general_fan_out (int): General fan-out metric
max_nesting_depth (int): Maximum nesting depth reached in the function
top_nesting_level (int): Top-level nesting information
unqualified_name (str): Function name without namespace qualifiers
"""
def add_to_function_name(self, app):
"""
Appends text to the function name.
Args:
app (str): Text to append to function name
"""
def add_to_long_name(self, app):
"""
Appends text to the long function name (includes namespace).
Args:
app (str): Text to append to long name
"""
def add_parameter(self, token):
"""
Adds a parameter to the function's parameter count.
Args:
token (str): Parameter token to add
"""Contains comprehensive file-level statistics and the list of functions found in the file.
class FileInformation:
"""
Contains file-level statistics and function list.
Attributes:
filename (str): Path to the analyzed file
nloc (int): Total lines of code without comments in file
function_list (list): List of FunctionInfo objects for functions in file
average_nloc (float): Average lines of code per function
average_token_count (float): Average token count per function
average_cyclomatic_complexity (float): Average cyclomatic complexity per function
CCN (int): Total cyclomatic complexity for the file
ND (int): Total of maximum nesting depths across all functions in the file
token_count (int): Total token count for the file
"""
def functions_average(self, attr_name):
"""
Calculates average of a function attribute across all functions.
Args:
attr_name (str): Name of the attribute to average
Returns:
float: Average value of the attribute, or 0 if no functions
Example:
avg_complexity = file_info.functions_average('cyclomatic_complexity')
avg_params = file_info.functions_average('parameter_count')
"""Main analysis engine that processes individual files and applies extensions.
class FileAnalyzer:
"""
Main file analysis engine with extension support.
Args:
extensions (list): List of extension objects to apply during analysis
"""
def __call__(self, filename):
"""
Analyzes a single file and returns file information.
Args:
filename (str): Path to file to analyze
Returns:
FileInformation: Analysis results for the file
Example:
analyzer = FileAnalyzer([])
file_info = analyzer('src/app.py')
print(f"Functions found: {len(file_info.function_list)}")
"""
def analyze_source_code(self, filename, code):
"""
Analyzes source code string and returns file information.
Args:
filename (str): Filename for the code (used for language detection)
code (str): Source code to analyze
Returns:
FileInformation: Analysis results for the code
Example:
analyzer = FileAnalyzer([])
code = "def hello():\\n print('world')"
file_info = analyzer.analyze_source_code('test.py', code)
"""Classes representing code nesting levels and namespace structures.
class Nesting:
"""
Base class representing one level of nesting.
Attributes:
name_in_space (str): Name within the current namespace
"""
class Namespace(Nesting):
"""
Represents namespace nesting level.
Args:
name (str): Name of the namespace
"""
def __init__(self, name):
"""
Initialize namespace with given name.
Args:
name (str): Name of the namespace
"""
@property
def name_in_space(self):
"""
Returns the namespace name.
Returns:
str: The namespace name
"""Supporting classes for building analysis results and managing nesting state.
class FileInfoBuilder:
"""
Builder for file and function information (also called "context").
Manages the construction of FileInformation objects during parsing.
"""
class NestingStack:
"""
Manages nesting stack for code analysis.
Properties:
current_nesting_level (int): Current depth of nesting
last_function (FunctionInfo): Most recently processed function
"""
def add_namespace(self, namespace):
"""Add a namespace to the nesting stack."""
def start_new_function_nesting(self, func):
"""Start tracking a new function's nesting."""
def pop_nesting(self):
"""Remove the top level of nesting."""
class OutputScheme:
"""
Manages output formatting and column schemas.
Handles the formatting of analysis results for display.
"""
def function_info_head(self):
"""Returns header string for function information display."""
def function_info(self, func):
"""Formats function information for display."""
class AllResult:
"""
Aggregates analysis results across all files.
Provides summary statistics for entire analysis runs.
"""
def function_count(self):
"""Returns total number of functions analyzed."""
def nloc_in_functions(self):
"""Returns total lines of code in all functions."""
def as_fileinfo(self):
"""Returns aggregated data as a FileInformation object."""import lizard
results = lizard.analyze(['src/'])
for file_info in results:
print(f"File: {file_info.filename}")
print(f"Total NLOC: {file_info.nloc}")
print(f"Number of functions: {len(file_info.function_list)}")
for func in file_info.function_list:
print(f" Function: {func.name}")
print(f" Location: {func.location}")
print(f" Complexity: {func.cyclomatic_complexity}")
print(f" NLOC: {func.nloc}")
print(f" Parameters: {func.parameter_count}")
print(f" Length: {func.length}")import lizard
results = lizard.analyze(['src/'])
for file_info in results:
print(f"File: {file_info.filename}")
print(f" Total complexity: {file_info.CCN}")
print(f" Max nesting depth: {file_info.ND}")
print(f" Average complexity per function: {file_info.average_cyclomatic_complexity:.2f}")
print(f" Average NLOC per function: {file_info.average_nloc:.2f}")
print(f" Average tokens per function: {file_info.average_token_count:.2f}")import lizard
# Analyze a single file directly
analyzer = lizard.FileAnalyzer([])
file_info = analyzer('src/complex_module.py')
print(f"Analyzed: {file_info.filename}")
print(f"Functions found: {len(file_info.function_list)}")
# Find most complex function
most_complex = max(file_info.function_list,
key=lambda f: f.cyclomatic_complexity)
print(f"Most complex function: {most_complex.name} (CCN: {most_complex.cyclomatic_complexity})")import lizard
code = '''
def calculate_price(base_price, discount, tax_rate):
if discount > 0:
if discount > 0.5:
final_price = base_price * 0.5
else:
final_price = base_price * (1 - discount)
else:
final_price = base_price
if tax_rate > 0:
final_price *= (1 + tax_rate)
return final_price
'''
analyzer = lizard.FileAnalyzer([])
file_info = analyzer.analyze_source_code('example.py', code)
func = file_info.function_list[0]
print(f"Function: {func.name}")
print(f"Complexity: {func.cyclomatic_complexity}")
print(f"Parameters: {func.parameter_count}")
print(f"NLOC: {func.nloc}")Install with Tessl CLI
npx tessl i tessl/pypi-lizard