Files
kicad-mcp-server/python/commands/schematic.py
Eugene Mikhantyev e06082bb44 chore: normalize schematic.py and apply black to create_schematic signature
Bundles two changes for python/commands/schematic.py:
  1. CRLF → LF line-ending normalization (matches the bulk renormalize
     from the previous commit — was held back here because black would
     also need to re-reformat it).
  2. Black reflow of create_schematic()'s parameter list, which exceeded
     the line length. Pre-existing drift, no logic change.

`git show --ignore-all-space HEAD` shows just the 2-line signature diff.
2026-04-18 15:24:02 +01:00

135 lines
4.9 KiB
Python

import logging
import os
import shutil
import uuid
from typing import Any, Optional
from skip import Schematic
logger = logging.getLogger("kicad_interface")
class SchematicManager:
"""Core schematic operations using kicad-skip"""
@staticmethod
def create_schematic(
name: str, metadata: Optional[Any] = None, *, path: Optional[str] = None
) -> Any:
"""Create a new empty schematic from template"""
try:
# Determine template path (use template_with_symbols for component cloning support)
template_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"..",
"templates",
"template_with_symbols.kicad_sch",
)
# Determine output path
base_name = name if name.endswith(".kicad_sch") else f"{name}.kicad_sch"
output_path = os.path.join(path, base_name) if path else base_name
if os.path.exists(template_path):
# Copy template to target location
shutil.copy(template_path, output_path)
# Regenerate UUID to ensure uniqueness for each created schematic
import re
with open(output_path, "r", encoding="utf-8") as f:
content = f.read()
new_uuid = str(uuid.uuid4())
content = re.sub(
r"\(uuid [0-9a-fA-F-]+\)",
f"(uuid {new_uuid})",
content,
count=1, # Only replace first (schematic) UUID
)
with open(output_path, "w", encoding="utf-8", newline="\n") as f:
f.write(content)
logger.info(f"Created schematic from template: {output_path}")
else:
# Fallback: create minimal schematic
logger.warning(f"Template not found at {template_path}, creating minimal schematic")
# Generate unique UUID for this schematic
schematic_uuid = str(uuid.uuid4())
# Write with explicit UTF-8 encoding and Unix line endings for cross-platform compatibility
with open(output_path, "w", encoding="utf-8", newline="\n") as f:
f.write('(kicad_sch (version 20250114) (generator "KiCAD-MCP-Server")\n\n')
f.write(f" (uuid {schematic_uuid})\n\n")
f.write(' (paper "A4")\n\n')
f.write(" (lib_symbols\n )\n\n")
f.write(' (sheet_instances\n (path "/" (page "1"))\n )\n')
f.write(")\n")
# Load the schematic
sch = Schematic(output_path)
logger.info(f"Loaded new schematic: {output_path}")
return sch
except Exception as e:
logger.error(f"Error creating schematic: {e}")
raise
@staticmethod
def load_schematic(file_path: str) -> Optional[Any]:
"""Load an existing schematic"""
if not os.path.exists(file_path):
logger.error(f"Schematic file not found at {file_path}")
return None
try:
sch = Schematic(file_path)
logger.info(f"Loaded schematic from: {file_path}")
return sch
except Exception as e:
logger.error(f"Error loading schematic from {file_path}: {e}")
return None
@staticmethod
def save_schematic(schematic: Any, file_path: str) -> bool:
"""Save a schematic to file"""
try:
# kicad-skip uses write method, not save
schematic.write(file_path)
logger.info(f"Saved schematic to: {file_path}")
return True
except Exception as e:
logger.error(f"Error saving schematic to {file_path}: {e}")
return False
@staticmethod
def get_schematic_metadata(schematic: Any) -> dict[str, Any]:
"""Extract metadata from schematic"""
# kicad-skip doesn't expose a direct metadata object on Schematic.
# We can return basic info like version and generator.
metadata = {
"version": schematic.version,
"generator": schematic.generator,
# Add other relevant properties if needed
}
logger.debug("Extracted schematic metadata")
return metadata
if __name__ == "__main__":
# Example Usage (for testing)
# Create a new schematic
new_sch = SchematicManager.create_schematic("MyTestSchematic")
# Save the schematic
test_file = "test_schematic.kicad_sch"
SchematicManager.save_schematic(new_sch, test_file)
# Load the schematic
loaded_sch = SchematicManager.load_schematic(test_file)
if loaded_sch:
metadata = SchematicManager.get_schematic_metadata(loaded_sch)
print(f"Loaded schematic metadata: {metadata}")
# Clean up test file
if os.path.exists(test_file):
os.remove(test_file)
print(f"Cleaned up {test_file}")