kicad-sch-api 0.4.0__py3-none-any.whl → 0.4.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.

Files changed (57) hide show
  1. kicad_sch_api/__init__.py +2 -2
  2. kicad_sch_api/cli/__init__.py +45 -0
  3. kicad_sch_api/cli/base.py +302 -0
  4. kicad_sch_api/cli/bom.py +164 -0
  5. kicad_sch_api/cli/erc.py +229 -0
  6. kicad_sch_api/cli/export_docs.py +289 -0
  7. kicad_sch_api/cli/netlist.py +94 -0
  8. kicad_sch_api/cli/types.py +43 -0
  9. kicad_sch_api/core/collections/__init__.py +5 -0
  10. kicad_sch_api/core/collections/base.py +248 -0
  11. kicad_sch_api/core/component_bounds.py +5 -0
  12. kicad_sch_api/core/components.py +142 -47
  13. kicad_sch_api/core/config.py +85 -3
  14. kicad_sch_api/core/factories/__init__.py +5 -0
  15. kicad_sch_api/core/factories/element_factory.py +276 -0
  16. kicad_sch_api/core/formatter.py +22 -5
  17. kicad_sch_api/core/junctions.py +26 -75
  18. kicad_sch_api/core/labels.py +28 -52
  19. kicad_sch_api/core/managers/file_io.py +3 -2
  20. kicad_sch_api/core/managers/metadata.py +6 -5
  21. kicad_sch_api/core/managers/validation.py +3 -2
  22. kicad_sch_api/core/managers/wire.py +7 -1
  23. kicad_sch_api/core/nets.py +38 -43
  24. kicad_sch_api/core/no_connects.py +29 -53
  25. kicad_sch_api/core/parser.py +75 -1765
  26. kicad_sch_api/core/schematic.py +211 -148
  27. kicad_sch_api/core/texts.py +28 -55
  28. kicad_sch_api/core/types.py +59 -18
  29. kicad_sch_api/core/wires.py +27 -75
  30. kicad_sch_api/parsers/elements/__init__.py +22 -0
  31. kicad_sch_api/parsers/elements/graphics_parser.py +564 -0
  32. kicad_sch_api/parsers/elements/label_parser.py +194 -0
  33. kicad_sch_api/parsers/elements/library_parser.py +165 -0
  34. kicad_sch_api/parsers/elements/metadata_parser.py +58 -0
  35. kicad_sch_api/parsers/elements/sheet_parser.py +352 -0
  36. kicad_sch_api/parsers/elements/symbol_parser.py +313 -0
  37. kicad_sch_api/parsers/elements/text_parser.py +250 -0
  38. kicad_sch_api/parsers/elements/wire_parser.py +242 -0
  39. kicad_sch_api/parsers/utils.py +80 -0
  40. kicad_sch_api/validation/__init__.py +25 -0
  41. kicad_sch_api/validation/erc.py +171 -0
  42. kicad_sch_api/validation/erc_models.py +203 -0
  43. kicad_sch_api/validation/pin_matrix.py +243 -0
  44. kicad_sch_api/validation/validators.py +391 -0
  45. {kicad_sch_api-0.4.0.dist-info → kicad_sch_api-0.4.2.dist-info}/METADATA +17 -9
  46. kicad_sch_api-0.4.2.dist-info/RECORD +87 -0
  47. kicad_sch_api/core/manhattan_routing.py +0 -430
  48. kicad_sch_api/core/simple_manhattan.py +0 -228
  49. kicad_sch_api/core/wire_routing.py +0 -380
  50. kicad_sch_api/parsers/label_parser.py +0 -254
  51. kicad_sch_api/parsers/symbol_parser.py +0 -222
  52. kicad_sch_api/parsers/wire_parser.py +0 -99
  53. kicad_sch_api-0.4.0.dist-info/RECORD +0 -67
  54. {kicad_sch_api-0.4.0.dist-info → kicad_sch_api-0.4.2.dist-info}/WHEEL +0 -0
  55. {kicad_sch_api-0.4.0.dist-info → kicad_sch_api-0.4.2.dist-info}/entry_points.txt +0 -0
  56. {kicad_sch_api-0.4.0.dist-info → kicad_sch_api-0.4.2.dist-info}/licenses/LICENSE +0 -0
  57. {kicad_sch_api-0.4.0.dist-info → kicad_sch_api-0.4.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,229 @@
1
+ """Electrical Rule Check (ERC) functionality using kicad-cli."""
2
+
3
+ import json
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from kicad_sch_api.cli.base import KiCadExecutor
9
+ from kicad_sch_api.cli.types import ErcFormat, ErcSeverity, Units
10
+
11
+
12
+ @dataclass
13
+ class ErcViolation:
14
+ """Represents a single ERC violation."""
15
+ severity: str
16
+ type: str
17
+ description: str
18
+ sheet: str
19
+ position: Optional[Dict[str, float]] = None
20
+
21
+
22
+ @dataclass
23
+ class ErcReport:
24
+ """ERC report with violations and summary."""
25
+ violations: List[ErcViolation]
26
+ error_count: int
27
+ warning_count: int
28
+ exclusion_count: int
29
+ schematic_path: Path
30
+ raw_output: str
31
+
32
+ def has_errors(self) -> bool:
33
+ """Check if report contains any errors."""
34
+ return self.error_count > 0
35
+
36
+ def has_warnings(self) -> bool:
37
+ """Check if report contains any warnings."""
38
+ return self.warning_count > 0
39
+
40
+ def has_violations(self) -> bool:
41
+ """Check if report contains any violations."""
42
+ return len(self.violations) > 0
43
+
44
+ def get_errors(self) -> List[ErcViolation]:
45
+ """Get all error-level violations."""
46
+ return [v for v in self.violations if v.severity == "error"]
47
+
48
+ def get_warnings(self) -> List[ErcViolation]:
49
+ """Get all warning-level violations."""
50
+ return [v for v in self.violations if v.severity == "warning"]
51
+
52
+
53
+ def run_erc(
54
+ schematic_path: Path,
55
+ output_path: Optional[Path] = None,
56
+ format: ErcFormat = "json",
57
+ severity: ErcSeverity = "all",
58
+ units: Units = "mm",
59
+ exit_code_violations: bool = False,
60
+ variables: Optional[Dict[str, str]] = None,
61
+ executor: Optional[KiCadExecutor] = None,
62
+ ) -> ErcReport:
63
+ """
64
+ Run Electrical Rule Check (ERC) on schematic using kicad-cli.
65
+
66
+ Validates schematic for electrical errors like unconnected pins,
67
+ conflicting drivers, etc.
68
+
69
+ Args:
70
+ schematic_path: Path to .kicad_sch file
71
+ output_path: Output report path (auto-generated if None)
72
+ format: Report format ('json' or 'report')
73
+ severity: Severity levels to report ('all', 'error', 'warning', 'exclusions')
74
+ units: Measurement units for coordinates ('mm', 'in', 'mils')
75
+ exit_code_violations: Return non-zero exit code if violations exist
76
+ variables: Project variables to override (key=value pairs)
77
+ executor: Custom KiCadExecutor instance (creates default if None)
78
+
79
+ Returns:
80
+ ErcReport with violations and summary
81
+
82
+ Raises:
83
+ RuntimeError: If kicad-cli not found or ERC fails
84
+ FileNotFoundError: If schematic file doesn't exist
85
+
86
+ Example:
87
+ >>> from pathlib import Path
88
+ >>> report = run_erc(Path('circuit.kicad_sch'))
89
+ >>> if report.has_errors():
90
+ ... print(f"Found {report.error_count} errors:")
91
+ ... for error in report.get_errors():
92
+ ... print(f" - {error.description}")
93
+
94
+ >>> # Check for specific severity
95
+ >>> report = run_erc(
96
+ ... Path('circuit.kicad_sch'),
97
+ ... severity='error', # Only errors
98
+ ... )
99
+
100
+ >>> # Generate human-readable report
101
+ >>> report = run_erc(
102
+ ... Path('circuit.kicad_sch'),
103
+ ... format='report',
104
+ ... )
105
+ >>> print(report.raw_output)
106
+ """
107
+ schematic_path = Path(schematic_path)
108
+
109
+ if not schematic_path.exists():
110
+ raise FileNotFoundError(f"Schematic not found: {schematic_path}")
111
+
112
+ # Auto-generate output path if not provided
113
+ if output_path is None:
114
+ ext = ".json" if format == "json" else ".rpt"
115
+ output_path = schematic_path.with_stem(f"{schematic_path.stem}_erc").with_suffix(ext)
116
+ else:
117
+ output_path = Path(output_path)
118
+
119
+ # Create executor if not provided
120
+ if executor is None:
121
+ executor = KiCadExecutor()
122
+
123
+ # Build command
124
+ args = [
125
+ "sch", "erc",
126
+ "--output", str(output_path),
127
+ "--format", format,
128
+ "--units", units,
129
+ ]
130
+
131
+ # Add severity flags
132
+ if severity == "all":
133
+ args.append("--severity-all")
134
+ elif severity == "error":
135
+ args.append("--severity-error")
136
+ elif severity == "warning":
137
+ args.append("--severity-warning")
138
+ elif severity == "exclusions":
139
+ args.append("--severity-exclusions")
140
+
141
+ # Add optional parameters
142
+ if exit_code_violations:
143
+ args.append("--exit-code-violations")
144
+
145
+ if variables:
146
+ for key, value in variables.items():
147
+ args.extend(["--define-var", f"{key}={value}"])
148
+
149
+ # Add schematic path
150
+ args.append(str(schematic_path))
151
+
152
+ # Execute command (don't check return code if exit_code_violations is True)
153
+ result = executor.run(args, cwd=schematic_path.parent, check=not exit_code_violations)
154
+
155
+ # Read output file
156
+ output_content = output_path.read_text()
157
+
158
+ # Parse report
159
+ if format == "json":
160
+ report = _parse_json_report(output_content, schematic_path)
161
+ else:
162
+ report = _parse_text_report(output_content, schematic_path)
163
+
164
+ return report
165
+
166
+
167
+ def _parse_json_report(content: str, schematic_path: Path) -> ErcReport:
168
+ """Parse JSON ERC report."""
169
+ try:
170
+ data = json.loads(content)
171
+ except json.JSONDecodeError:
172
+ # If JSON parsing fails, return empty report
173
+ return ErcReport(
174
+ violations=[],
175
+ error_count=0,
176
+ warning_count=0,
177
+ exclusion_count=0,
178
+ schematic_path=schematic_path,
179
+ raw_output=content,
180
+ )
181
+
182
+ violations = []
183
+ error_count = 0
184
+ warning_count = 0
185
+ exclusion_count = 0
186
+
187
+ # Parse violations from JSON
188
+ for violation_data in data.get("violations", []):
189
+ violation = ErcViolation(
190
+ severity=violation_data.get("severity", "unknown"),
191
+ type=violation_data.get("type", "unknown"),
192
+ description=violation_data.get("description", ""),
193
+ sheet=violation_data.get("sheet", ""),
194
+ position=violation_data.get("position"),
195
+ )
196
+ violations.append(violation)
197
+
198
+ if violation.severity == "error":
199
+ error_count += 1
200
+ elif violation.severity == "warning":
201
+ warning_count += 1
202
+ elif violation.severity == "exclusion":
203
+ exclusion_count += 1
204
+
205
+ return ErcReport(
206
+ violations=violations,
207
+ error_count=error_count,
208
+ warning_count=warning_count,
209
+ exclusion_count=exclusion_count,
210
+ schematic_path=schematic_path,
211
+ raw_output=content,
212
+ )
213
+
214
+
215
+ def _parse_text_report(content: str, schematic_path: Path) -> ErcReport:
216
+ """Parse text ERC report."""
217
+ # For text reports, do simple counting
218
+ lines = content.split("\n")
219
+ error_count = sum(1 for line in lines if "error" in line.lower())
220
+ warning_count = sum(1 for line in lines if "warning" in line.lower())
221
+
222
+ return ErcReport(
223
+ violations=[], # Text format doesn't provide structured violations
224
+ error_count=error_count,
225
+ warning_count=warning_count,
226
+ exclusion_count=0,
227
+ schematic_path=schematic_path,
228
+ raw_output=content,
229
+ )
@@ -0,0 +1,289 @@
1
+ """Document export functionality (PDF, SVG, DXF) using kicad-cli."""
2
+
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional
5
+
6
+ from kicad_sch_api.cli.base import KiCadExecutor
7
+
8
+
9
+ def export_pdf(
10
+ schematic_path: Path,
11
+ output_path: Optional[Path] = None,
12
+ theme: Optional[str] = None,
13
+ black_and_white: bool = False,
14
+ drawing_sheet: Optional[Path] = None,
15
+ exclude_drawing_sheet: bool = False,
16
+ default_font: str = "KiCad Font",
17
+ exclude_pdf_property_popups: bool = False,
18
+ exclude_pdf_hierarchical_links: bool = False,
19
+ exclude_pdf_metadata: bool = False,
20
+ no_background_color: bool = False,
21
+ pages: Optional[List[int]] = None,
22
+ variables: Optional[Dict[str, str]] = None,
23
+ executor: Optional[KiCadExecutor] = None,
24
+ ) -> Path:
25
+ """
26
+ Export schematic as PDF using kicad-cli.
27
+
28
+ Args:
29
+ schematic_path: Path to .kicad_sch file
30
+ output_path: Output PDF path (auto-generated if None)
31
+ theme: Color theme to use (default: schematic settings)
32
+ black_and_white: Export in black and white
33
+ drawing_sheet: Path to custom drawing sheet
34
+ exclude_drawing_sheet: Don't include drawing sheet
35
+ default_font: Default font name (default: "KiCad Font")
36
+ exclude_pdf_property_popups: Don't generate property popups
37
+ exclude_pdf_hierarchical_links: Don't generate clickable hierarchical links
38
+ exclude_pdf_metadata: Don't generate PDF metadata from variables
39
+ no_background_color: Don't set background color
40
+ pages: List of page numbers to export (None = all pages)
41
+ variables: Project variables to override
42
+ executor: Custom KiCadExecutor instance
43
+
44
+ Returns:
45
+ Path to generated PDF file
46
+
47
+ Example:
48
+ >>> from pathlib import Path
49
+ >>> pdf = export_pdf(
50
+ ... Path('circuit.kicad_sch'),
51
+ ... theme='KiCad Classic',
52
+ ... )
53
+ """
54
+ schematic_path = Path(schematic_path)
55
+
56
+ if not schematic_path.exists():
57
+ raise FileNotFoundError(f"Schematic not found: {schematic_path}")
58
+
59
+ if output_path is None:
60
+ output_path = schematic_path.with_suffix(".pdf")
61
+ else:
62
+ output_path = Path(output_path)
63
+
64
+ if executor is None:
65
+ executor = KiCadExecutor()
66
+
67
+ # Build command
68
+ args = ["sch", "export", "pdf", "--output", str(output_path)]
69
+
70
+ if theme:
71
+ args.extend(["--theme", theme])
72
+
73
+ if black_and_white:
74
+ args.append("--black-and-white")
75
+
76
+ if drawing_sheet:
77
+ args.extend(["--drawing-sheet", str(drawing_sheet)])
78
+
79
+ if exclude_drawing_sheet:
80
+ args.append("--exclude-drawing-sheet")
81
+
82
+ args.extend(["--default-font", default_font])
83
+
84
+ if exclude_pdf_property_popups:
85
+ args.append("--exclude-pdf-property-popups")
86
+
87
+ if exclude_pdf_hierarchical_links:
88
+ args.append("--exclude-pdf-hierarchical-links")
89
+
90
+ if exclude_pdf_metadata:
91
+ args.append("--exclude-pdf-metadata")
92
+
93
+ if no_background_color:
94
+ args.append("--no-background-color")
95
+
96
+ if pages:
97
+ args.extend(["--pages", ",".join(map(str, pages))])
98
+
99
+ if variables:
100
+ for key, value in variables.items():
101
+ args.extend(["--define-var", f"{key}={value}"])
102
+
103
+ args.append(str(schematic_path))
104
+
105
+ # Execute command
106
+ executor.run(args, cwd=schematic_path.parent)
107
+
108
+ return output_path
109
+
110
+
111
+ def export_svg(
112
+ schematic_path: Path,
113
+ output_dir: Optional[Path] = None,
114
+ theme: Optional[str] = None,
115
+ black_and_white: bool = False,
116
+ drawing_sheet: Optional[Path] = None,
117
+ exclude_drawing_sheet: bool = False,
118
+ default_font: str = "KiCad Font",
119
+ no_background_color: bool = False,
120
+ pages: Optional[List[int]] = None,
121
+ variables: Optional[Dict[str, str]] = None,
122
+ executor: Optional[KiCadExecutor] = None,
123
+ ) -> List[Path]:
124
+ """
125
+ Export schematic as SVG using kicad-cli.
126
+
127
+ Args:
128
+ schematic_path: Path to .kicad_sch file
129
+ output_dir: Output directory (default: schematic directory)
130
+ theme: Color theme to use (default: schematic settings)
131
+ black_and_white: Export in black and white
132
+ drawing_sheet: Path to custom drawing sheet
133
+ exclude_drawing_sheet: Don't include drawing sheet
134
+ default_font: Default font name (default: "KiCad Font")
135
+ no_background_color: Don't set background color
136
+ pages: List of page numbers to export (None = all pages)
137
+ variables: Project variables to override
138
+ executor: Custom KiCadExecutor instance
139
+
140
+ Returns:
141
+ List of paths to generated SVG files
142
+
143
+ Example:
144
+ >>> from pathlib import Path
145
+ >>> svgs = export_svg(
146
+ ... Path('circuit.kicad_sch'),
147
+ ... theme='KiCad Classic',
148
+ ... )
149
+ >>> for svg in svgs:
150
+ ... print(f"Generated: {svg}")
151
+ """
152
+ schematic_path = Path(schematic_path)
153
+
154
+ if not schematic_path.exists():
155
+ raise FileNotFoundError(f"Schematic not found: {schematic_path}")
156
+
157
+ if output_dir is None:
158
+ output_dir = schematic_path.parent
159
+ else:
160
+ output_dir = Path(output_dir)
161
+ output_dir.mkdir(parents=True, exist_ok=True)
162
+
163
+ if executor is None:
164
+ executor = KiCadExecutor()
165
+
166
+ # Build command
167
+ args = ["sch", "export", "svg", "--output", str(output_dir)]
168
+
169
+ if theme:
170
+ args.extend(["--theme", theme])
171
+
172
+ if black_and_white:
173
+ args.append("--black-and-white")
174
+
175
+ if drawing_sheet:
176
+ args.extend(["--drawing-sheet", str(drawing_sheet)])
177
+
178
+ if exclude_drawing_sheet:
179
+ args.append("--exclude-drawing-sheet")
180
+
181
+ args.extend(["--default-font", default_font])
182
+
183
+ if no_background_color:
184
+ args.append("--no-background-color")
185
+
186
+ if pages:
187
+ args.extend(["--pages", ",".join(map(str, pages))])
188
+
189
+ if variables:
190
+ for key, value in variables.items():
191
+ args.extend(["--define-var", f"{key}={value}"])
192
+
193
+ args.append(str(schematic_path))
194
+
195
+ # Execute command
196
+ executor.run(args, cwd=schematic_path.parent)
197
+
198
+ # Find generated SVG files
199
+ svg_files = list(output_dir.glob(f"{schematic_path.stem}*.svg"))
200
+
201
+ return svg_files
202
+
203
+
204
+ def export_dxf(
205
+ schematic_path: Path,
206
+ output_dir: Optional[Path] = None,
207
+ theme: Optional[str] = None,
208
+ black_and_white: bool = False,
209
+ drawing_sheet: Optional[Path] = None,
210
+ exclude_drawing_sheet: bool = False,
211
+ default_font: str = "KiCad Font",
212
+ no_background_color: bool = False,
213
+ pages: Optional[List[int]] = None,
214
+ variables: Optional[Dict[str, str]] = None,
215
+ executor: Optional[KiCadExecutor] = None,
216
+ ) -> List[Path]:
217
+ """
218
+ Export schematic as DXF using kicad-cli.
219
+
220
+ Args:
221
+ schematic_path: Path to .kicad_sch file
222
+ output_dir: Output directory (default: schematic directory)
223
+ theme: Color theme to use (default: schematic settings)
224
+ black_and_white: Export in black and white
225
+ drawing_sheet: Path to custom drawing sheet
226
+ exclude_drawing_sheet: Don't include drawing sheet
227
+ default_font: Default font name (default: "KiCad Font")
228
+ no_background_color: Don't set background color
229
+ pages: List of page numbers to export (None = all pages)
230
+ variables: Project variables to override
231
+ executor: Custom KiCadExecutor instance
232
+
233
+ Returns:
234
+ List of paths to generated DXF files
235
+
236
+ Example:
237
+ >>> from pathlib import Path
238
+ >>> dxfs = export_dxf(Path('circuit.kicad_sch'))
239
+ """
240
+ schematic_path = Path(schematic_path)
241
+
242
+ if not schematic_path.exists():
243
+ raise FileNotFoundError(f"Schematic not found: {schematic_path}")
244
+
245
+ if output_dir is None:
246
+ output_dir = schematic_path.parent
247
+ else:
248
+ output_dir = Path(output_dir)
249
+ output_dir.mkdir(parents=True, exist_ok=True)
250
+
251
+ if executor is None:
252
+ executor = KiCadExecutor()
253
+
254
+ # Build command
255
+ args = ["sch", "export", "dxf", "--output", str(output_dir)]
256
+
257
+ if theme:
258
+ args.extend(["--theme", theme])
259
+
260
+ if black_and_white:
261
+ args.append("--black-and-white")
262
+
263
+ if drawing_sheet:
264
+ args.extend(["--drawing-sheet", str(drawing_sheet)])
265
+
266
+ if exclude_drawing_sheet:
267
+ args.append("--exclude-drawing-sheet")
268
+
269
+ args.extend(["--default-font", default_font])
270
+
271
+ if no_background_color:
272
+ args.append("--no-background-color")
273
+
274
+ if pages:
275
+ args.extend(["--pages", ",".join(map(str, pages))])
276
+
277
+ if variables:
278
+ for key, value in variables.items():
279
+ args.extend(["--define-var", f"{key}={value}"])
280
+
281
+ args.append(str(schematic_path))
282
+
283
+ # Execute command
284
+ executor.run(args, cwd=schematic_path.parent)
285
+
286
+ # Find generated DXF files
287
+ dxf_files = list(output_dir.glob(f"{schematic_path.stem}*.dxf"))
288
+
289
+ return dxf_files
@@ -0,0 +1,94 @@
1
+ """Netlist export functionality using kicad-cli."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ from kicad_sch_api.cli.base import KiCadExecutor
7
+ from kicad_sch_api.cli.types import NetlistFormat
8
+
9
+
10
+ def export_netlist(
11
+ schematic_path: Path,
12
+ output_path: Optional[Path] = None,
13
+ format: NetlistFormat = "kicadsexpr",
14
+ executor: Optional[KiCadExecutor] = None,
15
+ ) -> Path:
16
+ """
17
+ Export netlist from schematic using kicad-cli.
18
+
19
+ Supports 8 different netlist formats for PCB layout and simulation.
20
+
21
+ Args:
22
+ schematic_path: Path to .kicad_sch file
23
+ output_path: Output netlist path (auto-generated if None)
24
+ format: Netlist format (see NetlistFormat for options)
25
+ executor: Custom KiCadExecutor instance (creates default if None)
26
+
27
+ Returns:
28
+ Path to generated netlist file
29
+
30
+ Raises:
31
+ RuntimeError: If kicad-cli not found or netlist generation fails
32
+ FileNotFoundError: If schematic file doesn't exist
33
+
34
+ Example:
35
+ >>> from pathlib import Path
36
+ >>> netlist = export_netlist(
37
+ ... Path('circuit.kicad_sch'),
38
+ ... format='spice'
39
+ ... )
40
+ >>> print(f"Netlist: {netlist}")
41
+
42
+ Supported formats:
43
+ - kicadsexpr: KiCad S-expression netlist (default)
44
+ - kicadxml: KiCad XML netlist
45
+ - cadstar: Cadstar format
46
+ - orcadpcb2: OrCAD PCB2 format
47
+ - spice: SPICE netlist
48
+ - spicemodel: SPICE with models
49
+ - pads: PADS format
50
+ - allegro: Allegro format
51
+ """
52
+ schematic_path = Path(schematic_path)
53
+
54
+ if not schematic_path.exists():
55
+ raise FileNotFoundError(f"Schematic not found: {schematic_path}")
56
+
57
+ # Auto-generate output path if not provided
58
+ if output_path is None:
59
+ ext = _get_extension_for_format(format)
60
+ output_path = schematic_path.with_suffix(ext)
61
+ else:
62
+ output_path = Path(output_path)
63
+
64
+ # Create executor if not provided
65
+ if executor is None:
66
+ executor = KiCadExecutor()
67
+
68
+ # Build command
69
+ args = [
70
+ "sch", "export", "netlist",
71
+ "--format", format,
72
+ "--output", str(output_path),
73
+ str(schematic_path),
74
+ ]
75
+
76
+ # Execute command
77
+ executor.run(args, cwd=schematic_path.parent)
78
+
79
+ return output_path
80
+
81
+
82
+ def _get_extension_for_format(format: NetlistFormat) -> str:
83
+ """Get file extension for netlist format."""
84
+ extensions = {
85
+ "kicadsexpr": ".net",
86
+ "kicadxml": ".xml",
87
+ "cadstar": ".frp",
88
+ "orcadpcb2": ".net",
89
+ "spice": ".cir",
90
+ "spicemodel": ".cir",
91
+ "pads": ".asc",
92
+ "allegro": ".alg",
93
+ }
94
+ return extensions.get(format, ".net")
@@ -0,0 +1,43 @@
1
+ """Type definitions for KiCad CLI operations."""
2
+
3
+ from typing import Literal
4
+
5
+ # Netlist export formats
6
+ NetlistFormat = Literal[
7
+ "kicadsexpr", # KiCad S-expression netlist (default)
8
+ "kicadxml", # KiCad XML netlist
9
+ "cadstar", # Cadstar format
10
+ "orcadpcb2", # OrCAD PCB2 format
11
+ "spice", # SPICE netlist
12
+ "spicemodel", # SPICE with models
13
+ "pads", # PADS format
14
+ "allegro", # Allegro format
15
+ ]
16
+
17
+ # ERC (Electrical Rule Check) formats
18
+ ErcFormat = Literal[
19
+ "json", # JSON format (machine-readable)
20
+ "report", # Human-readable text report
21
+ ]
22
+
23
+ # ERC severity levels
24
+ ErcSeverity = Literal[
25
+ "all", # Report all violations
26
+ "error", # Error level only
27
+ "warning", # Warning level only
28
+ "exclusions", # Excluded violations only
29
+ ]
30
+
31
+ # Units for measurements
32
+ Units = Literal[
33
+ "mm", # Millimeters (default)
34
+ "in", # Inches
35
+ "mils", # Mils (1/1000 inch)
36
+ ]
37
+
38
+ # Execution modes
39
+ ExecutionMode = Literal[
40
+ "auto", # Auto-detect (try local, fall back to Docker)
41
+ "local", # Force local kicad-cli
42
+ "docker", # Force Docker mode
43
+ ]
@@ -0,0 +1,5 @@
1
+ """Collection base classes for schematic elements."""
2
+
3
+ from .base import BaseCollection
4
+
5
+ __all__ = ["BaseCollection"]