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>
This commit is contained in:
86
test/TestProject.kicad_pcb
Normal file
86
test/TestProject.kicad_pcb
Normal file
@@ -0,0 +1,86 @@
|
||||
(kicad_pcb
|
||||
(version 20241229)
|
||||
(generator "pcbnew")
|
||||
(generator_version "9.0")
|
||||
(general
|
||||
(thickness 1.6)
|
||||
(legacy_teardrops no)
|
||||
)
|
||||
(paper "A4")
|
||||
(title_block
|
||||
(title "TestProject")
|
||||
(date "2025-04-26")
|
||||
)
|
||||
(layers
|
||||
(0 "F.Cu" signal)
|
||||
(2 "B.Cu" signal)
|
||||
(9 "F.Adhes" user "F.Adhesive")
|
||||
(11 "B.Adhes" user "B.Adhesive")
|
||||
(13 "F.Paste" user)
|
||||
(15 "B.Paste" user)
|
||||
(5 "F.SilkS" user "F.Silkscreen")
|
||||
(7 "B.SilkS" user "B.Silkscreen")
|
||||
(1 "F.Mask" user)
|
||||
(3 "B.Mask" user)
|
||||
(17 "Dwgs.User" user "User.Drawings")
|
||||
(19 "Cmts.User" user "User.Comments")
|
||||
(21 "Eco1.User" user "User.Eco1")
|
||||
(23 "Eco2.User" user "User.Eco2")
|
||||
(25 "Edge.Cuts" user)
|
||||
(27 "Margin" user)
|
||||
(31 "F.CrtYd" user "F.Courtyard")
|
||||
(29 "B.CrtYd" user "B.Courtyard")
|
||||
(35 "F.Fab" user)
|
||||
(33 "B.Fab" user)
|
||||
(39 "User.1" user)
|
||||
(41 "User.2" user)
|
||||
(43 "User.3" user)
|
||||
(45 "User.4" user)
|
||||
)
|
||||
(setup
|
||||
(pad_to_mask_clearance 0)
|
||||
(allow_soldermask_bridges_in_footprints no)
|
||||
(tenting front back)
|
||||
(pcbplotparams
|
||||
(layerselection 0x00000000_00000000_55555555_5755f5ff)
|
||||
(plot_on_all_layers_selection 0x00000000_00000000_00000000_00000000)
|
||||
(disableapertmacros no)
|
||||
(usegerberextensions no)
|
||||
(usegerberattributes yes)
|
||||
(usegerberadvancedattributes yes)
|
||||
(creategerberjobfile yes)
|
||||
(dashed_line_dash_ratio 12.000000)
|
||||
(dashed_line_gap_ratio 3.000000)
|
||||
(svgprecision 4)
|
||||
(plotframeref no)
|
||||
(mode 1)
|
||||
(useauxorigin no)
|
||||
(hpglpennumber 1)
|
||||
(hpglpenspeed 20)
|
||||
(hpglpendiameter 15.000000)
|
||||
(pdf_front_fp_property_popups yes)
|
||||
(pdf_back_fp_property_popups yes)
|
||||
(pdf_metadata yes)
|
||||
(pdf_single_document no)
|
||||
(dxfpolygonmode yes)
|
||||
(dxfimperialunits yes)
|
||||
(dxfusepcbnewfont yes)
|
||||
(psnegative no)
|
||||
(psa4output no)
|
||||
(plot_black_and_white yes)
|
||||
(sketchpadsonfab no)
|
||||
(plotpadnumbers no)
|
||||
(hidednponfab no)
|
||||
(sketchdnponfab yes)
|
||||
(crossoutdnponfab yes)
|
||||
(subtractmaskfromsilk no)
|
||||
(outputformat 1)
|
||||
(mirror no)
|
||||
(drillshape 1)
|
||||
(scaleselection 1)
|
||||
(outputdirectory "")
|
||||
)
|
||||
)
|
||||
(net 0 "")
|
||||
(embedded_fonts no)
|
||||
)
|
||||
5
test/TestProject.kicad_pro
Normal file
5
test/TestProject.kicad_pro
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"board": {
|
||||
"filename": "TestProject.kicad_pcb"
|
||||
}
|
||||
}
|
||||
50
test/check_skip.py
Normal file
50
test/check_skip.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple script to check if the skip module is available
|
||||
"""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
print("Python executable:", sys.executable)
|
||||
print("Python version:", sys.version)
|
||||
|
||||
try:
|
||||
print("Attempting to import skip module...")
|
||||
import skip
|
||||
print("Successfully imported skip module!")
|
||||
print("Skip module version:", getattr(skip, "__version__", "Unknown"))
|
||||
print("Skip module path:", skip.__file__)
|
||||
|
||||
# Check if Schematic class is available
|
||||
print("\nChecking for Schematic class...")
|
||||
if hasattr(skip, "Schematic"):
|
||||
print("Schematic class is available!")
|
||||
|
||||
# Create a schematic object
|
||||
print("Creating schematic object...")
|
||||
sch = skip.Schematic()
|
||||
print("Successfully created schematic object!")
|
||||
|
||||
# Check for methods and attributes we use
|
||||
print("\nChecking schematic methods/attributes:")
|
||||
print("- add_symbol method:", hasattr(sch, "add_symbol"))
|
||||
print("- add_wire method:", hasattr(sch, "add_wire"))
|
||||
print("- save method:", hasattr(sch, "save"))
|
||||
print("- version attribute:", hasattr(sch, "version"))
|
||||
|
||||
else:
|
||||
print("ERROR: Schematic class is NOT available in the skip module!")
|
||||
|
||||
# List all available classes/functions in the skip module
|
||||
print("\nAvailable members in skip module:")
|
||||
for name in dir(skip):
|
||||
if not name.startswith("_"): # Skip private/internal items
|
||||
print(f"- {name}")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"ERROR: Failed to import skip module: {e}")
|
||||
traceback.print_exc()
|
||||
except Exception as e:
|
||||
print(f"ERROR: An unexpected error occurred: {e}")
|
||||
traceback.print_exc()
|
||||
121
test/example_skip_usage.py
Normal file
121
test/example_skip_usage.py
Normal file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Example script to inspect and document kicad-skip library capabilities
|
||||
"""
|
||||
|
||||
import sys
|
||||
import inspect
|
||||
import os
|
||||
import traceback
|
||||
|
||||
def main():
|
||||
"""Examine the kicad-skip library functionality"""
|
||||
print("=== Examining kicad-skip library ===")
|
||||
|
||||
try:
|
||||
# Import the module
|
||||
print("Importing skip module...")
|
||||
import skip
|
||||
print(f"Skip module path: {skip.__file__}")
|
||||
|
||||
# Display module contents
|
||||
print("\nSkip module contents:")
|
||||
for item_name in dir(skip):
|
||||
if not item_name.startswith('_'):
|
||||
try:
|
||||
item = getattr(skip, item_name)
|
||||
if inspect.isclass(item):
|
||||
print(f" Class: {item_name}")
|
||||
# List methods of the class
|
||||
for method_name in dir(item):
|
||||
if not method_name.startswith('_'):
|
||||
method = getattr(item, method_name)
|
||||
if inspect.ismethod(method) or inspect.isfunction(method):
|
||||
print(f" - Method: {method_name}")
|
||||
elif inspect.isfunction(item):
|
||||
print(f" Function: {item_name}")
|
||||
else:
|
||||
print(f" Other: {item_name} (type: {type(item).__name__})")
|
||||
except Exception as e:
|
||||
print(f" Error examining {item_name}: {e}")
|
||||
|
||||
# Test Schematic class specifically
|
||||
print("\nExamining Schematic class:")
|
||||
if hasattr(skip, 'Schematic'):
|
||||
schematic_class = skip.Schematic
|
||||
print(f"Schematic class: {schematic_class}")
|
||||
|
||||
# Check initialization parameters
|
||||
try:
|
||||
sig = inspect.signature(schematic_class.__init__)
|
||||
print(f"Schematic.__init__ signature: {sig}")
|
||||
|
||||
# List required parameters
|
||||
required_params = [
|
||||
name for name, param in sig.parameters.items()
|
||||
if param.default == inspect.Parameter.empty and name != 'self'
|
||||
]
|
||||
print(f"Required parameters: {required_params}")
|
||||
|
||||
# Display initialization docstring
|
||||
print(f"__init__ docstring: {schematic_class.__init__.__doc__}")
|
||||
except Exception as e:
|
||||
print(f"Error examining Schematic.__init__: {e}")
|
||||
|
||||
# Create a simple test file
|
||||
test_dir = os.path.dirname(__file__)
|
||||
test_file = os.path.join(test_dir, 'test_example.kicad_sch')
|
||||
|
||||
with open(test_file, 'w') as f:
|
||||
f.write("(kicad_sch (version 20230121) (generator \"Test Example\"))\n")
|
||||
|
||||
# Try loading the test file
|
||||
print(f"\nLoading test file {test_file}")
|
||||
try:
|
||||
sch = skip.Schematic(test_file)
|
||||
print("Successfully created Schematic object")
|
||||
|
||||
# Examine the object's attributes and methods
|
||||
print("\nSchematic object attributes:")
|
||||
for attr_name in dir(sch):
|
||||
if not attr_name.startswith('_'):
|
||||
try:
|
||||
attr = getattr(sch, attr_name)
|
||||
if callable(attr):
|
||||
print(f" Method: {attr_name}")
|
||||
else:
|
||||
print(f" Attribute: {attr_name} = {attr}")
|
||||
except Exception as e:
|
||||
print(f" Error examining {attr_name}: {e}")
|
||||
|
||||
# Check for io-related methods
|
||||
print("\nLooking for IO-related methods:")
|
||||
for method_name in ['save', 'write', 'to_file', 'export', 'dump']:
|
||||
print(f" Has '{method_name}' method: {hasattr(sch, method_name)}")
|
||||
|
||||
# Examine the representation of the object
|
||||
print(f"\nStr representation: {str(sch)}")
|
||||
print(f"Repr representation: {repr(sch)}")
|
||||
|
||||
# Clean up
|
||||
os.remove(test_file)
|
||||
except Exception as e:
|
||||
print(f"Error testing Schematic: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
# Clean up even on error
|
||||
if os.path.exists(test_file):
|
||||
os.remove(test_file)
|
||||
else:
|
||||
print("Schematic class not found in skip module")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"Failed to import skip module: {e}")
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
print("\n=== Examination completed ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
93
test/manual_test_schematic.py
Normal file
93
test/manual_test_schematic.py
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Manual test script for the schematic functionality
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
# Import our schematic modules
|
||||
from python.commands.schematic import SchematicManager
|
||||
from python.commands.component_schematic import ComponentManager
|
||||
from python.commands.connection_schematic import ConnectionManager
|
||||
|
||||
def main():
|
||||
"""Run a basic test of schematic functionality"""
|
||||
print("=== Starting manual schematic test ===")
|
||||
|
||||
# Set up test output directory
|
||||
test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output')
|
||||
if not os.path.exists(test_dir):
|
||||
os.makedirs(test_dir)
|
||||
|
||||
# 1. Create a new schematic
|
||||
schematic_name = "TestCircuitManual"
|
||||
schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch")
|
||||
print(f"Creating schematic: {schematic_name}")
|
||||
|
||||
schematic = SchematicManager.create_schematic(schematic_name)
|
||||
|
||||
# 2. Add components to the schematic
|
||||
print("Adding components to schematic...")
|
||||
|
||||
# Add resistor R1
|
||||
r1_def = {
|
||||
"type": "R",
|
||||
"reference": "R1",
|
||||
"value": "10k",
|
||||
"library": "Device",
|
||||
"x": 100,
|
||||
"y": 100
|
||||
}
|
||||
r1 = ComponentManager.add_component(schematic, r1_def)
|
||||
|
||||
# Add resistor R2
|
||||
r2_def = {
|
||||
"type": "R",
|
||||
"reference": "R2",
|
||||
"value": "4.7k",
|
||||
"library": "Device",
|
||||
"x": 100,
|
||||
"y": 200
|
||||
}
|
||||
r2 = ComponentManager.add_component(schematic, r2_def)
|
||||
|
||||
# Add capacitor C1
|
||||
c1_def = {
|
||||
"type": "C",
|
||||
"reference": "C1",
|
||||
"value": "0.1uF",
|
||||
"library": "Device",
|
||||
"x": 200,
|
||||
"y": 150
|
||||
}
|
||||
c1 = ComponentManager.add_component(schematic, c1_def)
|
||||
|
||||
# 3. Add wires to connect components
|
||||
print("Adding wires to connect components...")
|
||||
|
||||
# Connect R1 to R2
|
||||
wire1 = ConnectionManager.add_wire(schematic, [150, 100], [150, 200])
|
||||
|
||||
# Connect R2 to C1
|
||||
wire2 = ConnectionManager.add_wire(schematic, [150, 200], [200, 200])
|
||||
|
||||
# Connect C1 to R1
|
||||
wire3 = ConnectionManager.add_wire(schematic, [200, 100], [150, 100])
|
||||
|
||||
# 4. Save the schematic
|
||||
print(f"Saving schematic to: {schematic_path}")
|
||||
success = SchematicManager.save_schematic(schematic, schematic_path)
|
||||
|
||||
if success:
|
||||
print(f"Successfully saved schematic to: {schematic_path}")
|
||||
else:
|
||||
print("Failed to save schematic")
|
||||
|
||||
print("=== Manual schematic test completed ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
87
test/skip_test.py
Normal file
87
test/skip_test.py
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple test script for the kicad-skip library functionality
|
||||
This test doesn't depend on KiCAD's Python modules like pcbnew.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
def main():
|
||||
"""Test basic kicad-skip functionality"""
|
||||
print("=== Testing kicad-skip schematic functionality ===")
|
||||
|
||||
# Set up test output directory
|
||||
test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output')
|
||||
if not os.path.exists(test_dir):
|
||||
os.makedirs(test_dir)
|
||||
|
||||
print("Test directory:", test_dir)
|
||||
|
||||
try:
|
||||
# Import skip module
|
||||
print("Importing skip module...")
|
||||
from skip import Schematic
|
||||
print("Successfully imported skip module")
|
||||
|
||||
# Create a new schematic
|
||||
print("Creating new schematic...")
|
||||
sch = Schematic()
|
||||
sch.version = "20230121"
|
||||
sch.generator = "KiCAD-MCP-Server-Test"
|
||||
print("Created schematic object with version:", sch.version)
|
||||
|
||||
# Add resistor component
|
||||
print("Adding resistor component...")
|
||||
resistor = sch.add_symbol(
|
||||
lib="Device",
|
||||
name="R",
|
||||
reference="R1",
|
||||
at=[100, 100],
|
||||
unit=1
|
||||
)
|
||||
resistor.property.Value.value = "10k"
|
||||
print("Added resistor:", resistor.reference, resistor.property.Value.value)
|
||||
|
||||
# Add capacitor component
|
||||
print("Adding capacitor component...")
|
||||
capacitor = sch.add_symbol(
|
||||
lib="Device",
|
||||
name="C",
|
||||
reference="C1",
|
||||
at=[200, 100],
|
||||
unit=1
|
||||
)
|
||||
capacitor.property.Value.value = "0.1uF"
|
||||
print("Added capacitor:", capacitor.reference, capacitor.property.Value.value)
|
||||
|
||||
# Add wire connection
|
||||
print("Adding wire connection...")
|
||||
wire = sch.add_wire(start=[100, 150], end=[200, 150])
|
||||
print("Added wire from", wire.start, "to", wire.end)
|
||||
|
||||
# Save the schematic
|
||||
schematic_path = os.path.join(test_dir, "skip_test.kicad_sch")
|
||||
print(f"Saving schematic to: {schematic_path}")
|
||||
sch.save(schematic_path)
|
||||
print(f"Schematic saved to: {schematic_path}")
|
||||
|
||||
# Verify the file exists
|
||||
if os.path.exists(schematic_path):
|
||||
print(f"SUCCESS: Schematic file created at: {schematic_path}")
|
||||
print(f"File size: {os.path.getsize(schematic_path)} bytes")
|
||||
else:
|
||||
print(f"ERROR: Failed to create schematic file at: {schematic_path}")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"ERROR: Failed to import required modules: {e}")
|
||||
traceback.print_exc()
|
||||
except Exception as e:
|
||||
print(f"ERROR: An unexpected error occurred: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
print("=== Test completed ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
230
test/test_schematic.js
Normal file
230
test/test_schematic.js
Normal file
@@ -0,0 +1,230 @@
|
||||
import { spawn } from 'child_process';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Get current file directory (ESM equivalent of __dirname)
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
/**
|
||||
* Test script for the schematic generation functionality
|
||||
*
|
||||
* This script tests the KiCAD MCP server's schematic generation capabilities by:
|
||||
* 1. Creating a new schematic
|
||||
* 2. Adding components (resistors, capacitors)
|
||||
* 3. Adding connections between them
|
||||
* 4. Exporting the schematic to PDF
|
||||
*/
|
||||
|
||||
// Directory for test outputs
|
||||
const TEST_OUTPUT_DIR = path.join(__dirname, 'schematic_test_output');
|
||||
if (!fs.existsSync(TEST_OUTPUT_DIR)) {
|
||||
fs.mkdirSync(TEST_OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// Function to send a command to the KiCAD MCP server
|
||||
function sendCommand(serverProcess, command, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Create request object
|
||||
const request = {
|
||||
command,
|
||||
params
|
||||
};
|
||||
|
||||
// Convert to JSON and add newline
|
||||
const requestStr = JSON.stringify(request) + '\n';
|
||||
|
||||
// Write to stdin of server process
|
||||
console.log(`Sending request to server: ${requestStr}`);
|
||||
serverProcess.stdin.write(requestStr);
|
||||
|
||||
// Set up response handler
|
||||
let responseData = '';
|
||||
const responseHandler = (data) => {
|
||||
const chunk = data.toString();
|
||||
console.log(`Received data: ${chunk}`);
|
||||
responseData += chunk;
|
||||
try {
|
||||
// Try to parse as JSON
|
||||
const response = JSON.parse(responseData);
|
||||
// Got a complete response
|
||||
console.log(`Parsed complete response: ${JSON.stringify(response)}`);
|
||||
serverProcess.stdout.removeListener('data', responseHandler);
|
||||
resolve(response);
|
||||
} catch (e) {
|
||||
// Not complete JSON yet, keep collecting
|
||||
console.log(`JSON parsing failed, continuing to collect data: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Set a timeout to prevent hanging indefinitely
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.log("Command timeout after 10 seconds");
|
||||
serverProcess.stdout.removeListener('data', responseHandler);
|
||||
resolve({
|
||||
success: false,
|
||||
message: "Timeout waiting for response from server"
|
||||
});
|
||||
}, 10000); // 10 second timeout
|
||||
|
||||
// Listen for response
|
||||
serverProcess.stdout.on('data', responseHandler);
|
||||
|
||||
// Handle errors
|
||||
serverProcess.stderr.on('data', (data) => {
|
||||
console.error(`Server stderr: ${data.toString()}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function runTest() {
|
||||
console.log('\n=== TESTING SCHEMATIC GENERATION ===\n');
|
||||
|
||||
// Start the KiCAD MCP server
|
||||
console.log('Starting KiCAD MCP server...');
|
||||
// Use shell: true to ensure proper command execution in Windows
|
||||
const serverProcess = spawn('node', ['dist/kicad-server.js'], {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
// Log server startup messages
|
||||
serverProcess.stderr.on('data', (data) => {
|
||||
console.log(`Server startup: ${data.toString()}`);
|
||||
});
|
||||
|
||||
// Give server time to start
|
||||
console.log('Waiting for server to start...');
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
console.log('Server should be ready now');
|
||||
|
||||
try {
|
||||
// 1. Create a new schematic
|
||||
const schematicName = 'TestCircuit';
|
||||
const schematicPath = path.join(TEST_OUTPUT_DIR, `${schematicName}.kicad_sch`);
|
||||
console.log(`Creating schematic: ${schematicName}...`);
|
||||
|
||||
const createResult = await sendCommand(serverProcess, 'create_schematic', {
|
||||
projectName: schematicName,
|
||||
path: TEST_OUTPUT_DIR,
|
||||
metadata: {
|
||||
description: 'Test circuit schematic',
|
||||
author: 'KiCAD MCP Test'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Create schematic result:', createResult);
|
||||
|
||||
if (!createResult.success) {
|
||||
throw new Error(`Failed to create schematic: ${createResult.message}`);
|
||||
}
|
||||
|
||||
// 2. Add components: resistors, capacitor, and power/ground connections
|
||||
console.log('Adding components to schematic...');
|
||||
|
||||
// Add resistor R1
|
||||
const addR1Result = await sendCommand(serverProcess, 'add_schematic_component', {
|
||||
schematicPath: schematicPath,
|
||||
component: {
|
||||
type: 'R',
|
||||
reference: 'R1',
|
||||
value: '10k',
|
||||
library: 'Device',
|
||||
x: 100,
|
||||
y: 100
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Add R1 result:', addR1Result);
|
||||
|
||||
// Add resistor R2
|
||||
const addR2Result = await sendCommand(serverProcess, 'add_schematic_component', {
|
||||
schematicPath: schematicPath,
|
||||
component: {
|
||||
type: 'R',
|
||||
reference: 'R2',
|
||||
value: '4.7k',
|
||||
library: 'Device',
|
||||
x: 100,
|
||||
y: 200
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Add R2 result:', addR2Result);
|
||||
|
||||
// Add capacitor C1
|
||||
const addC1Result = await sendCommand(serverProcess, 'add_schematic_component', {
|
||||
schematicPath: schematicPath,
|
||||
component: {
|
||||
type: 'C',
|
||||
reference: 'C1',
|
||||
value: '0.1uF',
|
||||
library: 'Device',
|
||||
x: 200,
|
||||
y: 150
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Add C1 result:', addC1Result);
|
||||
|
||||
// 3. Add wires to connect components
|
||||
console.log('Adding wires to connect components...');
|
||||
|
||||
// Connect R1 to R2
|
||||
const addWire1Result = await sendCommand(serverProcess, 'add_schematic_wire', {
|
||||
schematicPath: schematicPath,
|
||||
startPoint: [150, 100],
|
||||
endPoint: [150, 200]
|
||||
});
|
||||
|
||||
console.log('Add wire 1 result:', addWire1Result);
|
||||
|
||||
// Connect R2 to C1
|
||||
const addWire2Result = await sendCommand(serverProcess, 'add_schematic_wire', {
|
||||
schematicPath: schematicPath,
|
||||
startPoint: [150, 200],
|
||||
endPoint: [200, 200]
|
||||
});
|
||||
|
||||
console.log('Add wire 2 result:', addWire2Result);
|
||||
|
||||
// Connect C1 to R1
|
||||
const addWire3Result = await sendCommand(serverProcess, 'add_schematic_wire', {
|
||||
schematicPath: schematicPath,
|
||||
startPoint: [200, 100],
|
||||
endPoint: [150, 100]
|
||||
});
|
||||
|
||||
console.log('Add wire 3 result:', addWire3Result);
|
||||
|
||||
// 4. Export to PDF
|
||||
console.log('Exporting schematic to PDF...');
|
||||
const pdfPath = path.join(TEST_OUTPUT_DIR, `${schematicName}.pdf`);
|
||||
|
||||
const exportResult = await sendCommand(serverProcess, 'export_schematic_pdf', {
|
||||
schematicPath: schematicPath,
|
||||
outputPath: pdfPath
|
||||
});
|
||||
|
||||
console.log('Export PDF result:', exportResult);
|
||||
|
||||
if (exportResult.success) {
|
||||
console.log(`PDF successfully created at: ${pdfPath}`);
|
||||
} else {
|
||||
console.log(`Failed to create PDF: ${exportResult.message}`);
|
||||
}
|
||||
|
||||
console.log('\n=== SCHEMATIC GENERATION TEST COMPLETED ===\n');
|
||||
console.log(`Schematic file: ${schematicPath}`);
|
||||
console.log(`PDF file: ${pdfPath}`);
|
||||
} catch (error) {
|
||||
console.error('Test error:', error);
|
||||
} finally {
|
||||
// Kill the server process
|
||||
serverProcess.kill();
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test
|
||||
runTest().catch(console.error);
|
||||
111
test/test_schematic_debug.py
Normal file
111
test/test_schematic_debug.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Debug test script for the schematic manager implementation
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
def main():
|
||||
"""Test the SchematicManager functions with detailed debug output"""
|
||||
print("=== DEBUGGING SchematicManager functionality ===")
|
||||
|
||||
# Set up test output directory
|
||||
test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output')
|
||||
if not os.path.exists(test_dir):
|
||||
os.makedirs(test_dir)
|
||||
|
||||
print("Test directory:", test_dir)
|
||||
|
||||
try:
|
||||
# Import directly from skip for comparison
|
||||
print("Importing skip module...")
|
||||
from skip import Schematic
|
||||
print("Successfully imported skip module")
|
||||
|
||||
# Create a template file directly
|
||||
template_path = os.path.join(test_dir, "debug_template.kicad_sch")
|
||||
print(f"Creating template file at: {template_path}")
|
||||
with open(template_path, 'w') as f:
|
||||
f.write("(kicad_sch (version 20230121) (generator \"KiCAD-MCP-Server-Debug\"))\n")
|
||||
|
||||
print(f"Template file created, size: {os.path.getsize(template_path)} bytes")
|
||||
|
||||
# Load the template with skip directly
|
||||
print("Loading template with skip.Schematic...")
|
||||
try:
|
||||
sch = Schematic(template_path)
|
||||
print("Successfully loaded template")
|
||||
|
||||
# Save directly
|
||||
output_path = os.path.join(test_dir, "direct_save.kicad_sch")
|
||||
print(f"Saving with skip.Schematic.save() to: {output_path}")
|
||||
sch.save(output_path)
|
||||
|
||||
if os.path.exists(output_path):
|
||||
print(f"Direct save successful, file size: {os.path.getsize(output_path)} bytes")
|
||||
else:
|
||||
print("Direct save failed, no file created")
|
||||
except Exception as e:
|
||||
print(f"Error using skip directly: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
print("\n--- Now testing SchematicManager ---\n")
|
||||
|
||||
# Import our SchematicManager
|
||||
print("Importing SchematicManager...")
|
||||
from python.commands.schematic import SchematicManager
|
||||
print("Successfully imported SchematicManager")
|
||||
|
||||
# Create a new schematic
|
||||
print("\nCreating new schematic with SchematicManager...")
|
||||
schematic_name = "TestDebugManager"
|
||||
metadata = {
|
||||
"description": "Debug test schematic",
|
||||
"author": "Debug script"
|
||||
}
|
||||
|
||||
try:
|
||||
sch = SchematicManager.create_schematic(schematic_name, metadata)
|
||||
print("Successfully created schematic object")
|
||||
|
||||
# Print schematic properties
|
||||
print("Schematic properties:")
|
||||
print(f" Version: {sch.version}")
|
||||
print(f" Generator: {sch.generator}")
|
||||
|
||||
# Save the schematic
|
||||
schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch")
|
||||
print(f"\nSaving schematic to: {schematic_path}")
|
||||
|
||||
try:
|
||||
success = SchematicManager.save_schematic(sch, schematic_path)
|
||||
|
||||
if success:
|
||||
print(f"Successfully saved schematic to: {schematic_path}")
|
||||
print(f"File size: {os.path.getsize(schematic_path)} bytes")
|
||||
else:
|
||||
print("SchematicManager.save_schematic returned False")
|
||||
except Exception as e:
|
||||
print(f"Error in save_schematic: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in create_schematic: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
except ImportError as e:
|
||||
print(f"ERROR: Failed to import required modules: {e}")
|
||||
traceback.print_exc()
|
||||
except Exception as e:
|
||||
print(f"ERROR: An unexpected error occurred: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
print("\n=== Debug test completed ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
82
test/test_schematic_manager.py
Normal file
82
test/test_schematic_manager.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for the schematic manager implementation using KiCAD python
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
# Add the parent directory to the module search path
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
def main():
|
||||
"""Test the SchematicManager functions"""
|
||||
print("=== Testing SchematicManager functionality ===")
|
||||
|
||||
try:
|
||||
# Set up test output directory
|
||||
test_dir = os.path.join(os.path.dirname(__file__), 'schematic_test_output')
|
||||
if not os.path.exists(test_dir):
|
||||
os.makedirs(test_dir)
|
||||
|
||||
print("Test directory:", test_dir)
|
||||
|
||||
# Import our SchematicManager
|
||||
print("Importing SchematicManager...")
|
||||
from python.commands.schematic import SchematicManager
|
||||
print("Successfully imported SchematicManager")
|
||||
|
||||
# Create a new schematic
|
||||
print("\nCreating new schematic...")
|
||||
schematic_name = "TestSchemManager"
|
||||
metadata = {
|
||||
"description": "Test schematic",
|
||||
"author": "Test script"
|
||||
}
|
||||
sch = SchematicManager.create_schematic(schematic_name, metadata)
|
||||
print("Successfully created schematic object")
|
||||
|
||||
# Save the schematic
|
||||
schematic_path = os.path.join(test_dir, f"{schematic_name}.kicad_sch")
|
||||
print(f"\nSaving schematic to: {schematic_path}")
|
||||
success = SchematicManager.save_schematic(sch, schematic_path)
|
||||
|
||||
if success:
|
||||
print(f"Successfully saved schematic to: {schematic_path}")
|
||||
else:
|
||||
print("Failed to save schematic")
|
||||
return
|
||||
|
||||
# Load the schematic
|
||||
print("\nLoading schematic from file...")
|
||||
loaded_sch = SchematicManager.load_schematic(schematic_path)
|
||||
|
||||
if loaded_sch:
|
||||
print("Successfully loaded schematic")
|
||||
|
||||
# Get metadata
|
||||
print("\nGetting schematic metadata...")
|
||||
metadata = SchematicManager.get_schematic_metadata(loaded_sch)
|
||||
print(f"Metadata: {metadata}")
|
||||
else:
|
||||
print("Failed to load schematic")
|
||||
|
||||
# Verify the file exists
|
||||
if os.path.exists(schematic_path):
|
||||
print(f"\nSCHEMATIC TEST SUCCESSFUL: File created at: {schematic_path}")
|
||||
print(f"File size: {os.path.getsize(schematic_path)} bytes")
|
||||
else:
|
||||
print(f"\nERROR: File not found at: {schematic_path}")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"ERROR: Failed to import required modules: {e}")
|
||||
traceback.print_exc()
|
||||
except Exception as e:
|
||||
print(f"ERROR: An unexpected error occurred: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
print("\n=== Test completed ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user