kicad-sch-api 0.3.5__py3-none-any.whl → 0.4.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.
Files changed (81) 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/collections/__init__.py +2 -2
  10. kicad_sch_api/collections/base.py +5 -7
  11. kicad_sch_api/collections/components.py +24 -12
  12. kicad_sch_api/collections/junctions.py +31 -43
  13. kicad_sch_api/collections/labels.py +19 -27
  14. kicad_sch_api/collections/wires.py +17 -18
  15. kicad_sch_api/core/collections/__init__.py +5 -0
  16. kicad_sch_api/core/collections/base.py +248 -0
  17. kicad_sch_api/core/component_bounds.py +5 -0
  18. kicad_sch_api/core/components.py +67 -45
  19. kicad_sch_api/core/config.py +85 -3
  20. kicad_sch_api/core/factories/__init__.py +5 -0
  21. kicad_sch_api/core/factories/element_factory.py +276 -0
  22. kicad_sch_api/core/formatter.py +3 -1
  23. kicad_sch_api/core/junctions.py +26 -75
  24. kicad_sch_api/core/labels.py +29 -53
  25. kicad_sch_api/core/managers/__init__.py +26 -0
  26. kicad_sch_api/core/managers/file_io.py +244 -0
  27. kicad_sch_api/core/managers/format_sync.py +501 -0
  28. kicad_sch_api/core/managers/graphics.py +579 -0
  29. kicad_sch_api/core/managers/metadata.py +269 -0
  30. kicad_sch_api/core/managers/sheet.py +454 -0
  31. kicad_sch_api/core/managers/text_elements.py +536 -0
  32. kicad_sch_api/core/managers/validation.py +475 -0
  33. kicad_sch_api/core/managers/wire.py +352 -0
  34. kicad_sch_api/core/nets.py +38 -43
  35. kicad_sch_api/core/no_connects.py +33 -55
  36. kicad_sch_api/core/parser.py +75 -1731
  37. kicad_sch_api/core/schematic.py +951 -1192
  38. kicad_sch_api/core/texts.py +28 -55
  39. kicad_sch_api/core/types.py +60 -22
  40. kicad_sch_api/core/wires.py +27 -75
  41. kicad_sch_api/geometry/font_metrics.py +3 -1
  42. kicad_sch_api/geometry/symbol_bbox.py +40 -21
  43. kicad_sch_api/interfaces/__init__.py +1 -1
  44. kicad_sch_api/interfaces/parser.py +1 -1
  45. kicad_sch_api/interfaces/repository.py +1 -1
  46. kicad_sch_api/interfaces/resolver.py +1 -1
  47. kicad_sch_api/parsers/__init__.py +2 -2
  48. kicad_sch_api/parsers/base.py +7 -10
  49. kicad_sch_api/parsers/elements/__init__.py +22 -0
  50. kicad_sch_api/parsers/elements/graphics_parser.py +564 -0
  51. kicad_sch_api/parsers/elements/label_parser.py +194 -0
  52. kicad_sch_api/parsers/elements/library_parser.py +165 -0
  53. kicad_sch_api/parsers/elements/metadata_parser.py +58 -0
  54. kicad_sch_api/parsers/elements/sheet_parser.py +352 -0
  55. kicad_sch_api/parsers/elements/symbol_parser.py +313 -0
  56. kicad_sch_api/parsers/elements/text_parser.py +250 -0
  57. kicad_sch_api/parsers/elements/wire_parser.py +242 -0
  58. kicad_sch_api/parsers/registry.py +4 -2
  59. kicad_sch_api/parsers/utils.py +80 -0
  60. kicad_sch_api/symbols/__init__.py +1 -1
  61. kicad_sch_api/symbols/cache.py +9 -12
  62. kicad_sch_api/symbols/resolver.py +20 -26
  63. kicad_sch_api/symbols/validators.py +188 -137
  64. kicad_sch_api/validation/__init__.py +25 -0
  65. kicad_sch_api/validation/erc.py +171 -0
  66. kicad_sch_api/validation/erc_models.py +203 -0
  67. kicad_sch_api/validation/pin_matrix.py +243 -0
  68. kicad_sch_api/validation/validators.py +391 -0
  69. {kicad_sch_api-0.3.5.dist-info → kicad_sch_api-0.4.1.dist-info}/METADATA +17 -9
  70. kicad_sch_api-0.4.1.dist-info/RECORD +87 -0
  71. kicad_sch_api/core/manhattan_routing.py +0 -430
  72. kicad_sch_api/core/simple_manhattan.py +0 -228
  73. kicad_sch_api/core/wire_routing.py +0 -380
  74. kicad_sch_api/parsers/label_parser.py +0 -254
  75. kicad_sch_api/parsers/symbol_parser.py +0 -227
  76. kicad_sch_api/parsers/wire_parser.py +0 -99
  77. kicad_sch_api-0.3.5.dist-info/RECORD +0 -58
  78. {kicad_sch_api-0.3.5.dist-info → kicad_sch_api-0.4.1.dist-info}/WHEEL +0 -0
  79. {kicad_sch_api-0.3.5.dist-info → kicad_sch_api-0.4.1.dist-info}/entry_points.txt +0 -0
  80. {kicad_sch_api-0.3.5.dist-info → kicad_sch_api-0.4.1.dist-info}/licenses/LICENSE +0 -0
  81. {kicad_sch_api-0.3.5.dist-info → kicad_sch_api-0.4.1.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,8 @@ import uuid
10
10
  from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Union
11
11
 
12
12
  from ..utils.validation import SchematicValidator, ValidationError, ValidationIssue
13
- from .types import Point, NoConnect
13
+ from .collections import BaseCollection
14
+ from .types import NoConnect, Point
14
15
 
15
16
  logger = logging.getLogger(__name__)
16
17
 
@@ -72,10 +73,13 @@ class NoConnectElement:
72
73
  return f"<NoConnect @ {self.position}>"
73
74
 
74
75
 
75
- class NoConnectCollection:
76
+ class NoConnectCollection(BaseCollection[NoConnectElement]):
76
77
  """
77
78
  Collection class for efficient no-connect element management.
78
79
 
80
+ Inherits from BaseCollection for standard operations and adds no-connect-specific
81
+ functionality including position-based indexing.
82
+
79
83
  Provides fast lookup, filtering, and bulk operations for schematic no-connect elements.
80
84
  """
81
85
 
@@ -86,18 +90,17 @@ class NoConnectCollection:
86
90
  Args:
87
91
  no_connects: Initial list of no-connect data
88
92
  """
89
- self._no_connects: List[NoConnectElement] = []
90
- self._uuid_index: Dict[str, NoConnectElement] = {}
93
+ # Initialize base collection
94
+ super().__init__([], collection_name="no_connects")
95
+
96
+ # Additional no-connect-specific index
91
97
  self._position_index: Dict[Tuple[float, float], List[NoConnectElement]] = {}
92
- self._modified = False
93
98
 
94
99
  # Add initial no-connects
95
100
  if no_connects:
96
101
  for no_connect_data in no_connects:
97
102
  self._add_to_indexes(NoConnectElement(no_connect_data, self))
98
103
 
99
- logger.debug(f"NoConnectCollection initialized with {len(self._no_connects)} no-connects")
100
-
101
104
  def add(
102
105
  self,
103
106
  position: Union[Point, Tuple[float, float]],
@@ -144,9 +147,7 @@ class NoConnectCollection:
144
147
  logger.debug(f"Added no-connect: {no_connect_element}")
145
148
  return no_connect_element
146
149
 
147
- def get(self, no_connect_uuid: str) -> Optional[NoConnectElement]:
148
- """Get no-connect by UUID."""
149
- return self._uuid_index.get(no_connect_uuid)
150
+ # get() method inherited from BaseCollection
150
151
 
151
152
  def remove(self, no_connect_uuid: str) -> bool:
152
153
  """
@@ -158,18 +159,26 @@ class NoConnectCollection:
158
159
  Returns:
159
160
  True if no-connect was removed, False if not found
160
161
  """
161
- no_connect_element = self._uuid_index.get(no_connect_uuid)
162
+ no_connect_element = self.get(no_connect_uuid)
162
163
  if not no_connect_element:
163
164
  return False
164
165
 
165
- # Remove from indexes
166
- self._remove_from_indexes(no_connect_element)
167
- self._mark_modified()
166
+ # Remove from position index
167
+ pos_key = (no_connect_element.position.x, no_connect_element.position.y)
168
+ if pos_key in self._position_index:
169
+ self._position_index[pos_key].remove(no_connect_element)
170
+ if not self._position_index[pos_key]:
171
+ del self._position_index[pos_key]
172
+
173
+ # Remove using base class method
174
+ super().remove(no_connect_uuid)
168
175
 
169
176
  logger.debug(f"Removed no-connect: {no_connect_element}")
170
177
  return True
171
178
 
172
- def find_at_position(self, position: Union[Point, Tuple[float, float]], tolerance: float = 0.1) -> List[NoConnectElement]:
179
+ def find_at_position(
180
+ self, position: Union[Point, Tuple[float, float]], tolerance: float = 0.1
181
+ ) -> List[NoConnectElement]:
173
182
  """
174
183
  Find no-connects at or near a position.
175
184
 
@@ -184,7 +193,7 @@ class NoConnectCollection:
184
193
  position = Point(position[0], position[1])
185
194
 
186
195
  matches = []
187
- for no_connect_element in self._no_connects:
196
+ for no_connect_element in self._items:
188
197
  distance = no_connect_element.position.distance_to(position)
189
198
  if distance <= tolerance:
190
199
  matches.append(no_connect_element)
@@ -192,7 +201,7 @@ class NoConnectCollection:
192
201
 
193
202
  def filter(self, predicate: Callable[[NoConnectElement], bool]) -> List[NoConnectElement]:
194
203
  """
195
- Filter no-connects by predicate function.
204
+ Filter no-connects by predicate function (delegates to base class find).
196
205
 
197
206
  Args:
198
207
  predicate: Function that returns True for no-connects to include
@@ -200,7 +209,7 @@ class NoConnectCollection:
200
209
  Returns:
201
210
  List of no-connects matching predicate
202
211
  """
203
- return [no_connect for no_connect in self._no_connects if predicate(no_connect)]
212
+ return self.find(predicate)
204
213
 
205
214
  def bulk_update(self, criteria: Callable[[NoConnectElement], bool], updates: Dict[str, Any]):
206
215
  """
@@ -211,7 +220,7 @@ class NoConnectCollection:
211
220
  updates: Dictionary of property updates
212
221
  """
213
222
  updated_count = 0
214
- for no_connect_element in self._no_connects:
223
+ for no_connect_element in self._items:
215
224
  if criteria(no_connect_element):
216
225
  for prop, value in updates.items():
217
226
  if hasattr(no_connect_element, prop):
@@ -224,15 +233,12 @@ class NoConnectCollection:
224
233
 
225
234
  def clear(self):
226
235
  """Remove all no-connects from collection."""
227
- self._no_connects.clear()
228
- self._uuid_index.clear()
229
236
  self._position_index.clear()
230
- self._mark_modified()
237
+ super().clear()
231
238
 
232
239
  def _add_to_indexes(self, no_connect_element: NoConnectElement):
233
- """Add no-connect to internal indexes."""
234
- self._no_connects.append(no_connect_element)
235
- self._uuid_index[no_connect_element.uuid] = no_connect_element
240
+ """Add no-connect to internal indexes (base + position index)."""
241
+ self._add_item(no_connect_element)
236
242
 
237
243
  # Add to position index
238
244
  pos_key = (no_connect_element.position.x, no_connect_element.position.y)
@@ -240,35 +246,7 @@ class NoConnectCollection:
240
246
  self._position_index[pos_key] = []
241
247
  self._position_index[pos_key].append(no_connect_element)
242
248
 
243
- def _remove_from_indexes(self, no_connect_element: NoConnectElement):
244
- """Remove no-connect from internal indexes."""
245
- self._no_connects.remove(no_connect_element)
246
- del self._uuid_index[no_connect_element.uuid]
247
-
248
- # Remove from position index
249
- pos_key = (no_connect_element.position.x, no_connect_element.position.y)
250
- if pos_key in self._position_index:
251
- self._position_index[pos_key].remove(no_connect_element)
252
- if not self._position_index[pos_key]:
253
- del self._position_index[pos_key]
254
-
255
- def _mark_modified(self):
256
- """Mark collection as modified."""
257
- self._modified = True
258
-
259
- # Collection interface methods
260
- def __len__(self) -> int:
261
- """Return number of no-connects."""
262
- return len(self._no_connects)
263
-
264
- def __iter__(self) -> Iterator[NoConnectElement]:
265
- """Iterate over no-connects."""
266
- return iter(self._no_connects)
267
-
268
- def __getitem__(self, index: int) -> NoConnectElement:
269
- """Get no-connect by index."""
270
- return self._no_connects[index]
271
-
249
+ # Collection interface methods - __len__, __iter__, __getitem__ inherited from BaseCollection
272
250
  def __bool__(self) -> bool:
273
251
  """Return True if collection has no-connects."""
274
- return len(self._no_connects) > 0
252
+ return len(self._items) > 0