#!/usr/bin/env python3
import inspect
import importlib
from argparse import ArgumentParser
try:
import graphviz
_has_graphviz = True
except ModuleNotFoundError:
_has_graphviz = False
# Import all the classes
from siliconcompiler import (Project, ASIC, FPGA, Lint, Sim, Design, PDK,
Flowgraph, Checklist, StdCellLibrary, FPGADevice,
Task, ShowTask, ScreenshotTask, Schematic)
from siliconcompiler.asic import ASICTask
from siliconcompiler.constraints import (ASICTimingConstraintSchema, ASICAreaConstraint,
ASICComponentConstraints, ASICPinConstraints,
FPGAComponentConstraints, FPGAPinConstraints,
FPGATimingConstraintSchema)
from siliconcompiler.schema_support import metric, record, option
from siliconcompiler.library import ToolLibrarySchema
def generate_class_hierarchy(classes, output_file="class_hierarchy"):
"""
Generates a class inheritance graph using graphviz.
"""
if not _has_graphviz:
raise RuntimeError("Graphviz is not installed."
" Please install it to generate class hierarchy graphs.")
dot = graphviz.Digraph('SiliconCompiler Class Hierarchy',
comment='SiliconCompiler Class Hierarchy')
dot.attr('graph', rankdir='RL', concentrate='true')
dot.attr('node', shape='box', )
SCHEMA_COLOR = "#fff8dc" # cornsilk
SCHEMA_SUPPORT_COLOR = "#add8e6" # lightblue
DEFAULT_COLOR = "#d3d3d3" # lightgrey
# Classes exposed at the top-level of the siliconcompiler package
TOP_LEVEL_CLASSES = {
'Project', 'ASIC', 'FPGA', 'Lint', 'Sim', 'Design', 'PDK',
'Flowgraph', 'Checklist', 'StdCellLibrary', 'FPGADevice',
'Task', 'ShowTask', 'ScreenshotTask', 'Schematic'
}
added_nodes = set()
all_mro_classes = set()
for cls in classes:
mro = [c for c in inspect.getmro(cls) if 'siliconcompiler' in c.__module__ or c is cls]
all_mro_classes.update(mro)
# Create a subgraph for top-level classes to cluster them
with dot.subgraph(name='cluster_api') as c:
c.attr(label='SiliconCompiler API', , color='#f0f0f0', fontcolor='black')
for cls in all_mro_classes:
if cls.__name__ not in added_nodes:
module_name = cls.__module__
if module_name.startswith('siliconcompiler.schema.'):
color = SCHEMA_COLOR
elif module_name.startswith('siliconcompiler.schema_support.'):
color = SCHEMA_SUPPORT_COLOR
else:
color = DEFAULT_COLOR
# Add node to the cluster or the main graph
if cls.__name__ in TOP_LEVEL_CLASSES:
c.node(cls.__name__, fillcolor=color)
else:
dot.node(cls.__name__, fillcolor=color)
added_nodes.add(cls.__name__)
edges = []
for cls in all_mro_classes:
for base in cls.__bases__:
if 'siliconcompiler' not in base.__module__:
continue
if (base.__name__, cls.__name__) in edges:
continue
edges.append((base.__name__, cls.__name__))
# Add edge
dot.edge(f"{base.__name__}:w", f"{cls.__name__}:e")
# Save the dot file and render a PNG
try:
dot.render(output_file, view=False, format='png', cleanup=True)
print(f"Generated class hierarchy graph at {output_file}.png")
except graphviz.ExecutableNotFound:
print("Graphviz executable not found. Please install it and add it to your PATH.")
print("On Debian/Ubuntu: sudo apt-get install graphviz")
print("On macOS (with Homebrew): brew install graphviz")
with open(f"{output_file}.dot", 'w') as f:
f.write(dot.source)
print(f"Generated dot file at {output_file}.dot")
if __name__ == "__main__":
parser = ArgumentParser(
description="Generate a class inheritance graph for SiliconCompiler classes.")
parser.add_argument("cls", nargs="?",
help="A specific class to graph in module/ClassName format "
"(e.g., siliconcompiler/Project).")
parser.add_argument("--output", default="class_hierarchy",
help="Output file name without extension.")
args = parser.parse_args()
if args.cls:
module, cls_name = args.cls.split("/")
classes_to_graph = [getattr(importlib.import_module(module), cls_name)]
else:
# The list of classes from methods.py
classes_to_graph = [
Project, ASIC, FPGA, Lint, Sim,
Design, PDK, Flowgraph, Checklist, StdCellLibrary, FPGADevice, Schematic,
Task, ShowTask, ScreenshotTask,
ASICTask,
ASICTimingConstraintSchema, ASICAreaConstraint, ASICComponentConstraints,
ASICPinConstraints, FPGAComponentConstraints, FPGAPinConstraints,
FPGATimingConstraintSchema,
metric.MetricSchema, record.RecordSchema, option.OptionSchema,
ToolLibrarySchema
]
generate_class_hierarchy(classes_to_graph, args.output)