Phase 1 critical fixes addressing three high-priority issues: Issue #36 - Windows IPC backend crash (os.getuid not available): - Add platform detection to skip Unix-specific socket paths on Windows - Use hasattr check before calling os.getuid() - Windows now uses auto-detect fallback (named pipes) - Maintains full Unix socket support on Linux/macOS Issue #37 - Windows schematic file creation broken: - Generate unique UUIDs instead of invalid all-zeros UUID - Add explicit UTF-8 encoding for cross-platform compatibility - Force Unix line endings (LF) to prevent Windows CRLF issues - Update template file with valid placeholder UUID - Fix hardcoded /tmp/ paths in wire_manager.py and pin_locator.py Issue #35 - JLCPCB download limited to 100 parts: - Change batch_size from 1000 to 100 to match tscircuit API limit - Remove premature loop termination when batch < batch_size - Add documentation explaining API limitation - Expected result: Full ~2.5M part catalog download (40-60 minutes) All changes maintain backward compatibility and include detailed comments. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -143,14 +143,17 @@ class JLCSearchClient:
|
|||||||
def download_all_components(
|
def download_all_components(
|
||||||
self,
|
self,
|
||||||
callback: Optional[Callable[[int, str], None]] = None,
|
callback: Optional[Callable[[int, str], None]] = None,
|
||||||
batch_size: int = 1000
|
batch_size: int = 100
|
||||||
) -> List[Dict]:
|
) -> List[Dict]:
|
||||||
"""
|
"""
|
||||||
Download all components from jlcsearch database
|
Download all components from jlcsearch database
|
||||||
|
|
||||||
|
Note: tscircuit API has a hard-coded 100 result limit per request.
|
||||||
|
Full catalog download requires ~25,000 paginated requests (~40-60 minutes).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
callback: Optional progress callback function(parts_count, status_msg)
|
callback: Optional progress callback function(parts_count, status_msg)
|
||||||
batch_size: Number of parts per batch
|
batch_size: Number of parts per batch (max 100 due to API limit)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of all parts
|
List of all parts
|
||||||
@@ -168,7 +171,8 @@ class JLCSearchClient:
|
|||||||
offset=offset
|
offset=offset
|
||||||
)
|
)
|
||||||
|
|
||||||
if not batch:
|
# Stop if no results returned (end of catalog)
|
||||||
|
if not batch or len(batch) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
all_parts.extend(batch)
|
all_parts.extend(batch)
|
||||||
@@ -179,9 +183,8 @@ class JLCSearchClient:
|
|||||||
else:
|
else:
|
||||||
logger.info(f"Downloaded {len(all_parts)} parts so far...")
|
logger.info(f"Downloaded {len(all_parts)} parts so far...")
|
||||||
|
|
||||||
# If we got fewer results than requested, we've reached the end
|
# Continue pagination - API returns exactly 100 results per page until exhausted
|
||||||
if len(batch) < batch_size:
|
# Only stop when we get 0 results (handled above)
|
||||||
break
|
|
||||||
|
|
||||||
# Rate limiting - be nice to the API
|
# Rate limiting - be nice to the API
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Uses S-expression parsing to extract pin data from symbol definitions.
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Tuple, Optional, Dict
|
from typing import List, Tuple, Optional, Dict
|
||||||
import sexpdata
|
import sexpdata
|
||||||
@@ -314,8 +315,8 @@ if __name__ == '__main__':
|
|||||||
print("PIN LOCATOR TEST")
|
print("PIN LOCATOR TEST")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
|
|
||||||
# Create test schematic with components
|
# Create test schematic with components (cross-platform temp directory)
|
||||||
test_path = Path('/tmp/test_pin_locator.kicad_sch')
|
test_path = Path(tempfile.gettempdir()) / 'test_pin_locator.kicad_sch'
|
||||||
template_path = Path('/home/chris/MCP/KiCAD-MCP-Server/python/templates/template_with_symbols_expanded.kicad_sch')
|
template_path = Path('/home/chris/MCP/KiCAD-MCP-Server/python/templates/template_with_symbols_expanded.kicad_sch')
|
||||||
|
|
||||||
shutil.copy(template_path, test_path)
|
shutil.copy(template_path, test_path)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from skip import Schematic
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
|
|
||||||
logger = logging.getLogger('kicad_interface')
|
logger = logging.getLogger('kicad_interface')
|
||||||
|
|
||||||
@@ -28,9 +29,12 @@ class SchematicManager:
|
|||||||
else:
|
else:
|
||||||
# Fallback: create minimal schematic
|
# Fallback: create minimal schematic
|
||||||
logger.warning(f"Template not found at {template_path}, creating minimal schematic")
|
logger.warning(f"Template not found at {template_path}, creating minimal schematic")
|
||||||
with open(output_path, 'w') as f:
|
# 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 20230121) (generator "KiCAD-MCP-Server")\n\n')
|
f.write('(kicad_sch (version 20230121) (generator "KiCAD-MCP-Server")\n\n')
|
||||||
f.write(' (uuid 00000000-0000-0000-0000-000000000000)\n\n')
|
f.write(f' (uuid {schematic_uuid})\n\n')
|
||||||
f.write(' (paper "A4")\n\n')
|
f.write(' (paper "A4")\n\n')
|
||||||
f.write(' (lib_symbols\n )\n\n')
|
f.write(' (lib_symbols\n )\n\n')
|
||||||
f.write(' (sheet_instances\n (path "/" (page "1"))\n )\n')
|
f.write(' (sheet_instances\n (path "/" (page "1"))\n )\n')
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ manipulate the .kicad_sch file directly.
|
|||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Tuple, Optional, Dict
|
from typing import List, Tuple, Optional, Dict
|
||||||
import sexpdata
|
import sexpdata
|
||||||
@@ -382,8 +383,8 @@ if __name__ == '__main__':
|
|||||||
print("WIRE MANAGER TEST")
|
print("WIRE MANAGER TEST")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
|
|
||||||
# Create test schematic
|
# Create test schematic (cross-platform temp directory)
|
||||||
test_path = Path('/tmp/test_wire_manager.kicad_sch')
|
test_path = Path(tempfile.gettempdir()) / 'test_wire_manager.kicad_sch'
|
||||||
template_path = Path('/home/chris/MCP/KiCAD-MCP-Server/python/templates/empty.kicad_sch')
|
template_path = Path('/home/chris/MCP/KiCAD-MCP-Server/python/templates/empty.kicad_sch')
|
||||||
|
|
||||||
shutil.copy(template_path, test_path)
|
shutil.copy(template_path, test_path)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Key Benefits over SWIG:
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Dict, Any, List, Callable
|
from typing import Optional, Dict, Any, List, Callable
|
||||||
|
|
||||||
@@ -74,12 +75,16 @@ class IPCBackend(KiCADBackend):
|
|||||||
if socket_path:
|
if socket_path:
|
||||||
socket_paths_to_try.append(socket_path)
|
socket_paths_to_try.append(socket_path)
|
||||||
else:
|
else:
|
||||||
# Common socket locations
|
# Common socket locations (Unix-like systems only)
|
||||||
socket_paths_to_try = [
|
# Windows uses named pipes, handled by auto-detect
|
||||||
'ipc:///tmp/kicad/api.sock', # Linux default
|
if platform.system() != "Windows":
|
||||||
f'ipc:///run/user/{os.getuid()}/kicad/api.sock', # XDG runtime
|
socket_paths_to_try.append('ipc:///tmp/kicad/api.sock') # Linux default
|
||||||
None # Let kipy auto-detect
|
# XDG runtime directory (requires getuid, Unix only)
|
||||||
]
|
if hasattr(os, 'getuid'):
|
||||||
|
socket_paths_to_try.append(f'ipc:///run/user/{os.getuid()}/kicad/api.sock')
|
||||||
|
|
||||||
|
# Auto-detect for all platforms (Windows uses named pipes, Unix uses sockets)
|
||||||
|
socket_paths_to_try.append(None)
|
||||||
|
|
||||||
last_error = None
|
last_error = None
|
||||||
for path in socket_paths_to_try:
|
for path in socket_paths_to_try:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
(kicad_sch (version 20230121) (generator "KiCAD-MCP-Server")
|
(kicad_sch (version 20230121) (generator "KiCAD-MCP-Server")
|
||||||
|
|
||||||
(uuid 00000000-0000-0000-0000-000000000000)
|
(uuid a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d)
|
||||||
|
|
||||||
(paper "A4")
|
(paper "A4")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user