Advanced Hierarchy Managementο
Implementation Date: 2025-11-05 Issue: #37 - Advanced hierarchy and sheet management (2.7) Issue: #100 - Hierarchical sheet component references Status: β Complete
Overviewο
This document covers two aspects of hierarchical schematic management:
Creating Hierarchical Schematics - How to build hierarchical designs with proper component references
Analyzing Hierarchical Schematics - How to analyze existing hierarchical designs
Part 1: Creating Hierarchical Schematicsο
Component Reference Problem (Issue #100)ο
When creating hierarchical schematics, components in child sheets must have correct hierarchical instance paths for KiCad to properly assign reference designators. Without proper paths, KiCad shows β?β instead of βC1β, βR1β, etc.
Solution: set_hierarchy_context()ο
Use the set_hierarchy_context() method to configure child schematics with proper hierarchical paths.
Quick Start Exampleο
import kicad_sch_api as ksa
# 1. Create parent schematic
main = ksa.create_schematic("MyProject")
parent_uuid = main.uuid
# 2. Add sheet to parent
power_sheet_uuid = main.sheets.add_sheet(
name="Power Supply",
filename="power.kicad_sch",
position=(50, 50),
size=(100, 100),
project_name="MyProject" # MUST match parent project name
)
# 3. Add sheet pins
main.sheets.add_sheet_pin(power_sheet_uuid, "VIN", "input", "left", 5)
main.sheets.add_sheet_pin(power_sheet_uuid, "+3.3V", "output", "right", 5)
# 4. Create child schematic with hierarchy context
power = ksa.create_schematic("MyProject") # SAME project name
power.set_hierarchy_context(parent_uuid, power_sheet_uuid) # KEY STEP!
# 5. Add components - they automatically get correct hierarchical paths
vreg = power.components.add(
'Regulator_Linear:AMS1117-3.3',
'U1',
'AMS1117-3.3',
position=(127, 101.6)
)
# Component instance path: /parent_uuid/power_sheet_uuid (CORRECT!)
# 6. Save both schematics
main.save("main.kicad_sch")
power.save("power.kicad_sch")
Complete Hierarchical Design Patternο
import kicad_sch_api as ksa
from pathlib import Path
# Project configuration
PROJECT_NAME = "STM32_Board"
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
# ===== STEP 1: Create Main Schematic =====
main = ksa.create_schematic(PROJECT_NAME)
parent_uuid = main.uuid # Save for child schematics
# ===== STEP 2: Add Hierarchical Sheets =====
# Power supply sheet
power_sheet_uuid = main.sheets.add_sheet(
name="Power Supply",
filename="power.kicad_sch",
position=(50, 50),
size=(100, 80),
project_name=PROJECT_NAME
)
main.sheets.add_sheet_pin(power_sheet_uuid, "VIN", "input", "left", 5)
main.sheets.add_sheet_pin(power_sheet_uuid, "+3.3V", "output", "right", 5)
main.sheets.add_sheet_pin(power_sheet_uuid, "GND", "passive", "bottom", 10)
# MCU sheet
mcu_sheet_uuid = main.sheets.add_sheet(
name="Microcontroller",
filename="mcu.kicad_sch",
position=(175, 50),
size=(100, 80),
project_name=PROJECT_NAME
)
main.sheets.add_sheet_pin(mcu_sheet_uuid, "+3.3V", "input", "left", 5)
main.sheets.add_sheet_pin(mcu_sheet_uuid, "GND", "passive", "bottom", 10)
# Add labels for connections
main.add_label("+3.3V", position=(155, 55))
main.add_label("GND", position=(100, 140))
# Save main schematic
main.save(str(output_dir / f"{PROJECT_NAME}.kicad_sch"))
# ===== STEP 3: Create Child Schematics with Hierarchy Context =====
# Power supply child schematic
power = ksa.create_schematic(PROJECT_NAME)
power.set_hierarchy_context(parent_uuid, power_sheet_uuid) # Set context!
vreg = power.components.add(
'Regulator_Linear:AMS1117-3.3',
'U1',
'AMS1117-3.3',
position=(127, 101.6)
)
vreg.footprint = 'Package_TO_SOT_SMD:SOT-223-3_TabPin2'
c_in = power.components.add('Device:C', 'C1', '10Β΅F', position=(101.6, 101.6))
c_out = power.components.add('Device:C', 'C2', '10Β΅F', position=(152.4, 101.6))
power.add_label("VIN", position=(76.2, 101.6))
power.add_label("+3.3V", position=(177.8, 101.6))
power.add_label("GND", position=(127, 127))
power.save(str(output_dir / "power.kicad_sch"))
# MCU child schematic
mcu_sch = ksa.create_schematic(PROJECT_NAME)
mcu_sch.set_hierarchy_context(parent_uuid, mcu_sheet_uuid) # Set context!
mcu = mcu_sch.components.add(
'MCU_ST_STM32G4:STM32G431R_6-8-B_Tx',
'U2',
'STM32G431RBT6',
position=(127, 101.6)
)
mcu.footprint = 'Package_QFP:LQFP-64_10x10mm_P0.5mm'
# Add decoupling caps
for i, x_pos in enumerate([101.6, 152.4], start=3):
cap = mcu_sch.components.add('Device:C', f'C{i}', '100nF', position=(x_pos, 76.2))
cap.footprint = 'Capacitor_SMD:C_0603_1608Metric'
mcu_sch.add_label("+3.3V", position=(76.2, 63.5))
mcu_sch.add_label("GND", position=(127, 152.4))
mcu_sch.save(str(output_dir / "mcu.kicad_sch"))
print(f"β Hierarchical schematic created in {output_dir}/")
print(f" - {PROJECT_NAME}.kicad_sch (main)")
print(f" - power.kicad_sch (child)")
print(f" - mcu.kicad_sch (child)")
Critical Requirementsο
Same Project Name: All schematics (parent and children) MUST use the same project name
main = ksa.create_schematic("MyProject") child = ksa.create_schematic("MyProject") # SAME name!
Call
set_hierarchy_context()BEFORE Adding Components:child = ksa.create_schematic("MyProject") child.set_hierarchy_context(parent_uuid, sheet_uuid) # Do this FIRST child.components.add(...) # Then add components
Save Parent UUID Early:
main = ksa.create_schematic("MyProject") parent_uuid = main.uuid # Save this immediately
Pass
project_nametoadd_sheet():sheet_uuid = main.sheets.add_sheet( name="Child", filename="child.kicad_sch", position=(50, 50), size=(100, 80), project_name="MyProject" # Required! )
What Happens Internallyο
When you call set_hierarchy_context():
The schematic stores the parent UUID and sheet UUID
The hierarchical path is computed:
/{parent_uuid}/{sheet_uuid}When components are added, this path is automatically set in their instance data
KiCad uses this path to properly annotate components
Without set_hierarchy_context():
Component path:
/child_uuidβ WRONGKiCad shows: βC?β instead of βC1β
With set_hierarchy_context():
Component path:
/parent_uuid/sheet_uuidβ CORRECTKiCad shows: βC1β, βC2β, βR1β (proper references)
Real-World Exampleο
For hierarchical schematic examples, refer to the test fixtures in tests/reference_kicad_projects/ which demonstrate:
Parent/child schematic relationships
Sheet pin connections
Hierarchical label usage
Multi-level hierarchy structures
Part 2: Analyzing Hierarchical Schematicsο
The HierarchyManager provides comprehensive tools for analyzing existing hierarchical KiCAD schematic designs.
Features Implementedο
1. Sheet Reuse Tracking β ο
Track sheets used multiple times in a design (same schematic file instantiated in different locations).
tree = sch.hierarchy.build_hierarchy_tree(sch)
reused = sch.hierarchy.find_reused_sheets()
for filename, instances in reused.items():
print(f"{filename} used {len(instances)} times")
Key Methods:
build_hierarchy_tree()- Build complete hierarchy treefind_reused_sheets()- Find sheets instantiated multiple times
2. Cross-Sheet Signal Tracking β ο
Trace signals through hierarchical boundaries.
paths = sch.hierarchy.trace_signal_path("VCC")
for path in paths:
print(f"Signal: {path.signal_name}")
print(f"Path: {path.start_path} β {path.end_path}")
print(f"Sheet crossings: {path.sheet_crossings}")
Key Methods:
trace_signal_path(signal_name, start_path)- Trace signal through hierarchyReturns
SignalPathobjects with routing information
3. Sheet Pin Validation β ο
Validate sheet pins match hierarchical labels in child schematics.
tree = sch.hierarchy.build_hierarchy_tree(sch, schematic_path)
connections = sch.hierarchy.validate_sheet_pins()
errors = sch.hierarchy.get_validation_errors()
for error in errors:
print(f"Pin {error['pin_name']}: {error['error']}")
Validation Checks:
Sheet pins have matching hierarchical labels
Pin types are compatible (input/output/bidirectional)
Pin names match exactly
No duplicate pins
Key Methods:
validate_sheet_pins()- Validate all sheet pin connectionsget_validation_errors()- Get detailed validation errors
4. Hierarchy Flattening β ο
Flatten hierarchical design into single-level representation.
flattened = sch.hierarchy.flatten_hierarchy(prefix_references=True)
print(f"Components: {len(flattened['components'])}")
print(f"Wires: {len(flattened['wires'])}")
# Hierarchy map shows original locations
for ref, path in flattened['hierarchy_map'].items():
print(f"{ref} was in {path}")
Options:
prefix_references=True- Prefix component references with sheet pathprefix_references=False- Keep original references
Key Methods:
flatten_hierarchy(prefix_references)- Flatten to single level
5. Hierarchy Visualization β ο
Generate text-based hierarchy tree visualization.
viz = sch.hierarchy.visualize_hierarchy(include_stats=True)
print(viz)
# Output:
# βββ Root (5 components)
# β βββ PowerSupply [power.kicad_sch] (3 components)
# β βββ MCU [mcu.kicad_sch] (12 components)
Key Methods:
visualize_hierarchy(include_stats)- Generate tree visualizationget_hierarchy_statistics()- Get comprehensive statistics
6. Hierarchy Statistics β ο
Get comprehensive statistics about hierarchical design.
stats = sch.hierarchy.get_hierarchy_statistics()
print(f"Total sheets: {stats['total_sheets']}")
print(f"Max depth: {stats['max_hierarchy_depth']}")
print(f"Reused sheets: {stats['reused_sheets_count']}")
print(f"Components: {stats['total_components']}")
print(f"Wires: {stats['total_wires']}")
print(f"Valid connections: {stats['valid_connections']}")
Architectureο
Core Classesο
HierarchyManagerο
Main manager class providing all hierarchy operations.
Key Properties:
_hierarchy_tree- Root node of hierarchy tree_sheet_instances- Tracks all sheet instances_loaded_schematics- Cache of loaded schematics_pin_connections- Validated sheet pin connections
HierarchyNodeο
Represents a node in the hierarchy tree.
Key Properties:
path- Hierarchical path (e.g., β/root_uuid/child_uuid/β)name- Sheet nameschematic- Loaded schematic objectparent- Parent nodechildren- List of child nodesis_root- Whether this is the root node
Methods:
get_depth()- Get depth in hierarchy (root = 0)get_full_path()- Get full path from root to this nodeadd_child(node)- Add child node
SheetInstanceο
Represents a single instance of a hierarchical sheet.
Properties:
sheet_uuid- UUID of sheet symbolsheet_name- Name of the sheetfilename- Referenced schematic filenamepath- Hierarchical pathparent_path- Parentβs pathschematic- Loaded schematic objectsheet_pins- List of sheet pinsposition- Position on parent schematic
SheetPinConnectionο
Represents validated connection between sheet pin and hierarchical label.
Properties:
sheet_path- Path to sheet instancesheet_pin_name- Sheet pin namesheet_pin_type- Pin type (input/output/bidirectional)hierarchical_label_name- Matching label namevalidated- Whether connection is validvalidation_errors- List of validation errors
SignalPathο
Represents a signalβs path through hierarchy.
Properties:
signal_name- Name of signalstart_path- Starting hierarchical pathend_path- Ending hierarchical pathconnections- List of connection pointssheet_crossings- Number of sheet boundaries crossed
API Referenceο
Building Hierarchyο
# Build hierarchy tree from root schematic
tree = sch.hierarchy.build_hierarchy_tree(sch, schematic_path)
Sheet Reuseο
# Find sheets used multiple times
reused = sch.hierarchy.find_reused_sheets()
# Returns: Dict[filename, List[SheetInstance]]
Validationο
# Validate sheet pins
connections = sch.hierarchy.validate_sheet_pins()
# Returns: List[SheetPinConnection]
# Get validation errors
errors = sch.hierarchy.get_validation_errors()
# Returns: List[Dict[str, Any]]
Signal Tracingο
# Trace signal through hierarchy
paths = sch.hierarchy.trace_signal_path("SIGNAL_NAME", start_path="/")
# Returns: List[SignalPath]
Flatteningο
# Flatten hierarchy
flattened = sch.hierarchy.flatten_hierarchy(prefix_references=True)
# Returns: Dict with 'components', 'wires', 'labels', 'hierarchy_map'
Statisticsο
# Get statistics
stats = sch.hierarchy.get_hierarchy_statistics()
# Returns: Dict with comprehensive statistics
Visualizationο
# Visualize hierarchy
viz = sch.hierarchy.visualize_hierarchy(include_stats=True)
# Returns: String representation of tree
Usage Patternsο
Pattern 1: Validate Hierarchical Designο
# Load root schematic
sch = ksa.Schematic.load("project.kicad_sch")
# Build hierarchy tree
tree = sch.hierarchy.build_hierarchy_tree(sch, Path("project.kicad_sch"))
# Validate all sheet pins
connections = sch.hierarchy.validate_sheet_pins()
# Check for errors
errors = sch.hierarchy.get_validation_errors()
if errors:
for error in errors:
print(f"ERROR: {error['sheet_path']} - {error['pin_name']}: {error['error']}")
Pattern 2: Analyze Reusable Modulesο
# Build hierarchy
tree = sch.hierarchy.build_hierarchy_tree(sch, sch_path)
# Find reused sheets
reused = sch.hierarchy.find_reused_sheets()
for filename, instances in reused.items():
print(f"\nModule: {filename}")
print(f"Used {len(instances)} times:")
for inst in instances:
print(f" - {inst.sheet_name} at {inst.path}")
Pattern 3: Flatten for Analysisο
# Build and flatten
tree = sch.hierarchy.build_hierarchy_tree(sch, sch_path)
flattened = sch.hierarchy.flatten_hierarchy(prefix_references=True)
# Analyze flattened design
print(f"Total components: {len(flattened['components'])}")
print(f"Total connections: {len(flattened['wires'])}")
# Map back to original locations
for comp in flattened['components']:
print(f"{comp['reference']}: {comp['lib_id']} from {comp['hierarchy_path']}")
Pattern 4: Generate Hierarchy Reportο
# Build hierarchy
tree = sch.hierarchy.build_hierarchy_tree(sch, sch_path)
# Get statistics
stats = sch.hierarchy.get_hierarchy_statistics()
# Generate report
print("=" * 60)
print("HIERARCHY REPORT")
print("=" * 60)
print(f"Total Sheets: {stats['total_sheets']}")
print(f"Max Depth: {stats['max_hierarchy_depth']}")
print(f"Reused Sheets: {stats['reused_sheets_count']}")
print(f"Total Components: {stats['total_components']}")
print(f"Total Wires: {stats['total_wires']}")
print(f"\nHierarchy Tree:")
print(sch.hierarchy.visualize_hierarchy(include_stats=True))
Testingο
Test Coverageο
19 comprehensive unit tests covering:
β Hierarchy tree building (3 tests)
β Sheet reuse detection (2 tests)
β Sheet pin validation (3 tests)
β Hierarchy flattening (2 tests)
β Hierarchy statistics (2 tests)
β Hierarchy visualization (2 tests)
β Signal tracing (2 tests)
β Edge cases (3 tests)
All tests passing: pytest tests/unit/test_hierarchy_manager.py -v
Examplesο
Complete examples available in: examples/hierarchy_example.py
Run examples:
python examples/hierarchy_example.py
Implementation Notesο
Design Decisionsο
Tree-Based Structure: Hierarchy represented as tree of
HierarchyNodeobjects for efficient traversal and depth calculation.Lazy Loading: Child schematics loaded on-demand during tree building, reducing memory usage for large projects.
Validation Caching: Sheet pin validation results cached in
_pin_connectionsfor repeated access without re-validation.Path-Based Tracking: Hierarchical paths use KiCADβs UUID-based format (
/root_uuid/child_uuid/) for precise tracking.Flexible Flattening: Flattening creates data representation only (not real schematic), preserving original hierarchy information in
hierarchy_map.
Performance Considerationsο
Tree building: O(n) where n is total number of sheets
Sheet reuse detection: O(n) lookup in
_sheet_instancesdictionaryValidation: O(m Γ p) where m is sheets, p is pins per sheet
Flattening: O(n Γ c) where n is sheets, c is components per sheet
Signal tracing: O(n Γ l) where n is sheets, l is labels per sheet
Integrationο
With ConnectivityAnalyzerο
HierarchyManager complements ConnectivityAnalyzer by providing:
Sheet structure and navigation
Pin validation before connectivity analysis
Flattened view for simplified connectivity tracing
With SheetManagerο
HierarchyManager extends SheetManager with:
Multi-level hierarchy tracking
Reuse detection
Cross-sheet analysis
SheetManager: Basic sheet operations
HierarchyManager: Advanced hierarchy analysis
Limitationsο
File System Dependency: Requires actual schematic files to exist for loading child schematics.
Memory Usage: Loading large hierarchies loads all schematics into memory.
Circular References: Does not detect circular sheet references (A includes B includes A).
Read-Only: Hierarchy analysis is read-only; modifications must be made through
SheetManager.
Future Enhancementsο
Potential improvements (not in scope of #37):
Circular Reference Detection: Detect and report circular sheet dependencies
Hierarchy Editing: Modify hierarchy structure programmatically
Diff/Merge: Compare and merge hierarchical designs
Export Formats: Export hierarchy to other formats (JSON, DOT, etc.)
Incremental Loading: Load hierarchy incrementally for very large designs
Cache Management: Persistent caching of hierarchy analysis results
See Alsoο
SheetManager:
kicad_sch_api/core/managers/sheet.py- Basic sheet operationsConnectivityAnalyzer:
kicad_sch_api/core/connectivity.py- Network connectivityExamples:
examples/hierarchy_example.py- Usage examplesTests:
tests/unit/test_hierarchy_manager.py- Test coverage
Changelogο
v0.4.6 (2025-11-05)
β Implemented
HierarchyManagerclassβ Added 19 comprehensive unit tests
β Integrated with
Schematicclass viasch.hierarchypropertyβ Created usage examples and documentation
β All tests passing
Status: Issue #37 - β Complete
For questions or issues, please refer to the GitHub repository.