Files
kicad-mcp-server/python/kicad_api/ipc_backend.py
KiCAD MCP Bot e4c7119c51 feat: Week 1 complete - Linux support + IPC API prep
🎉 Major v2.0 rebuild kickoff - Week 1 accomplished!

## Highlights

### Cross-Platform Support 🌍
-  Linux primary platform (Ubuntu/Debian tested)
-  Windows fully supported
-  macOS experimental support
-  Platform-agnostic path handling (XDG spec)
-  Auto-detection of KiCAD installation

### Infrastructure 🏗️
-  GitHub Actions CI/CD pipeline
-  Pytest framework with 20+ tests
-  Pre-commit hooks (Black, MyPy, ESLint)
-  Automated Linux installation script
-  Enhanced npm scripts

### IPC API Migration Prep 🚀
-  Comprehensive migration plan (30 pages)
-  Backend abstraction layer (800+ lines)
-  Factory pattern with auto-detection
-  SWIG backward compatibility wrapper
-  IPC backend skeleton ready

### Documentation 📚
-  Updated README (Linux installation)
-  CONTRIBUTING.md guide
-  Linux compatibility audit
-  IPC API migration plan
-  Session summaries
-  Platform-specific config templates

## Files Changed

- 27 files created
- ~3,000 lines of code/docs
- 8 comprehensive documentation pages
- 20+ unit tests
- 5 abstraction layer modules

## Next Steps

- Week 2: IPC API migration (project.py → component.py → routing.py)
- Migrate from deprecated SWIG to official IPC API
- JLCPCB/Digikey integration prep

🤖 Generated with Claude Code
https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 20:48:00 -04:00

196 lines
6.4 KiB
Python

"""
IPC API Backend (KiCAD 9.0+)
Uses the official kicad-python library for inter-process communication
with a running KiCAD instance.
Note: Requires KiCAD to be running with IPC server enabled:
Preferences > Plugins > Enable IPC API Server
"""
import logging
from pathlib import Path
from typing import Optional, Dict, Any, List
from kicad_api.base import (
KiCADBackend,
BoardAPI,
ConnectionError,
APINotAvailableError
)
logger = logging.getLogger(__name__)
class IPCBackend(KiCADBackend):
"""
KiCAD IPC API backend
Communicates with KiCAD via Protocol Buffers over UNIX sockets.
Requires KiCAD 9.0+ to be running with IPC enabled.
"""
def __init__(self):
self.kicad = None
self._connected = False
def connect(self) -> bool:
"""
Connect to running KiCAD instance via IPC
Returns:
True if connection successful
Raises:
ConnectionError: If connection fails
"""
try:
# Import here to allow module to load even without kicad-python
from kicad import KiCad
logger.info("Connecting to KiCAD via IPC...")
self.kicad = KiCad()
# Verify connection with version check
version = self.get_version()
logger.info(f"✓ Connected to KiCAD {version} via IPC")
self._connected = True
return True
except ImportError as e:
logger.error("kicad-python library not found")
raise APINotAvailableError(
"IPC backend requires kicad-python. "
"Install with: pip install kicad-python"
) from e
except Exception as e:
logger.error(f"Failed to connect via IPC: {e}")
logger.info(
"Ensure KiCAD is running with IPC enabled: "
"Preferences > Plugins > Enable IPC API Server"
)
raise ConnectionError(f"IPC connection failed: {e}") from e
def disconnect(self) -> None:
"""Disconnect from KiCAD"""
if self.kicad:
# kicad-python handles cleanup automatically
self.kicad = None
self._connected = False
logger.info("Disconnected from KiCAD IPC")
def is_connected(self) -> bool:
"""Check if connected"""
return self._connected and self.kicad is not None
def get_version(self) -> str:
"""Get KiCAD version"""
if not self.kicad:
raise ConnectionError("Not connected to KiCAD")
try:
# Use kicad-python's version checking
version_info = self.kicad.check_version()
return str(version_info)
except Exception as e:
logger.warning(f"Could not get version: {e}")
return "unknown"
# Project Operations
def create_project(self, path: Path, name: str) -> Dict[str, Any]:
"""
Create a new KiCAD project
TODO: Implement with IPC API
"""
if not self.is_connected():
raise ConnectionError("Not connected to KiCAD")
logger.warning("create_project not yet implemented for IPC backend")
raise NotImplementedError(
"Project creation via IPC API is not yet implemented. "
"This will be added in Week 2-3 migration."
)
def open_project(self, path: Path) -> Dict[str, Any]:
"""Open existing project"""
if not self.is_connected():
raise ConnectionError("Not connected to KiCAD")
logger.warning("open_project not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def save_project(self, path: Optional[Path] = None) -> Dict[str, Any]:
"""Save current project"""
if not self.is_connected():
raise ConnectionError("Not connected to KiCAD")
logger.warning("save_project not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def close_project(self) -> None:
"""Close current project"""
if not self.is_connected():
raise ConnectionError("Not connected to KiCAD")
logger.warning("close_project not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
# Board Operations
def get_board(self) -> BoardAPI:
"""Get board API"""
if not self.is_connected():
raise ConnectionError("Not connected to KiCAD")
return IPCBoardAPI(self.kicad)
class IPCBoardAPI(BoardAPI):
"""Board API implementation for IPC backend"""
def __init__(self, kicad_instance):
self.kicad = kicad_instance
self._board = None
def _get_board(self):
"""Lazy-load board instance"""
if self._board is None:
self._board = self.kicad.get_board()
return self._board
def set_size(self, width: float, height: float, unit: str = "mm") -> bool:
"""Set board size"""
logger.warning("set_size not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def get_size(self) -> Dict[str, float]:
"""Get board size"""
logger.warning("get_size not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def add_layer(self, layer_name: str, layer_type: str) -> bool:
"""Add layer"""
logger.warning("add_layer not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def list_components(self) -> List[Dict[str, Any]]:
"""List components"""
logger.warning("list_components not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
def place_component(
self,
reference: str,
footprint: str,
x: float,
y: float,
rotation: float = 0,
layer: str = "F.Cu"
) -> bool:
"""Place component"""
logger.warning("place_component not yet implemented for IPC backend")
raise NotImplementedError("Coming in Week 2-3 migration")
# Note: Full implementation will be completed during Week 2-3 migration
# This is a skeleton to establish the pattern