Comprehensive static code analysis tool for Python that performs deep code inspection without executing the program
—
UML diagram generation tool that analyzes Python code structure and creates class diagrams, package diagrams, and dependency visualizations in multiple formats. Pyreverse helps understand code architecture and relationships through visual representations.
Primary function for running pyreverse from Python code.
def run_pyreverse(argv=None):
"""
Generate UML diagrams from Python code.
Args:
argv (list, optional): Command line arguments. If None, uses sys.argv[1:]
Example:
run_pyreverse(['mypackage/', '--output-format=svg'])
run_pyreverse(['--help'])
"""Main class for handling pyreverse command-line operations.
class Run:
"""
Pyreverse command-line interface.
Processes command-line arguments, analyzes Python code,
and generates UML diagrams in various formats.
"""
def __init__(self, args):
"""
Initialize and run pyreverse.
Args:
args (list): Command line arguments
"""Classes for defining and managing diagram structures and content.
class DiadefsHandler:
"""
Diagram definition handler.
Manages the creation and organization of diagram definitions
based on code analysis results.
"""
def __init__(self, config):
"""
Initialize diagram handler.
Args:
config: Configuration object
"""
def get_diadefs(self, project, linker):
"""
Get diagram definitions for project.
Args:
project: Analyzed project object
linker: Object linking system
Returns:
list: Diagram definition objects
"""
class DiaDefGenerator:
"""
Diagram definition generator.
Generates diagram definitions by analyzing code structure
and relationships between classes and packages.
"""
def __init__(self, linker, handler):
"""
Initialize diagram generator.
Args:
linker: Object linking system
handler: Diagram handler
"""
def visit_project(self, node):
"""
Visit project node and generate diagrams.
Args:
node: Project AST node
"""Classes representing different types of UML diagrams.
class PackageDiagram:
"""
Package relationship diagrams.
Shows dependencies and relationships between packages
and modules in the analyzed code.
"""
def __init__(self, title, objects):
"""
Initialize package diagram.
Args:
title (str): Diagram title
objects (list): Objects to include in diagram
"""
def get_relationships(self):
"""
Get package relationships.
Returns:
list: Package relationship objects
"""
class ClassDiagram:
"""
Class relationship diagrams.
Shows inheritance hierarchies, associations, and
dependencies between classes.
"""
def __init__(self, title, objects):
"""
Initialize class diagram.
Args:
title (str): Diagram title
objects (list): Class objects to include
"""
def get_methods(self, node):
"""
Get methods for a class node.
Args:
node: Class AST node
Returns:
list: Method information
"""
def get_attrs(self, node):
"""
Get attributes for a class node.
Args:
node: Class AST node
Returns:
list: Attribute information
"""Classes for generating diagrams in different output formats.
class DiagramWriter:
"""
Base diagram writer.
Abstract base class for all diagram output formats,
providing common functionality and interface.
"""
def __init__(self, config):
"""
Initialize diagram writer.
Args:
config: Configuration object
"""
def write(self, diadefs):
"""
Write diagrams to output.
Args:
diadefs (list): Diagram definitions to write
"""
class DotWriter(DiagramWriter):
"""
Graphviz DOT format writer.
Generates diagrams in DOT format for rendering
with Graphviz tools (dot, neato, circo, etc.).
"""
def __init__(self, config):
"""Initialize DOT writer."""
super().__init__(config)
def write_packages(self, diagram):
"""
Write package diagram in DOT format.
Args:
diagram: Package diagram object
"""
def write_classes(self, diagram):
"""
Write class diagram in DOT format.
Args:
diagram: Class diagram object
"""
class PlantUmlWriter(DiagramWriter):
"""
PlantUML format writer.
Generates diagrams in PlantUML format for rendering
with PlantUML tools and online services.
"""
def __init__(self, config):
"""Initialize PlantUML writer."""
super().__init__(config)
def write_packages(self, diagram):
"""
Write package diagram in PlantUML format.
Args:
diagram: Package diagram object
"""
def write_classes(self, diagram):
"""
Write class diagram in PlantUML format.
Args:
diagram: Class diagram object
"""
class MermaidWriter(DiagramWriter):
"""
Mermaid format writer.
Generates diagrams in Mermaid format for rendering
in Markdown, GitHub, and web applications.
"""
def __init__(self, config):
"""Initialize Mermaid writer."""
super().__init__(config)
def write_packages(self, diagram):
"""
Write package diagram in Mermaid format.
Args:
diagram: Package diagram object
"""
def write_classes(self, diagram):
"""
Write class diagram in Mermaid format.
Args:
diagram: Class diagram object
"""import pylint
# Generate class diagrams for a package
pylint.run_pyreverse(['mypackage/', '--output-format=png'])
# Generate both class and package diagrams
pylint.run_pyreverse([
'myproject/',
'--output-format=svg',
'--project=MyProject'
])
# Generate PlantUML format
pylint.run_pyreverse([
'src/',
'--output-format=plantuml',
'--output-directory=docs/diagrams/'
])# Basic class diagram generation
pyreverse mypackage/
# Specify output format and directory
pyreverse --output-format=svg --output-directory=docs/ mypackage/
# Generate both class and package diagrams
pyreverse --show-associated --show-builtin mypackage/
# Filter classes and show details
pyreverse --filter-mode=PUB_ONLY --show-ancestors=2 mypackage/
# Generate PlantUML format
pyreverse --output-format=plantuml --project=MyApp src/
# Generate Mermaid format
pyreverse --output-format=mermaid --colorized src/from pylint.pyreverse.main import Run
from pylint.pyreverse.diadefslib import DiadefsHandler, DiaDefGenerator
from pylint.pyreverse.writer import DotWriter, PlantUmlWriter
# Run pyreverse programmatically
args = [
'mypackage/',
'--output-format=svg',
'--project=MyProject',
'--output-directory=output/'
]
pyreverse_run = Run(args)
# Custom diagram generation
class CustomDiagramGenerator:
"""Custom diagram generation example."""
def __init__(self, package_path):
self.package_path = package_path
def generate_diagrams(self):
"""Generate custom diagrams."""
# This would involve using pyreverse internals
# to create custom diagram analysis and output
pass# Configure pyreverse options
config = {
'output_format': 'svg',
'output_directory': 'diagrams/',
'project': 'MyProject',
'show_ancestors': 2,
'show_associated': True,
'show_builtin': False,
'module_names': True,
'colorized': True,
'max_color_depth': 2,
'ignore': ['tests', '__pycache__'],
'filter_mode': 'PUB_ONLY' # Show only public members
}
# Apply configuration and run
args = []
for key, value in config.items():
if isinstance(value, bool) and value:
args.append(f'--{key.replace("_", "-")}')
elif not isinstance(value, bool):
args.extend([f'--{key.replace("_", "-")}', str(value)])
args.append('mypackage/')
pylint.run_pyreverse(args)digraph "classes" {
charset="utf-8"
rankdir=BT
"mypackage.MyClass" [label="{MyClass|data : str\lvalue : int\l|process()\lvalidate()\l}",shape="record"];
"mypackage.BaseClass" [label="{BaseClass|name : str\l|__init__()\l}",shape="record"];
"mypackage.MyClass" -> "mypackage.BaseClass" [arrowhead="empty",arrowtail="none"];
}@startuml classes
set namespaceSeparator none
class "mypackage.BaseClass" as mypackage.BaseClass {
name : str
__init__()
}
class "mypackage.MyClass" as mypackage.MyClass {
data : str
value : int
process()
validate()
}
mypackage.MyClass --|> mypackage.BaseClass
@endumlclassDiagram
class BaseClass {
+str name
+__init__()
}
class MyClass {
+str data
+int value
+process()
+validate()
}
MyClass --|> BaseClass# Control what to show in diagrams
show_ancestors = 2 # Number of ancestor levels to show
show_associated = True # Show associated classes
show_builtin = False # Show built-in types
only_classnames = False # Show only class names, no details
module_names = True # Show module names in class labels# Output configuration
output_format = 'png' # png, svg, dot, plantuml, mermaid
output_directory = 'diagrams/' # Output directory
project = 'MyProject' # Project name for diagram titles
colorized = True # Use colors in diagrams
max_color_depth = 2 # Maximum color depth# Content filtering
filter_mode = 'PUB_ONLY' # PUB_ONLY, ALL, SPECIAL
ignore = ['tests', 'docs'] # Directories/files to ignore
class_names = ['MyClass', 'BaseClass'] # Specific classes to include# GitHub Actions example
name: Generate UML Diagrams
on: [push]
jobs:
diagrams:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install pylint graphviz
- name: Generate diagrams
run: |
pyreverse --output-format=svg --output-directory=docs/diagrams/ src/
- name: Commit diagrams
run: |
git add docs/diagrams/
git commit -m "Update UML diagrams" || exit 0
git push# Sphinx integration example
def generate_uml_diagrams():
"""Generate UML diagrams for Sphinx documentation."""
import os
import pylint
# Create diagrams directory
diagrams_dir = 'docs/source/_static/diagrams'
os.makedirs(diagrams_dir, exist_ok=True)
# Generate SVG diagrams for web display
pylint.run_pyreverse([
'src/',
'--output-format=svg',
f'--output-directory={diagrams_dir}',
'--project=MyProject',
'--colorized'
])
print(f"UML diagrams generated in {diagrams_dir}")
# Add to Sphinx conf.py
def setup(app):
generate_uml_diagrams()def analyze_class_complexity():
"""Analyze class complexity using pyreverse data."""
# This would involve extending pyreverse to collect
# additional metrics during diagram generation
# Example: Count methods, attributes, inheritance depth
class ComplexityAnalyzer:
def __init__(self):
self.metrics = {}
def visit_classdef(self, node):
"""Collect class complexity metrics."""
class_name = node.name
method_count = len([n for n in node.body
if n.__class__.__name__ == 'FunctionDef'])
attr_count = len([n for n in node.body
if n.__class__.__name__ == 'Assign'])
self.metrics[class_name] = {
'methods': method_count,
'attributes': attr_count,
'complexity': method_count + attr_count
}
def report(self):
"""Generate complexity report."""
for class_name, metrics in self.metrics.items():
print(f"{class_name}: {metrics['complexity']} complexity points")Install with Tessl CLI
npx tessl i tessl/pypi-pylint