kicad-sch-api 0.0.1__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.

@@ -0,0 +1,447 @@
1
+ """
2
+ Validation utilities for KiCAD schematic manipulation.
3
+
4
+ This module provides comprehensive validation capabilities including error collection,
5
+ syntax validation, and semantic checking for schematic operations.
6
+ """
7
+
8
+ import logging
9
+ import re
10
+ from dataclasses import dataclass
11
+ from enum import Enum
12
+ from typing import Any, Dict, List, Optional, Set, Union
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class ValidationLevel(Enum):
18
+ """Validation issue severity levels."""
19
+
20
+ INFO = "info"
21
+ WARNING = "warning"
22
+ ERROR = "error"
23
+ CRITICAL = "critical"
24
+
25
+
26
+ @dataclass
27
+ class ValidationIssue:
28
+ """Single validation issue with context."""
29
+
30
+ category: str # e.g., "syntax", "reference", "connection"
31
+ message: str # Human-readable description
32
+ level: ValidationLevel
33
+ context: Optional[Dict[str, Any]] = None # Additional context data
34
+ suggestion: Optional[str] = None # Suggested fix
35
+
36
+ def __post_init__(self):
37
+ if isinstance(self.level, str):
38
+ self.level = ValidationLevel(self.level)
39
+
40
+ def __str__(self) -> str:
41
+ context_str = f" ({self.context})" if self.context else ""
42
+ suggestion_str = f" Suggestion: {self.suggestion}" if self.suggestion else ""
43
+ return f"{self.level.value.upper()}: {self.category}: {self.message}{context_str}{suggestion_str}"
44
+
45
+
46
+ class ValidationError(Exception):
47
+ """Exception raised when critical validation errors are found."""
48
+
49
+ def __init__(self, message: str, issues: List[ValidationIssue] = None):
50
+ super().__init__(message)
51
+ self.issues = issues or []
52
+
53
+ def add_issue(self, issue: ValidationIssue):
54
+ """Add a validation issue to this error."""
55
+ self.issues.append(issue)
56
+
57
+ def get_errors(self) -> List[ValidationIssue]:
58
+ """Get only error-level issues."""
59
+ return [
60
+ issue
61
+ for issue in self.issues
62
+ if issue.level in (ValidationLevel.ERROR, ValidationLevel.CRITICAL)
63
+ ]
64
+
65
+ def get_warnings(self) -> List[ValidationIssue]:
66
+ """Get only warning-level issues."""
67
+ return [issue for issue in self.issues if issue.level == ValidationLevel.WARNING]
68
+
69
+
70
+ class SchematicValidator:
71
+ """
72
+ Comprehensive validator for schematic data structures and operations.
73
+
74
+ Provides validation for:
75
+ - S-expression syntax
76
+ - Component references and properties
77
+ - Library references
78
+ - Basic electrical connectivity
79
+ """
80
+
81
+ def __init__(self, strict: bool = False):
82
+ """
83
+ Initialize validator.
84
+
85
+ Args:
86
+ strict: If True, warnings are treated as errors
87
+ """
88
+ self.strict = strict
89
+ self.issues = []
90
+ self._valid_reference_pattern = re.compile(r"^[A-Z]+[0-9]*$")
91
+ self._valid_lib_id_pattern = re.compile(r"^[^:]+:[^:]+$")
92
+
93
+ def validate_schematic_data(self, schematic_data: Dict[str, Any]) -> List[ValidationIssue]:
94
+ """
95
+ Validate complete schematic data structure.
96
+
97
+ Args:
98
+ schematic_data: Parsed schematic data
99
+
100
+ Returns:
101
+ List of validation issues found
102
+ """
103
+ self.issues.clear()
104
+
105
+ # Validate basic structure
106
+ self._validate_basic_structure(schematic_data)
107
+
108
+ # Validate components
109
+ components = schematic_data.get("components", [])
110
+ self._validate_components(components)
111
+
112
+ # Validate references are unique
113
+ self._validate_unique_references(components)
114
+
115
+ # Validate wires and connections
116
+ wires = schematic_data.get("wires", [])
117
+ self._validate_wires(wires)
118
+
119
+ # Validate nets
120
+ nets = schematic_data.get("nets", [])
121
+ self._validate_nets(nets, components)
122
+
123
+ return self.issues.copy()
124
+
125
+ def validate_component(self, component_data: Dict[str, Any]) -> List[ValidationIssue]:
126
+ """Validate a single component."""
127
+ self.issues.clear()
128
+ self._validate_single_component(component_data)
129
+ return self.issues.copy()
130
+
131
+ def validate_reference(self, reference: str) -> bool:
132
+ """
133
+ Validate component reference format.
134
+
135
+ Args:
136
+ reference: Reference to validate (e.g., "R1", "U5")
137
+
138
+ Returns:
139
+ True if reference is valid
140
+ """
141
+ if not reference:
142
+ return False
143
+ return bool(self._valid_reference_pattern.match(reference))
144
+
145
+ def validate_lib_id(self, lib_id: str) -> bool:
146
+ """
147
+ Validate library ID format.
148
+
149
+ Args:
150
+ lib_id: Library ID to validate (e.g., "Device:R")
151
+
152
+ Returns:
153
+ True if lib_id is valid
154
+ """
155
+ if not lib_id:
156
+ return False
157
+ return bool(self._valid_lib_id_pattern.match(lib_id))
158
+
159
+ def _validate_basic_structure(self, data: Dict[str, Any]):
160
+ """Validate basic schematic structure."""
161
+ required_fields = ["version", "components"]
162
+
163
+ for field in required_fields:
164
+ if field not in data:
165
+ self.issues.append(
166
+ ValidationIssue(
167
+ category="structure",
168
+ message=f"Missing required field: {field}",
169
+ level=ValidationLevel.ERROR,
170
+ )
171
+ )
172
+
173
+ # Check version format
174
+ version = data.get("version")
175
+ if version and not isinstance(version, (int, str)):
176
+ self.issues.append(
177
+ ValidationIssue(
178
+ category="structure",
179
+ message=f"Invalid version type: {type(version)}",
180
+ level=ValidationLevel.WARNING,
181
+ suggestion="Version should be string or number",
182
+ )
183
+ )
184
+
185
+ def _validate_components(self, components: List[Dict[str, Any]]):
186
+ """Validate all components in schematic."""
187
+ if not isinstance(components, list):
188
+ self.issues.append(
189
+ ValidationIssue(
190
+ category="components",
191
+ message="Components must be a list",
192
+ level=ValidationLevel.ERROR,
193
+ )
194
+ )
195
+ return
196
+
197
+ for i, component in enumerate(components):
198
+ try:
199
+ self._validate_single_component(component, f"component[{i}]")
200
+ except Exception as e:
201
+ self.issues.append(
202
+ ValidationIssue(
203
+ category="components",
204
+ message=f"Error validating component {i}: {e}",
205
+ level=ValidationLevel.ERROR,
206
+ context={"component_index": i},
207
+ )
208
+ )
209
+
210
+ def _validate_single_component(self, component: Dict[str, Any], context: str = "component"):
211
+ """Validate a single component structure."""
212
+ required_fields = ["lib_id", "reference", "position"]
213
+
214
+ for field in required_fields:
215
+ if field not in component:
216
+ self.issues.append(
217
+ ValidationIssue(
218
+ category="component",
219
+ message=f"{context}: Missing required field: {field}",
220
+ level=ValidationLevel.ERROR,
221
+ context={"field": field},
222
+ )
223
+ )
224
+
225
+ # Validate reference format
226
+ reference = component.get("reference")
227
+ if reference and not self.validate_reference(reference):
228
+ self.issues.append(
229
+ ValidationIssue(
230
+ category="reference",
231
+ message=f"{context}: Invalid reference format: {reference}",
232
+ level=ValidationLevel.ERROR,
233
+ context={"reference": reference},
234
+ suggestion="Reference should match pattern: [A-Z]+[0-9]*",
235
+ )
236
+ )
237
+
238
+ # Validate lib_id format
239
+ lib_id = component.get("lib_id")
240
+ if lib_id and not self.validate_lib_id(lib_id):
241
+ self.issues.append(
242
+ ValidationIssue(
243
+ category="lib_id",
244
+ message=f"{context}: Invalid lib_id format: {lib_id}",
245
+ level=ValidationLevel.ERROR,
246
+ context={"lib_id": lib_id},
247
+ suggestion="lib_id should match pattern: Library:Symbol",
248
+ )
249
+ )
250
+
251
+ # Validate position
252
+ position = component.get("position")
253
+ if position:
254
+ self._validate_position(position, f"{context}.position")
255
+
256
+ # Validate UUID if present
257
+ uuid = component.get("uuid")
258
+ if uuid and not self._validate_uuid(uuid):
259
+ self.issues.append(
260
+ ValidationIssue(
261
+ category="uuid",
262
+ message=f"{context}: Invalid UUID format: {uuid}",
263
+ level=ValidationLevel.WARNING,
264
+ context={"uuid": uuid},
265
+ )
266
+ )
267
+
268
+ def _validate_position(self, position: Any, context: str):
269
+ """Validate position data."""
270
+ if hasattr(position, "x") and hasattr(position, "y"):
271
+ # Point object
272
+ try:
273
+ float(position.x)
274
+ float(position.y)
275
+ except (TypeError, ValueError):
276
+ self.issues.append(
277
+ ValidationIssue(
278
+ category="position",
279
+ message=f"{context}: Position coordinates must be numeric",
280
+ level=ValidationLevel.ERROR,
281
+ context={"position": str(position)},
282
+ )
283
+ )
284
+ else:
285
+ self.issues.append(
286
+ ValidationIssue(
287
+ category="position",
288
+ message=f"{context}: Invalid position format",
289
+ level=ValidationLevel.ERROR,
290
+ context={"position": position},
291
+ suggestion="Position should be Point object with x,y coordinates",
292
+ )
293
+ )
294
+
295
+ def _validate_unique_references(self, components: List[Dict[str, Any]]):
296
+ """Validate that all component references are unique."""
297
+ references = []
298
+ duplicates = set()
299
+
300
+ for component in components:
301
+ ref = component.get("reference")
302
+ if ref:
303
+ if ref in references:
304
+ duplicates.add(ref)
305
+ references.append(ref)
306
+
307
+ for ref in duplicates:
308
+ self.issues.append(
309
+ ValidationIssue(
310
+ category="reference",
311
+ message=f"Duplicate component reference: {ref}",
312
+ level=ValidationLevel.ERROR,
313
+ context={"reference": ref},
314
+ suggestion="Each component must have a unique reference",
315
+ )
316
+ )
317
+
318
+ def _validate_wires(self, wires: List[Dict[str, Any]]):
319
+ """Validate wire connections."""
320
+ for i, wire in enumerate(wires):
321
+ context = f"wire[{i}]"
322
+
323
+ # Validate start and end points
324
+ for point_name in ["start", "end"]:
325
+ point = wire.get(point_name)
326
+ if point:
327
+ self._validate_position(point, f"{context}.{point_name}")
328
+
329
+ # Validate wire has valid length
330
+ start = wire.get("start")
331
+ end = wire.get("end")
332
+ if start and end and hasattr(start, "x") and hasattr(end, "x"):
333
+ if start.x == end.x and start.y == end.y:
334
+ self.issues.append(
335
+ ValidationIssue(
336
+ category="wire",
337
+ message=f"{context}: Wire has zero length",
338
+ level=ValidationLevel.WARNING,
339
+ context={"start": str(start), "end": str(end)},
340
+ )
341
+ )
342
+
343
+ def _validate_nets(self, nets: List[Dict[str, Any]], components: List[Dict[str, Any]]):
344
+ """Validate electrical nets."""
345
+ component_refs = {comp.get("reference") for comp in components if comp.get("reference")}
346
+
347
+ for i, net in enumerate(nets):
348
+ context = f"net[{i}]"
349
+
350
+ # Validate net has connections
351
+ connections = net.get("components", [])
352
+ if not connections:
353
+ self.issues.append(
354
+ ValidationIssue(
355
+ category="net",
356
+ message=f"{context}: Net has no connections",
357
+ level=ValidationLevel.WARNING,
358
+ context={"net_name": net.get("name", "unnamed")},
359
+ )
360
+ )
361
+
362
+ # Validate all referenced components exist
363
+ for ref, pin in connections:
364
+ if ref not in component_refs:
365
+ self.issues.append(
366
+ ValidationIssue(
367
+ category="net",
368
+ message=f"{context}: References non-existent component: {ref}",
369
+ level=ValidationLevel.ERROR,
370
+ context={"reference": ref, "net_name": net.get("name", "unnamed")},
371
+ )
372
+ )
373
+
374
+ def _validate_uuid(self, uuid_str: str) -> bool:
375
+ """Validate UUID format."""
376
+ uuid_pattern = re.compile(
377
+ r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", re.IGNORECASE
378
+ )
379
+ return bool(uuid_pattern.match(uuid_str))
380
+
381
+ def has_errors(self) -> bool:
382
+ """Check if any error-level issues were found."""
383
+ return any(
384
+ issue.level in (ValidationLevel.ERROR, ValidationLevel.CRITICAL)
385
+ for issue in self.issues
386
+ )
387
+
388
+ def has_warnings(self) -> bool:
389
+ """Check if any warning-level issues were found."""
390
+ return any(issue.level == ValidationLevel.WARNING for issue in self.issues)
391
+
392
+ def get_summary(self) -> Dict[str, int]:
393
+ """Get summary of validation issues by level."""
394
+ summary = {level.value: 0 for level in ValidationLevel}
395
+ for issue in self.issues:
396
+ summary[issue.level.value] += 1
397
+ return summary
398
+
399
+
400
+ def validate_schematic_file(file_path: str) -> List[ValidationIssue]:
401
+ """
402
+ Convenience function to validate a schematic file.
403
+
404
+ Args:
405
+ file_path: Path to .kicad_sch file
406
+
407
+ Returns:
408
+ List of validation issues
409
+ """
410
+ from ..core.parser import SExpressionParser
411
+
412
+ parser = SExpressionParser()
413
+ try:
414
+ schematic_data = parser.parse_file(file_path)
415
+ validator = SchematicValidator()
416
+ return validator.validate_schematic_data(schematic_data)
417
+ except Exception as e:
418
+ return [
419
+ ValidationIssue(
420
+ category="file",
421
+ message=f"Failed to validate file {file_path}: {e}",
422
+ level=ValidationLevel.CRITICAL,
423
+ )
424
+ ]
425
+
426
+
427
+ def collect_validation_errors(func):
428
+ """
429
+ Decorator to collect validation errors from operations.
430
+
431
+ Usage:
432
+ @collect_validation_errors
433
+ def my_operation():
434
+ # ... operation that might have validation issues
435
+ """
436
+
437
+ def wrapper(*args, **kwargs):
438
+ try:
439
+ return func(*args, **kwargs)
440
+ except ValidationError as e:
441
+ logger.error(f"Validation failed in {func.__name__}: {e}")
442
+ # Log individual issues
443
+ for issue in e.issues:
444
+ logger.warning(f" {issue}")
445
+ raise
446
+
447
+ return wrapper
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: kicad-sch-api
3
+ Version: 0.0.1
4
+ Summary: Professional KiCAD schematic manipulation library with exact format preservation and AI agent integration
5
+ Author-email: Circuit-Synth <info@circuit-synth.com>
6
+ Maintainer-email: Circuit-Synth <info@circuit-synth.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/circuit-synth/kicad-sch-api
9
+ Project-URL: Documentation, https://circuit-synth.github.io/kicad-sch-api/
10
+ Project-URL: Repository, https://github.com/circuit-synth/kicad-sch-api.git
11
+ Project-URL: Bug Reports, https://github.com/circuit-synth/kicad-sch-api/issues
12
+ Project-URL: Changelog, https://github.com/circuit-synth/kicad-sch-api/blob/main/CHANGELOG.md
13
+ Keywords: kicad,schematic,eda,electronics,circuit-design,ai,mcp,automation,pcb
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Operating System :: OS Independent
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: sexpdata>=0.0.3
30
+ Requires-Dist: typing-extensions>=4.0.0; python_version < "3.11"
31
+ Provides-Extra: mcp
32
+ Requires-Dist: mcp>=0.1.0; extra == "mcp"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
35
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
36
+ Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
37
+ Requires-Dist: black>=22.0.0; extra == "dev"
38
+ Requires-Dist: isort>=5.0.0; extra == "dev"
39
+ Requires-Dist: flake8>=4.0.0; extra == "dev"
40
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
41
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
42
+ Provides-Extra: docs
43
+ Requires-Dist: sphinx>=5.0.0; extra == "docs"
44
+ Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "docs"
45
+ Requires-Dist: myst-parser>=0.18.0; extra == "docs"
46
+ Dynamic: license-file
47
+
48
+ # kicad-sch-api
49
+
50
+ **Professional KiCAD Schematic Manipulation Library with AI Agent Integration**
51
+
52
+ A modern, high-performance Python library for programmatic manipulation of KiCAD schematic files (.kicad_sch) with exact format preservation, enhanced component management, and native AI agent support via Model Context Protocol (MCP).
53
+
54
+ ## ๐Ÿš€ Key Features
55
+
56
+ - **๐Ÿ“‹ Exact Format Preservation**: Output matches KiCAD's native formatting exactly
57
+ - **โšก High Performance**: Optimized for large schematics with symbol caching
58
+ - **๐Ÿค– AI Agent Integration**: Native MCP server for seamless AI agent interaction
59
+ - **๐Ÿ”ง Enhanced API**: Intuitive object-oriented interface with bulk operations
60
+ - **๐Ÿ“š Advanced Library Management**: Multi-source symbol lookup and caching
61
+ - **โœ… Professional Validation**: Comprehensive error collection and reporting
62
+ - **๐ŸŽฏ KiCAD 9 Optimized**: Built specifically for latest KiCAD format
63
+
64
+ ## ๐Ÿ†š vs. Existing Solutions
65
+
66
+ | Feature | kicad-sch-api | kicad-skip | KiCAD Official API |
67
+ |---------|---------------|------------|-------------------|
68
+ | **Schematic Support** | โœ… Full | โœ… Full | โŒ PCB Only |
69
+ | **Format Preservation** | โœ… Exact | โŒ Basic | N/A |
70
+ | **Performance** | โœ… Optimized | โš ๏ธ Basic | N/A |
71
+ | **AI Integration** | โœ… Native MCP | โŒ None | โŒ None |
72
+ | **Library Management** | โœ… Advanced | โš ๏ธ Basic | N/A |
73
+ | **Runtime Dependencies** | โŒ None | โŒ None | โœ… KiCAD Required |
74
+
75
+ ## ๐Ÿ“ฆ Installation
76
+
77
+ ```bash
78
+ # Install from PyPI (coming soon)
79
+ pip install kicad-sch-api
80
+
81
+ # Or install from source
82
+ git clone https://github.com/circuit-synth/kicad-sch-api.git
83
+ cd kicad-sch-api/python
84
+ pip install -e .
85
+
86
+ # For AI agent integration (MCP server)
87
+ cd ../mcp-server
88
+ npm install
89
+ npm run build
90
+ ```
91
+
92
+ ## ๐ŸŽฏ Quick Start
93
+
94
+ ### Basic Schematic Manipulation
95
+
96
+ ```python
97
+ import kicad_sch_api as ksa
98
+
99
+ # Load existing schematic
100
+ sch = ksa.load_schematic('my_circuit.kicad_sch')
101
+
102
+ # Add components
103
+ resistor = sch.components.add('Device:R', ref='R1', value='10k', pos=(100, 100))
104
+ capacitor = sch.components.add('Device:C', ref='C1', value='0.1uF', pos=(150, 100))
105
+
106
+ # Update properties
107
+ resistor.footprint = 'Resistor_SMD:R_0603_1608Metric'
108
+ resistor.set_property('MPN', 'RC0603FR-0710KL')
109
+
110
+ # Connect components
111
+ sch.add_wire(resistor.get_pin_position('2'), capacitor.get_pin_position('1'))
112
+
113
+ # Save with exact format preservation
114
+ sch.save() # Preserves original formatting exactly
115
+ ```
116
+
117
+ ### Advanced Operations
118
+
119
+ ```python
120
+ # Bulk operations for large schematics
121
+ resistors = sch.components.filter(lib_id='Device:R')
122
+ for r in resistors:
123
+ r.set_property('Tolerance', '1%')
124
+
125
+ # Search and analysis
126
+ power_components = sch.components.in_area(0, 0, 50, 50)
127
+ high_value_resistors = sch.components.filter(
128
+ lib_id='Device:R',
129
+ value_pattern='*k' # Components with 'k' in value
130
+ )
131
+
132
+ # Validation and error checking
133
+ issues = sch.validate()
134
+ if issues:
135
+ print(f"Found {len(issues)} validation issues:")
136
+ for issue in issues:
137
+ print(f" {issue}")
138
+
139
+ # Performance statistics
140
+ stats = sch.get_performance_stats()
141
+ print(f"Cache hit rate: {stats['symbol_cache']['hit_rate_percent']}%")
142
+ ```
143
+
144
+ ### AI Agent Integration (MCP)
145
+
146
+ Configure in Claude Desktop or compatible MCP client:
147
+
148
+ ```json
149
+ {
150
+ "kicad-sch": {
151
+ "command": "node",
152
+ "args": ["/path/to/kicad-sch-api/mcp-server/dist/index.js"],
153
+ "env": {
154
+ "PYTHON_PATH": "python3",
155
+ "KICAD_SCH_API_PATH": "/path/to/kicad-sch-api/python"
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ Then use natural language with your AI agent:
162
+
163
+ ```
164
+ User: "Create a voltage divider circuit with two 10k resistors"
165
+
166
+ Claude: I'll create a voltage divider circuit for you.
167
+
168
+ [Agent automatically uses MCP tools to:]
169
+ 1. Create new schematic
170
+ 2. Add R1 (10k resistor) at (100, 100)
171
+ 3. Add R2 (10k resistor) at (100, 150)
172
+ 4. Connect components with wires
173
+ 5. Add voltage input and output labels
174
+ 6. Save schematic with exact formatting
175
+
176
+ Your voltage divider circuit is ready! The circuit provides 50% voltage division
177
+ with two 10kฮฉ resistors in series configuration.
178
+ ```
179
+
180
+ ## ๐Ÿ—๏ธ Architecture
181
+
182
+ The library consists of two main components:
183
+
184
+ ### Python Library (Core)
185
+ - **Enhanced Object Model**: Intuitive API with fast component collections
186
+ - **Exact Format Preservation**: S-expression writer that matches KiCAD output
187
+ - **Symbol Caching**: High-performance library symbol management
188
+ - **Comprehensive Validation**: Error collection and professional reporting
189
+
190
+ ### MCP Server (AI Integration)
191
+ - **TypeScript MCP Server**: Implements Anthropic's MCP specification
192
+ - **Python Bridge**: Reliable subprocess communication
193
+ - **Comprehensive Tools**: 15+ tools for complete schematic manipulation
194
+ - **Professional Error Handling**: Detailed error context for AI agents
195
+
196
+ ## ๐Ÿงช Testing & Quality
197
+
198
+ ```bash
199
+ # Python tests
200
+ cd python
201
+ python -m pytest tests/ -v --cov=kicad_sch_api
202
+
203
+ # MCP server tests
204
+ cd mcp-server
205
+ npm test
206
+
207
+ # Format preservation tests
208
+ python -m pytest tests/test_format_preservation.py -v
209
+ ```
210
+
211
+ ## ๐Ÿค Contributing
212
+
213
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
214
+
215
+ ## ๐Ÿ“„ License
216
+
217
+ MIT License - see [LICENSE](LICENSE) for details.
218
+
219
+ ## ๐Ÿ”— Related Projects
220
+
221
+ - **[circuit-synth](https://github.com/circuit-synth/circuit-synth)**: Comprehensive circuit design automation
222
+ - **[kicad-skip](https://github.com/psychogenic/kicad-skip)**: Foundation S-expression parser
223
+
224
+ ---
225
+
226
+ **Built with โค๏ธ by the Circuit-Synth team**
@@ -0,0 +1,20 @@
1
+ kicad_sch_api/__init__.py,sha256=kvc92hzeQ6mSe3AsXSbK-CvGgoXtljyUCrzJcmBa-ao,2821
2
+ kicad_sch_api/py.typed,sha256=e4ldqxwpY7pNDG1olbvj4HSKr8sZ9vxgA_2ek8xXn-Q,70
3
+ kicad_sch_api/core/__init__.py,sha256=ur_KeYBlGKl-e1hLpLdxAhGV2A-PCCGkcqd0r6KSeBA,566
4
+ kicad_sch_api/core/components.py,sha256=_sw8Hh2eemGHzYcjGoFrBeufX05G1JfO5inYMQDQD9k,22100
5
+ kicad_sch_api/core/formatter.py,sha256=MVF3Hhc5ZVPyVDYnGcxb88q0x0UTr2DQa45gppiFqNk,11953
6
+ kicad_sch_api/core/parser.py,sha256=x7aMqnsDO4Y2VJtYvgrrJJVi2r8SAFUjSCVtMIDVWDY,16652
7
+ kicad_sch_api/core/schematic.py,sha256=O76nZvj4qffHkFrMJV5Z35xU95efPW-_mtAD8Nni7ao,15553
8
+ kicad_sch_api/core/types.py,sha256=VyzloTl4RbjMKj0TKu5rEZ-rtxtiT8nvQw8L6xawEvs,9980
9
+ kicad_sch_api/library/__init__.py,sha256=NG9UTdcpn25Bl9tPsYs9ED7bvpaVPVdtLMbnxkQkOnU,250
10
+ kicad_sch_api/library/cache.py,sha256=_JtzEGgO7ViIKF4W2zVrvmHQBIiosp9hOr9pG06Tw6I,18917
11
+ kicad_sch_api/mcp/__init__.py,sha256=dVit9lqiieujSYkyvfycE8JTo0AEWMI4plNxCK9pSD0,128
12
+ kicad_sch_api/mcp/server.py,sha256=wGTdXPF6mMA8JoP-HiDUg7XJ21Dfr0ZoThB3WqKM_fQ,19079
13
+ kicad_sch_api/utils/__init__.py,sha256=1V_yGgI7jro6MUc4Pviux_WIeJ1wmiYFID186SZwWLQ,277
14
+ kicad_sch_api/utils/validation.py,sha256=i7VvhMaYxrb8wxddf0S3vvpDE7r8ldM53CDqF9-ARqI,15557
15
+ kicad_sch_api-0.0.1.dist-info/licenses/LICENSE,sha256=Em65Nvte1G9MHc0rHqtYuGkCPcshD588itTa358J6gs,1070
16
+ kicad_sch_api-0.0.1.dist-info/METADATA,sha256=jrEKEblgqF95O2aXEdzpuZhGm1gFp4RFFe3DKU86GeQ,7643
17
+ kicad_sch_api-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
+ kicad_sch_api-0.0.1.dist-info/entry_points.txt,sha256=VWKsFi2Jv7G_tmio3cNVhhIBfv_OZFaKa-T_ED84lc8,57
19
+ kicad_sch_api-0.0.1.dist-info/top_level.txt,sha256=n0ex4gOJ1b_fARowcGqRzyOGZcHRhc5LZa6_vVgGxcI,14
20
+ kicad_sch_api-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+