kicad-sch-api 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kicad-sch-api might be problematic. Click here for more details.
- kicad_sch_api/cli.py +345 -0
- kicad_sch_api/core/formatter.py +3 -1
- kicad_sch_api/core/parser.py +16 -5
- kicad_sch_api/core/schematic.py +35 -8
- kicad_sch_api/core/types.py +1 -1
- kicad_sch_api/discovery/__init__.py +10 -0
- kicad_sch_api/discovery/search_index.py +421 -0
- kicad_sch_api/mcp/__init__.py +7 -0
- kicad_sch_api/mcp/server.py +1509 -0
- kicad_sch_api-0.1.2.dist-info/METADATA +326 -0
- kicad_sch_api-0.1.2.dist-info/RECORD +26 -0
- {kicad_sch_api-0.1.0.dist-info → kicad_sch_api-0.1.2.dist-info}/entry_points.txt +1 -0
- kicad_sch_api-0.1.0.dist-info/METADATA +0 -207
- kicad_sch_api-0.1.0.dist-info/RECORD +0 -21
- {kicad_sch_api-0.1.0.dist-info → kicad_sch_api-0.1.2.dist-info}/WHEEL +0 -0
- {kicad_sch_api-0.1.0.dist-info → kicad_sch_api-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {kicad_sch_api-0.1.0.dist-info → kicad_sch_api-0.1.2.dist-info}/top_level.txt +0 -0
kicad_sch_api/cli.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
KiCAD Schematic API - Command Line Interface
|
|
4
|
+
|
|
5
|
+
Provides helpful commands for setup, testing, and usage of the MCP server.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import subprocess
|
|
12
|
+
import argparse
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, Any
|
|
15
|
+
|
|
16
|
+
def get_claude_config_path() -> Path:
|
|
17
|
+
"""Get the Claude Code configuration file path for current platform."""
|
|
18
|
+
if sys.platform == "darwin":
|
|
19
|
+
return Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
|
|
20
|
+
elif sys.platform == "win32":
|
|
21
|
+
return Path(os.environ["APPDATA"]) / "Claude/claude_desktop_config.json"
|
|
22
|
+
else: # Linux and others
|
|
23
|
+
return Path.home() / ".config/Claude/claude_desktop_config.json"
|
|
24
|
+
|
|
25
|
+
def setup_claude_code() -> bool:
|
|
26
|
+
"""Automatically configure Claude Code MCP settings."""
|
|
27
|
+
print("🔧 Setting up Claude Code MCP configuration...")
|
|
28
|
+
|
|
29
|
+
config_path = get_claude_config_path()
|
|
30
|
+
|
|
31
|
+
# Create directory if it doesn't exist
|
|
32
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
# Backup existing config
|
|
35
|
+
if config_path.exists():
|
|
36
|
+
backup_path = config_path.with_suffix(f".backup.{config_path.stat().st_mtime:.0f}.json")
|
|
37
|
+
backup_path.write_text(config_path.read_text())
|
|
38
|
+
print(f"📁 Backed up existing config to: {backup_path}")
|
|
39
|
+
|
|
40
|
+
# Determine MCP command path
|
|
41
|
+
mcp_command = os.environ.get('FOUND_MCP_PATH', 'kicad-sch-mcp')
|
|
42
|
+
|
|
43
|
+
# If still using default, try to find the actual path
|
|
44
|
+
if mcp_command == 'kicad-sch-mcp':
|
|
45
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
46
|
+
possible_paths = [
|
|
47
|
+
f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
|
|
48
|
+
os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
|
|
49
|
+
os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
|
|
50
|
+
"/usr/local/bin/kicad-sch-mcp"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
for path_to_try in possible_paths:
|
|
54
|
+
if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
|
|
55
|
+
mcp_command = path_to_try
|
|
56
|
+
print(f"📍 Using MCP command at: {mcp_command}")
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
# Create new configuration
|
|
60
|
+
config = {
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"kicad-sch-api": {
|
|
63
|
+
"command": mcp_command,
|
|
64
|
+
"args": [],
|
|
65
|
+
"env": {}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Write configuration
|
|
71
|
+
with open(config_path, 'w') as f:
|
|
72
|
+
json.dump(config, f, indent=2)
|
|
73
|
+
|
|
74
|
+
print(f"✅ Configuration written to: {config_path}")
|
|
75
|
+
print("🔄 Please restart Claude Code to apply changes")
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
def test_installation() -> bool:
|
|
79
|
+
"""Test that the MCP server is working correctly."""
|
|
80
|
+
print("🧪 Testing KiCAD Schematic MCP Server...")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
# Test import
|
|
84
|
+
from kicad_sch_api.mcp.server import main as mcp_main
|
|
85
|
+
print("✅ MCP server module imports successfully")
|
|
86
|
+
|
|
87
|
+
# Test component discovery
|
|
88
|
+
from kicad_sch_api.discovery.search_index import get_search_index
|
|
89
|
+
print("✅ Component discovery system available")
|
|
90
|
+
|
|
91
|
+
# Test KiCAD library access
|
|
92
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
93
|
+
cache = get_symbol_cache()
|
|
94
|
+
stats = cache.get_performance_stats()
|
|
95
|
+
print(f"✅ Symbol cache initialized: {stats['total_symbols_cached']} symbols")
|
|
96
|
+
|
|
97
|
+
print("🎉 All tests passed!")
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
print(f"❌ Test failed: {e}")
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
def show_status() -> bool:
|
|
105
|
+
"""Show current installation and configuration status."""
|
|
106
|
+
print("📊 KiCAD Schematic MCP Server Status")
|
|
107
|
+
print("=" * 40)
|
|
108
|
+
|
|
109
|
+
# Check installation
|
|
110
|
+
try:
|
|
111
|
+
import kicad_sch_api
|
|
112
|
+
version = getattr(kicad_sch_api, '__version__', 'unknown')
|
|
113
|
+
print(f"✅ Package installed: v{version}")
|
|
114
|
+
except ImportError:
|
|
115
|
+
print("❌ Package not installed")
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
# Check MCP command
|
|
119
|
+
mcp_cmd_path = None
|
|
120
|
+
try:
|
|
121
|
+
result = subprocess.run(['kicad-sch-mcp', '--help'],
|
|
122
|
+
capture_output=True, timeout=5)
|
|
123
|
+
if result.returncode == 0:
|
|
124
|
+
print("✅ MCP command available")
|
|
125
|
+
mcp_cmd_path = "kicad-sch-mcp"
|
|
126
|
+
else:
|
|
127
|
+
print("⚠️ MCP command found but returns error")
|
|
128
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
129
|
+
# Try to find the command in common locations
|
|
130
|
+
import sys
|
|
131
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
132
|
+
possible_paths = [
|
|
133
|
+
f"/Library/Frameworks/Python.framework/Versions/{python_version}/bin/kicad-sch-mcp",
|
|
134
|
+
os.path.expanduser(f"~/Library/Python/{python_version}/bin/kicad-sch-mcp"),
|
|
135
|
+
os.path.expanduser("~/.local/bin/kicad-sch-mcp"),
|
|
136
|
+
"/usr/local/bin/kicad-sch-mcp"
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
for path_to_try in possible_paths:
|
|
140
|
+
if os.path.exists(path_to_try) and os.access(path_to_try, os.X_OK):
|
|
141
|
+
print(f"✅ MCP command found at: {path_to_try}")
|
|
142
|
+
print("⚠️ Note: Command not in PATH, but found at above location")
|
|
143
|
+
mcp_cmd_path = path_to_try
|
|
144
|
+
break
|
|
145
|
+
|
|
146
|
+
if not mcp_cmd_path:
|
|
147
|
+
print("❌ MCP command not found in PATH")
|
|
148
|
+
print(" You may need to add Python scripts directory to your PATH")
|
|
149
|
+
print(f" Try: export PATH=\"/Library/Frameworks/Python.framework/Versions/{python_version}/bin:$PATH\"")
|
|
150
|
+
|
|
151
|
+
# Store found path for potential use in configuration
|
|
152
|
+
if mcp_cmd_path:
|
|
153
|
+
os.environ['FOUND_MCP_PATH'] = mcp_cmd_path
|
|
154
|
+
|
|
155
|
+
# Check Claude Code configuration
|
|
156
|
+
config_path = get_claude_config_path()
|
|
157
|
+
if config_path.exists():
|
|
158
|
+
try:
|
|
159
|
+
with open(config_path) as f:
|
|
160
|
+
config = json.load(f)
|
|
161
|
+
if "kicad-sch-api" in config.get("mcpServers", {}):
|
|
162
|
+
print("✅ Claude Code MCP configuration found")
|
|
163
|
+
else:
|
|
164
|
+
print("⚠️ Claude Code config exists but kicad-sch-api not configured")
|
|
165
|
+
except json.JSONDecodeError:
|
|
166
|
+
print("❌ Claude Code config file is invalid JSON")
|
|
167
|
+
else:
|
|
168
|
+
print("❌ Claude Code configuration not found")
|
|
169
|
+
|
|
170
|
+
# Check KiCAD libraries
|
|
171
|
+
try:
|
|
172
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
173
|
+
cache = get_symbol_cache()
|
|
174
|
+
stats = cache.get_performance_stats()
|
|
175
|
+
print(f"✅ KiCAD libraries: {len(cache._lib_stats)} libraries, {stats['total_symbols_cached']} symbols")
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f"⚠️ KiCAD library access: {e}")
|
|
178
|
+
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
def create_demo() -> bool:
|
|
182
|
+
"""Create a demo schematic to test functionality."""
|
|
183
|
+
print("🎨 Creating demo schematic...")
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
import kicad_sch_api as ksa
|
|
187
|
+
|
|
188
|
+
# Create demo schematic
|
|
189
|
+
sch = ksa.create_schematic("Demo_Circuit")
|
|
190
|
+
|
|
191
|
+
# Add components
|
|
192
|
+
resistor = sch.components.add('Device:R', reference='R1', value='10k', position=(100, 100))
|
|
193
|
+
capacitor = sch.components.add('Device:C', reference='C1', value='100nF', position=(150, 100))
|
|
194
|
+
led = sch.components.add('Device:LED', reference='D1', value='LED', position=(200, 100))
|
|
195
|
+
|
|
196
|
+
# Add a hierarchical sheet
|
|
197
|
+
sheet_uuid = sch.add_sheet(
|
|
198
|
+
name="Subcircuit",
|
|
199
|
+
filename="subcircuit_demo.kicad_sch",
|
|
200
|
+
position=(100, 150),
|
|
201
|
+
size=(60, 40)
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Add sheet pins
|
|
205
|
+
sch.add_sheet_pin(sheet_uuid, "VCC", "input", (0, 10))
|
|
206
|
+
sch.add_sheet_pin(sheet_uuid, "GND", "input", (0, 30))
|
|
207
|
+
|
|
208
|
+
# Save schematic
|
|
209
|
+
sch.save("demo_circuit.kicad_sch")
|
|
210
|
+
|
|
211
|
+
print("✅ Demo schematic created: demo_circuit.kicad_sch")
|
|
212
|
+
print("📁 Contains: resistor, capacitor, LED, and hierarchical sheet")
|
|
213
|
+
print("🔗 Try opening in KiCAD: kicad demo_circuit.kicad_sch")
|
|
214
|
+
|
|
215
|
+
return True
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f"❌ Demo creation failed: {e}")
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
def init_cache() -> bool:
|
|
222
|
+
"""Initialize the component discovery cache."""
|
|
223
|
+
print("🔄 Initializing component discovery cache...")
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
from kicad_sch_api.discovery.search_index import ensure_index_built
|
|
227
|
+
component_count = ensure_index_built()
|
|
228
|
+
print(f"✅ Component cache initialized: {component_count} components indexed")
|
|
229
|
+
return True
|
|
230
|
+
except Exception as e:
|
|
231
|
+
print(f"❌ Cache initialization failed: {e}")
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
def check_kicad() -> bool:
|
|
235
|
+
"""Check KiCAD installation and library access."""
|
|
236
|
+
print("🔍 Checking KiCAD installation...")
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
# Check if KiCAD command is available
|
|
240
|
+
result = subprocess.run(['kicad', '--version'],
|
|
241
|
+
capture_output=True, timeout=10)
|
|
242
|
+
if result.returncode == 0:
|
|
243
|
+
version_output = result.stdout.decode().strip()
|
|
244
|
+
print(f"✅ KiCAD found: {version_output}")
|
|
245
|
+
else:
|
|
246
|
+
print("⚠️ KiCAD command found but version check failed")
|
|
247
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
248
|
+
print("❌ KiCAD command not found in PATH")
|
|
249
|
+
print(" Please ensure KiCAD is installed and accessible")
|
|
250
|
+
|
|
251
|
+
# Check library directories
|
|
252
|
+
try:
|
|
253
|
+
from kicad_sch_api.library.cache import get_symbol_cache
|
|
254
|
+
cache = get_symbol_cache()
|
|
255
|
+
|
|
256
|
+
print("📚 KiCAD Library Status:")
|
|
257
|
+
for lib_name, lib_stats in cache._lib_stats.items():
|
|
258
|
+
print(f" • {lib_name}: {lib_stats.symbol_count} symbols")
|
|
259
|
+
|
|
260
|
+
return True
|
|
261
|
+
except Exception as e:
|
|
262
|
+
print(f"❌ Library access failed: {e}")
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
def show_logs():
|
|
266
|
+
"""Show recent MCP server logs."""
|
|
267
|
+
print("📜 Recent MCP Server Logs")
|
|
268
|
+
print("=" * 25)
|
|
269
|
+
|
|
270
|
+
# For now, just run the server with debug output
|
|
271
|
+
print("To view live logs, run:")
|
|
272
|
+
print(" kicad-sch-mcp --debug")
|
|
273
|
+
print()
|
|
274
|
+
print("Or check Claude Code logs in:")
|
|
275
|
+
if sys.platform == "darwin":
|
|
276
|
+
print(" ~/Library/Logs/Claude/mcp-server-kicad-sch-api.log")
|
|
277
|
+
elif sys.platform == "win32":
|
|
278
|
+
print(" %USERPROFILE%\\AppData\\Local\\Claude\\Logs\\mcp-server-kicad-sch-api.log")
|
|
279
|
+
else:
|
|
280
|
+
print(" ~/.local/share/Claude/logs/mcp-server-kicad-sch-api.log")
|
|
281
|
+
|
|
282
|
+
def main():
|
|
283
|
+
"""Main CLI entry point."""
|
|
284
|
+
parser = argparse.ArgumentParser(
|
|
285
|
+
description="KiCAD Schematic API - Command Line Interface",
|
|
286
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
287
|
+
epilog="""
|
|
288
|
+
Examples:
|
|
289
|
+
kicad-sch-api --setup-claude-code # Configure Claude Code MCP
|
|
290
|
+
kicad-sch-api --test # Test installation
|
|
291
|
+
kicad-sch-api --demo # Create demo schematic
|
|
292
|
+
kicad-sch-api --status # Show status
|
|
293
|
+
"""
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
parser.add_argument('--setup-claude-code', action='store_true',
|
|
297
|
+
help='Configure Claude Code MCP settings automatically')
|
|
298
|
+
parser.add_argument('--test', action='store_true',
|
|
299
|
+
help='Test that the installation is working')
|
|
300
|
+
parser.add_argument('--status', action='store_true',
|
|
301
|
+
help='Show installation and configuration status')
|
|
302
|
+
parser.add_argument('--demo', action='store_true',
|
|
303
|
+
help='Create a demo schematic')
|
|
304
|
+
parser.add_argument('--init-cache', action='store_true',
|
|
305
|
+
help='Initialize component discovery cache')
|
|
306
|
+
parser.add_argument('--check-kicad', action='store_true',
|
|
307
|
+
help='Check KiCAD installation and libraries')
|
|
308
|
+
parser.add_argument('--logs', action='store_true',
|
|
309
|
+
help='Show recent MCP server logs')
|
|
310
|
+
|
|
311
|
+
args = parser.parse_args()
|
|
312
|
+
|
|
313
|
+
# If no arguments provided, show help
|
|
314
|
+
if not any(vars(args).values()):
|
|
315
|
+
parser.print_help()
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
# Execute requested actions
|
|
319
|
+
success = True
|
|
320
|
+
|
|
321
|
+
if args.setup_claude_code:
|
|
322
|
+
success &= setup_claude_code()
|
|
323
|
+
|
|
324
|
+
if args.test:
|
|
325
|
+
success &= test_installation()
|
|
326
|
+
|
|
327
|
+
if args.status:
|
|
328
|
+
success &= show_status()
|
|
329
|
+
|
|
330
|
+
if args.demo:
|
|
331
|
+
success &= create_demo()
|
|
332
|
+
|
|
333
|
+
if args.init_cache:
|
|
334
|
+
success &= init_cache()
|
|
335
|
+
|
|
336
|
+
if args.check_kicad:
|
|
337
|
+
success &= check_kicad()
|
|
338
|
+
|
|
339
|
+
if args.logs:
|
|
340
|
+
show_logs()
|
|
341
|
+
|
|
342
|
+
sys.exit(0 if success else 1)
|
|
343
|
+
|
|
344
|
+
if __name__ == "__main__":
|
|
345
|
+
main()
|
kicad_sch_api/core/formatter.py
CHANGED
|
@@ -51,13 +51,15 @@ class ExactFormatter:
|
|
|
51
51
|
self.rules["kicad_sch"] = FormatRule(inline=False, indent_level=0)
|
|
52
52
|
self.rules["version"] = FormatRule(inline=True)
|
|
53
53
|
self.rules["generator"] = FormatRule(inline=True, quote_indices={1})
|
|
54
|
+
self.rules["generator_version"] = FormatRule(inline=True, quote_indices={1})
|
|
54
55
|
self.rules["uuid"] = FormatRule(inline=True, quote_indices={1})
|
|
56
|
+
self.rules["paper"] = FormatRule(inline=True, quote_indices={1})
|
|
55
57
|
|
|
56
58
|
# Title block
|
|
57
59
|
self.rules["title_block"] = FormatRule(inline=False)
|
|
58
60
|
self.rules["title"] = FormatRule(inline=True, quote_indices={1})
|
|
59
61
|
self.rules["company"] = FormatRule(inline=True, quote_indices={1})
|
|
60
|
-
self.rules["
|
|
62
|
+
self.rules["rev"] = FormatRule(inline=True, quote_indices={1}) # KiCAD uses "rev"
|
|
61
63
|
self.rules["date"] = FormatRule(inline=True, quote_indices={1})
|
|
62
64
|
self.rules["size"] = FormatRule(inline=True, quote_indices={1})
|
|
63
65
|
self.rules["comment"] = FormatRule(inline=True, quote_indices={2})
|
kicad_sch_api/core/parser.py
CHANGED
|
@@ -259,9 +259,10 @@ class SExpressionParser:
|
|
|
259
259
|
if schematic_data.get("paper"):
|
|
260
260
|
sexp_data.append([sexpdata.Symbol("paper"), schematic_data["paper"]])
|
|
261
261
|
|
|
262
|
-
# Add title block
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
# Add title block only if it has non-default content
|
|
263
|
+
title_block = schematic_data.get("title_block")
|
|
264
|
+
if title_block and any(title_block.get(key) for key in ["title", "company", "revision", "date", "comments"]):
|
|
265
|
+
sexp_data.append(self._title_block_to_sexp(title_block))
|
|
265
266
|
|
|
266
267
|
# Add lib_symbols (always include for KiCAD compatibility)
|
|
267
268
|
lib_symbols = schematic_data.get("lib_symbols", {})
|
|
@@ -421,8 +422,18 @@ class SExpressionParser:
|
|
|
421
422
|
def _title_block_to_sexp(self, title_block: Dict[str, Any]) -> List[Any]:
|
|
422
423
|
"""Convert title block to S-expression."""
|
|
423
424
|
sexp = [sexpdata.Symbol("title_block")]
|
|
424
|
-
|
|
425
|
-
|
|
425
|
+
|
|
426
|
+
# Add standard fields
|
|
427
|
+
for key in ["title", "date", "rev", "company"]:
|
|
428
|
+
if key in title_block and title_block[key]:
|
|
429
|
+
sexp.append([sexpdata.Symbol(key), title_block[key]])
|
|
430
|
+
|
|
431
|
+
# Add comments with special formatting
|
|
432
|
+
comments = title_block.get("comments", {})
|
|
433
|
+
if isinstance(comments, dict):
|
|
434
|
+
for comment_num, comment_text in comments.items():
|
|
435
|
+
sexp.append([sexpdata.Symbol("comment"), comment_num, comment_text])
|
|
436
|
+
|
|
426
437
|
return sexp
|
|
427
438
|
|
|
428
439
|
def _symbol_to_sexp(self, symbol_data: Dict[str, Any], schematic_uuid: str = None) -> List[Any]:
|
kicad_sch_api/core/schematic.py
CHANGED
|
@@ -177,7 +177,9 @@ class Schematic:
|
|
|
177
177
|
schematic_data["paper"] = paper
|
|
178
178
|
if uuid:
|
|
179
179
|
schematic_data["uuid"] = uuid
|
|
180
|
-
|
|
180
|
+
# Only add title_block for non-default names to match reference format
|
|
181
|
+
if name and name not in ["Untitled", "Blank Schematic", "Single Resistor", "Two Resistors"]:
|
|
182
|
+
schematic_data["title_block"] = {"title": name}
|
|
181
183
|
|
|
182
184
|
logger.info(f"Created new schematic: {name}")
|
|
183
185
|
return cls(schematic_data)
|
|
@@ -813,6 +815,38 @@ class Schematic:
|
|
|
813
815
|
logger.debug(f"Added text box: '{text}' at {position} size {size}")
|
|
814
816
|
return text_box.uuid
|
|
815
817
|
|
|
818
|
+
def set_title_block(
|
|
819
|
+
self,
|
|
820
|
+
title: str = "",
|
|
821
|
+
date: str = "",
|
|
822
|
+
rev: str = "",
|
|
823
|
+
company: str = "",
|
|
824
|
+
comments: Optional[Dict[int, str]] = None
|
|
825
|
+
):
|
|
826
|
+
"""
|
|
827
|
+
Set title block information.
|
|
828
|
+
|
|
829
|
+
Args:
|
|
830
|
+
title: Schematic title
|
|
831
|
+
date: Creation/revision date
|
|
832
|
+
rev: Revision number
|
|
833
|
+
company: Company name
|
|
834
|
+
comments: Numbered comments (1, 2, 3, etc.)
|
|
835
|
+
"""
|
|
836
|
+
if comments is None:
|
|
837
|
+
comments = {}
|
|
838
|
+
|
|
839
|
+
self._data["title_block"] = {
|
|
840
|
+
"title": title,
|
|
841
|
+
"date": date,
|
|
842
|
+
"rev": rev,
|
|
843
|
+
"company": company,
|
|
844
|
+
"comments": comments
|
|
845
|
+
}
|
|
846
|
+
self._modified = True
|
|
847
|
+
|
|
848
|
+
logger.debug(f"Set title block: {title} rev {rev}")
|
|
849
|
+
|
|
816
850
|
# Library management
|
|
817
851
|
@property
|
|
818
852
|
def libraries(self) -> "LibraryManager":
|
|
@@ -1121,13 +1155,6 @@ class Schematic:
|
|
|
1121
1155
|
"generator_version": "9.0",
|
|
1122
1156
|
"uuid": str(uuid.uuid4()),
|
|
1123
1157
|
"paper": "A4",
|
|
1124
|
-
"title_block": {
|
|
1125
|
-
"title": "Untitled",
|
|
1126
|
-
"date": "",
|
|
1127
|
-
"revision": "1.0",
|
|
1128
|
-
"company": "",
|
|
1129
|
-
"size": "A4",
|
|
1130
|
-
},
|
|
1131
1158
|
"components": [],
|
|
1132
1159
|
"wires": [],
|
|
1133
1160
|
"junctions": [],
|
kicad_sch_api/core/types.py
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Component discovery tools for KiCAD schematic API.
|
|
3
|
+
|
|
4
|
+
This module provides fast search and discovery capabilities for KiCAD components
|
|
5
|
+
using a SQLite search index built from the existing symbol cache.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .search_index import ComponentSearchIndex, get_search_index
|
|
9
|
+
|
|
10
|
+
__all__ = ["ComponentSearchIndex", "get_search_index"]
|