Refactor print statements for consistency and clarity across multiple files; remove unnecessary imports and improve code readability in pin_locator.py, routing.py, symbol_creator.py, wire_manager.py, factory.py, ipc_backend.py, kicad_interface.py, resource_definitions.py, test_ipc_backend.py, kicad_process.py, platform_helper.py, test_platform_helper.py. Add French README for KiCAD MCP Server with detailed features, installation instructions, and usage examples.

This commit is contained in:
L'électron rare
2026-03-26 07:58:28 +01:00
parent 564f5ac955
commit a8e4de917f
28 changed files with 1833 additions and 940 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ Board view command implementations for KiCAD interface
import os
import pcbnew
import logging
from typing import Dict, Any, Optional, List, Tuple
from typing import Dict, Any, Optional
from PIL import Image
import io
import base64
+3 -4
View File
@@ -2,7 +2,6 @@
Component-related command implementations for KiCAD interface
"""
import os
import pcbnew
import logging
import math
@@ -1519,11 +1518,11 @@ class ComponentCommands:
# Convert spacing to nm
unit = start_position.get("unit", "mm")
scale = 1000000 if unit == "mm" else 25400000 # mm or inch to nm
spacing_x_nm = int(spacing_x * scale)
spacing_y_nm = int(spacing_y * scale)
int(spacing_x * scale)
int(spacing_y * scale)
# Get layer ID
layer_id = self.board.GetLayerID(layer)
self.board.GetLayerID(layer)
for row in range(rows):
for col in range(columns):
-1
View File
@@ -1,5 +1,4 @@
from skip import Schematic
import os
import uuid
import logging
from pathlib import Path
+1 -2
View File
@@ -1,5 +1,4 @@
from skip import Schematic
import os
import logging
from pathlib import Path
from typing import Optional
@@ -261,7 +260,7 @@ class ConnectionManager:
# Create wire stub using WireManager
wire_success = WireManager.add_wire(schematic_path, pin_loc, stub_end)
if not wire_success:
logger.error(f"Failed to create wire stub for net connection")
logger.error("Failed to create wire stub for net connection")
return False
# Add label at the end of the stub using WireManager
+1 -3
View File
@@ -5,7 +5,7 @@ Design rules command implementations for KiCAD interface
import os
import pcbnew
import logging
from typing import Dict, Any, Optional, List, Tuple
from typing import Dict, Any, Optional, Tuple
import json
logger = logging.getLogger("kicad_interface")
@@ -185,8 +185,6 @@ class DesignRuleCommands:
import subprocess
import json
import tempfile
import platform
import shutil
try:
if not self.board:
+2 -2
View File
@@ -12,7 +12,7 @@ import re
import uuid
import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from typing import List, Optional
logger = logging.getLogger("kicad_interface")
@@ -575,6 +575,6 @@ if __name__ == "__main__":
if block and "LM2596S-12" in block:
print(f" OK: LM2596S-5 includes parent LM2596S-12 ({len(block)} chars)")
else:
print(f" FAIL: extends not resolved")
print(" FAIL: extends not resolved")
print("\nAll tests passed!")
+1 -4
View File
@@ -5,8 +5,7 @@ Export command implementations for KiCAD interface
import os
import pcbnew
import logging
from typing import Dict, Any, Optional, List, Tuple
import base64
from typing import Dict, Any, Optional, List
import subprocess
logger = logging.getLogger("kicad_interface")
@@ -322,8 +321,6 @@ class ExportCommands:
def export_3d(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Export 3D model files using kicad-cli (KiCAD 9.0 compatible)"""
import subprocess
import platform
import shutil
try:
if not self.board:
+17 -17
View File
@@ -107,9 +107,9 @@ class FootprintCreator:
# ---- header ----
lines.append(f'(footprint "{name}"')
lines.append(f' (version {KICAD9_FOOTPRINT_VERSION})')
lines.append(f' (generator "kicad-mcp")')
lines.append(f' (generator_version "9.0")')
lines.append(f' (layer "F.Cu")')
lines.append(' (generator "kicad-mcp")')
lines.append(' (generator_version "9.0")')
lines.append(' (layer "F.Cu")')
if description:
lines.append(f' (descr "{_esc(description)}")')
if tags:
@@ -125,22 +125,22 @@ class FootprintCreator:
lines.append(
f' (property "Reference" "REF**" (at {_fmt(ref_x)} {_fmt(ref_y)} 0)'
)
lines.append(f' (layer "F.SilkS")')
lines.append(' (layer "F.SilkS")')
lines.append(f' (uuid "{_new_uuid()}")')
lines.append(f' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(f' )')
lines.append(' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(' )')
lines.append(
f' (property "Value" "{_esc(name)}" (at {_fmt(val_x)} {_fmt(val_y)} 0)'
)
lines.append(f' (layer "F.Fab")')
lines.append(' (layer "F.Fab")')
lines.append(f' (uuid "{_new_uuid()}")')
lines.append(f' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(f' )')
lines.append(f' (property "Datasheet" "" (at 0 0 0)')
lines.append(f' (layer "F.Fab")')
lines.append(' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(' )')
lines.append(' (property "Datasheet" "" (at 0 0 0)')
lines.append(' (layer "F.Fab")')
lines.append(f' (uuid "{_new_uuid()}")')
lines.append(f' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(f' )')
lines.append(' (effects (font (size 1 1) (thickness 0.15)))')
lines.append(' )')
lines.append("")
# ---- courtyard ----
@@ -483,7 +483,7 @@ def _pad_lines(pad: Dict[str, Any]) -> List[str]:
lines.append(f" (roundrect_rratio {_fmt(rr_ratio)})")
lines.append(f' (uuid "{_new_uuid()}")')
lines.append(f" )")
lines.append(" )")
return lines
@@ -494,13 +494,13 @@ def _rect_lines(rect: Dict[str, Any], layer: str, default_width: float = 0.05) -
y2 = _fmt(rect.get("y2", 1.0))
w = _fmt(rect.get("width", default_width))
return [
f' (fp_rect',
' (fp_rect',
f' (start {x1} {y1})',
f' (end {x2} {y2})',
f' (stroke (width {w}) (type default))',
f' (fill none)',
' (fill none)',
f' (layer "{layer}")',
f' (uuid "{_new_uuid()}")',
f' )',
' )',
"",
]
+2 -3
View File
@@ -16,7 +16,6 @@ import string
import base64
import json
from typing import Optional, Dict, List, Callable
from pathlib import Path
logger = logging.getLogger('kicad_interface')
@@ -260,7 +259,7 @@ def test_jlcpcb_connection(app_id: Optional[str] = None, access_key: Optional[st
try:
client = JLCPCBClient(app_id, access_key, secret_key)
# Test by fetching first page
data = client.fetch_parts_page()
client.fetch_parts_page()
logger.info("JLCPCB API connection test successful")
return True
except Exception as e:
@@ -283,7 +282,7 @@ if __name__ == '__main__':
print(f"✓ Retrieved {len(parts)} parts in first page")
if parts:
print(f"\nExample part:")
print("\nExample part:")
part = parts[0]
print(f" LCSC: {part.get('componentCode')}")
print(f" MFR Part: {part.get('componentModelEn')}")
+1 -1
View File
@@ -501,7 +501,7 @@ if __name__ == '__main__':
# Get stats
stats = manager.get_database_stats()
print(f"\nDatabase Statistics:")
print("\nDatabase Statistics:")
print(f" Total parts: {stats['total_parts']}")
print(f" Basic parts: {stats['basic_parts']}")
print(f" Extended parts: {stats['extended_parts']}")
+1 -1
View File
@@ -234,7 +234,7 @@ if __name__ == '__main__':
print(f"✓ Found {len(resistors)} resistors")
if resistors:
print(f"\nExample resistor:")
print("\nExample resistor:")
r = resistors[0]
print(f" LCSC: C{r.get('lcsc')}")
print(f" MFR: {r.get('mfr')}")
-1
View File
@@ -10,7 +10,6 @@ import re
import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import glob
logger = logging.getLogger("kicad_interface")
+1 -2
View File
@@ -1,4 +1,3 @@
from skip import Schematic
# Symbol class might not be directly importable in the current version
import os
import glob
@@ -75,7 +74,7 @@ class LibraryManager:
# 3. Filtering symbols based on the query
# For now, this is a placeholder implementation
libraries = LibraryManager.list_available_libraries(search_paths)
LibraryManager.list_available_libraries(search_paths)
results = []
print(f"Searched for symbols matching '{query}'. This requires advanced implementation.")
-1
View File
@@ -656,7 +656,6 @@ class SymbolLibraryCommands:
if __name__ == '__main__':
# Test the symbol library manager
import json
logging.basicConfig(level=logging.INFO)
+1 -1
View File
@@ -439,7 +439,7 @@ if __name__ == "__main__":
if r1_pin1 and c1_pin1:
# R1 is not rotated, pins should be at y offset from symbol center
# C1 is rotated 90°, pins should be at x offset from symbol center
print(f"\n Pin offset analysis:")
print("\n Pin offset analysis:")
print(f" R1 (0°): pin 1 y-offset = {r1_pin1[1] - 100}")
print(f" C1 (90°): pin 1 x-offset = {c1_pin1[0] - 150}")
+2 -3
View File
@@ -2,11 +2,10 @@
Routing-related command implementations for KiCAD interface
"""
import os
import pcbnew
import logging
import math
from typing import Dict, Any, Optional, List, Tuple
from typing import Dict, Any, Optional
logger = logging.getLogger("kicad_interface")
@@ -844,7 +843,7 @@ class RoutingCommands:
offset_y = target_pos.y - source_pos.y
# Build mapping from source refs to target refs
ref_mapping = dict(zip(source_refs, target_refs))
dict(zip(source_refs, target_refs))
# Collect all nets connected to source components
source_nets = set()
+18 -18
View File
@@ -332,7 +332,7 @@ class SymbolCreator:
board_str = "yes" if on_board else "no"
lines.append(f' (symbol "{name}"')
lines.append(f' (exclude_from_sim no)')
lines.append(' (exclude_from_sim no)')
lines.append(f' (in_bom {bom_str})')
lines.append(f' (on_board {board_str})')
@@ -351,15 +351,15 @@ class SymbolCreator:
lines.extend(_rect_sym_lines(rect))
for pl in polylines:
lines.extend(_polyline_lines(pl))
lines.append(f' )')
lines.append(' )')
# Sub-symbol _1_1: pins
lines.append(f' (symbol "{name}_1_1"')
for pin in pins:
lines.extend(_pin_lines(pin))
lines.append(f' )')
lines.append(' )')
lines.append(f' )')
lines.append(' )')
return "\n".join(lines)
def _remove_symbol(self, content: str, name: str) -> str:
@@ -397,10 +397,10 @@ def _property_block(
return [
f' (property "{_esc(key)}" "{_esc(value)}"',
f' (at {_fmt(x)} {_fmt(y)} 0)',
f' (effects',
f' (font (size 1.27 1.27))',
' (effects',
' (font (size 1.27 1.27))',
f' ){hide}',
f' )',
' )',
]
@@ -412,12 +412,12 @@ def _rect_sym_lines(rect: Dict[str, Any]) -> List[str]:
w = _fmt(rect.get("width", 0.254))
fill = rect.get("fill", "background")
return [
f' (rectangle',
' (rectangle',
f' (start {x1} {y1})',
f' (end {x2} {y2})',
f' (stroke (width {w}) (type default))',
f' (fill (type {fill}))',
f' )',
' )',
]
@@ -426,16 +426,16 @@ def _polyline_lines(pl: Dict[str, Any]) -> List[str]:
w = _fmt(pl.get("width", 0.254))
fill = pl.get("fill", "none")
lines = [
f' (polyline',
f' (pts',
' (polyline',
' (pts',
]
for pt in pts:
lines.append(f' (xy {_fmt(pt["x"])} {_fmt(pt["y"])})')
lines += [
f' )',
' )',
f' (stroke (width {w}) (type default))',
f' (fill (type {fill}))',
f' )',
' )',
]
return lines
@@ -456,10 +456,10 @@ def _pin_lines(pin: Dict[str, Any]) -> List[str]:
f' (at {x} {y} {angle})',
f' (length {length})',
f' (name "{_esc(pin_name)}"',
f' (effects (font (size 1.27 1.27)))',
f' )',
' (effects (font (size 1.27 1.27)))',
' )',
f' (number "{_esc(pin_number)}"',
f' (effects (font (size 1.27 1.27)))',
f' )',
f' )',
' (effects (font (size 1.27 1.27)))',
' )',
' )',
]
+2 -3
View File
@@ -8,10 +8,9 @@ manipulate the .kicad_sch file directly.
import uuid
import logging
import math
import tempfile
from pathlib import Path
from typing import List, Tuple, Optional, Dict
from typing import List
import sexpdata
from sexpdata import Symbol
@@ -423,7 +422,7 @@ if __name__ == '__main__':
from skip import Schematic
sch = Schematic(str(test_path))
wire_count = len(list(sch.wire)) if hasattr(sch, 'wire') else 0
print(f" ✓ Loaded successfully")
print(" ✓ Loaded successfully")
print(f" ✓ Wire count: {wire_count}")
except Exception as e:
print(f" ✗ Failed: {e}")
-1
View File
@@ -6,7 +6,6 @@ Auto-detects available backends and provides fallback mechanism.
import os
import logging
from typing import Optional
from pathlib import Path
from kicad_api.base import KiCADBackend, APINotAvailableError
+2 -3
View File
@@ -582,7 +582,7 @@ class IPCBoardAPI(BoardAPI):
# Get the pcbnew board instance
# We need to get the actual board file path
project = board.get_project()
board.get_project()
board_path = None
# Try to get the board path from kipy
@@ -1089,7 +1089,7 @@ class IPCBoardAPI(BoardAPI):
"""
try:
from kipy.board_types import Zone, ZoneFillMode, ZoneType
from kipy.geometry import PolyLine, PolyLineNode, Vector2
from kipy.geometry import PolyLine, PolyLineNode
from kipy.util.units import from_mm
from kipy.proto.board.board_types_pb2 import BoardLayer
@@ -1174,7 +1174,6 @@ class IPCBoardAPI(BoardAPI):
def get_zones(self) -> List[Dict[str, Any]]:
"""Get all zones on the board."""
try:
from kipy.util.units import to_mm
board = self._get_board()
zones = board.get_zones()
+1 -1
View File
@@ -152,7 +152,7 @@ if KICAD_BACKEND in ("auto", "ipc"):
ipc_backend = IPCBackend()
if ipc_backend.connect():
USE_IPC_BACKEND = True
logger.info(f"✓ Using IPC backend - real-time UI sync enabled!")
logger.info("✓ Using IPC backend - real-time UI sync enabled!")
logger.info(f" KiCAD version: {ipc_backend.get_version()}")
else:
logger.info("IPC backend available but KiCAD not running with IPC enabled")
+1 -2
View File
@@ -6,8 +6,7 @@ read-only access to project data for LLM context.
"""
import json
import base64
from typing import Dict, Any, List, Optional
from typing import Dict, Any
import logging
logger = logging.getLogger('kicad_interface')
+1 -1
View File
@@ -42,7 +42,7 @@ def test_connection():
print("✓ IPCBackend created")
if backend.connect():
print(f"✓ Connected to KiCAD via IPC")
print("✓ Connected to KiCAD via IPC")
print(f" Version: {backend.get_version()}")
return backend
else:
-1
View File
@@ -3,7 +3,6 @@ KiCAD Process Management Utilities
Detects if KiCAD is running and provides auto-launch functionality.
"""
import os
import subprocess
import logging
import platform
+2 -2
View File
@@ -82,9 +82,9 @@ class PlatformHelper:
# Check system Python dist-packages (modern KiCAD 9+ on Ubuntu/Debian)
# This is where pcbnew.py typically lives on modern systems
candidates.extend([
Path(f"/usr/lib/python3/dist-packages"),
Path("/usr/lib/python3/dist-packages"),
Path(f"/usr/lib/python{py_version}/dist-packages"),
Path(f"/usr/local/lib/python3/dist-packages"),
Path("/usr/local/lib/python3/dist-packages"),
Path(f"/usr/local/lib/python{py_version}/dist-packages"),
])