kicad-sch-api 0.3.4__py3-none-any.whl → 0.4.0__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/collections/__init__.py +21 -0
- kicad_sch_api/collections/base.py +294 -0
- kicad_sch_api/collections/components.py +434 -0
- kicad_sch_api/collections/junctions.py +366 -0
- kicad_sch_api/collections/labels.py +404 -0
- kicad_sch_api/collections/wires.py +406 -0
- kicad_sch_api/core/components.py +5 -0
- kicad_sch_api/core/formatter.py +3 -1
- kicad_sch_api/core/labels.py +348 -0
- kicad_sch_api/core/managers/__init__.py +26 -0
- kicad_sch_api/core/managers/file_io.py +243 -0
- kicad_sch_api/core/managers/format_sync.py +501 -0
- kicad_sch_api/core/managers/graphics.py +579 -0
- kicad_sch_api/core/managers/metadata.py +268 -0
- kicad_sch_api/core/managers/sheet.py +454 -0
- kicad_sch_api/core/managers/text_elements.py +536 -0
- kicad_sch_api/core/managers/validation.py +474 -0
- kicad_sch_api/core/managers/wire.py +346 -0
- kicad_sch_api/core/nets.py +310 -0
- kicad_sch_api/core/no_connects.py +276 -0
- kicad_sch_api/core/parser.py +75 -41
- kicad_sch_api/core/schematic.py +904 -1074
- kicad_sch_api/core/texts.py +343 -0
- kicad_sch_api/core/types.py +13 -4
- kicad_sch_api/geometry/font_metrics.py +3 -1
- kicad_sch_api/geometry/symbol_bbox.py +56 -43
- kicad_sch_api/interfaces/__init__.py +17 -0
- kicad_sch_api/interfaces/parser.py +76 -0
- kicad_sch_api/interfaces/repository.py +70 -0
- kicad_sch_api/interfaces/resolver.py +117 -0
- kicad_sch_api/parsers/__init__.py +14 -0
- kicad_sch_api/parsers/base.py +145 -0
- kicad_sch_api/parsers/label_parser.py +254 -0
- kicad_sch_api/parsers/registry.py +155 -0
- kicad_sch_api/parsers/symbol_parser.py +222 -0
- kicad_sch_api/parsers/wire_parser.py +99 -0
- kicad_sch_api/symbols/__init__.py +18 -0
- kicad_sch_api/symbols/cache.py +467 -0
- kicad_sch_api/symbols/resolver.py +361 -0
- kicad_sch_api/symbols/validators.py +504 -0
- {kicad_sch_api-0.3.4.dist-info → kicad_sch_api-0.4.0.dist-info}/METADATA +1 -1
- kicad_sch_api-0.4.0.dist-info/RECORD +67 -0
- kicad_sch_api-0.3.4.dist-info/RECORD +0 -34
- {kicad_sch_api-0.3.4.dist-info → kicad_sch_api-0.4.0.dist-info}/WHEEL +0 -0
- {kicad_sch_api-0.3.4.dist-info → kicad_sch_api-0.4.0.dist-info}/entry_points.txt +0 -0
- {kicad_sch_api-0.3.4.dist-info → kicad_sch_api-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {kicad_sch_api-0.3.4.dist-info → kicad_sch_api-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sheet Manager for KiCAD hierarchical sheet operations.
|
|
3
|
+
|
|
4
|
+
Handles hierarchical sheet management, sheet pin connections, and
|
|
5
|
+
multi-sheet project coordination while maintaining sheet instance tracking.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import uuid
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
12
|
+
|
|
13
|
+
from ..types import Point
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SheetManager:
|
|
19
|
+
"""
|
|
20
|
+
Manages hierarchical sheets and multi-sheet project coordination.
|
|
21
|
+
|
|
22
|
+
Responsible for:
|
|
23
|
+
- Sheet creation and management
|
|
24
|
+
- Sheet pin connections
|
|
25
|
+
- Sheet instance tracking
|
|
26
|
+
- Hierarchical navigation
|
|
27
|
+
- Sheet file references
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, schematic_data: Dict[str, Any]):
|
|
31
|
+
"""
|
|
32
|
+
Initialize SheetManager.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
schematic_data: Reference to schematic data
|
|
36
|
+
"""
|
|
37
|
+
self._data = schematic_data
|
|
38
|
+
|
|
39
|
+
def add_sheet(
|
|
40
|
+
self,
|
|
41
|
+
name: str,
|
|
42
|
+
filename: str,
|
|
43
|
+
position: Union[Point, Tuple[float, float]],
|
|
44
|
+
size: Union[Point, Tuple[float, float]],
|
|
45
|
+
uuid_str: Optional[str] = None,
|
|
46
|
+
sheet_pins: Optional[List[Dict[str, Any]]] = None,
|
|
47
|
+
stroke_width: Optional[float] = None,
|
|
48
|
+
stroke_type: str = "solid",
|
|
49
|
+
project_name: Optional[str] = None,
|
|
50
|
+
page_number: Optional[str] = None,
|
|
51
|
+
) -> str:
|
|
52
|
+
"""
|
|
53
|
+
Add a hierarchical sheet to the schematic.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
name: Sheet name/title
|
|
57
|
+
filename: Referenced schematic filename
|
|
58
|
+
position: Sheet position (top-left corner)
|
|
59
|
+
size: Sheet size (width, height)
|
|
60
|
+
uuid_str: Optional UUID
|
|
61
|
+
sheet_pins: Optional list of sheet pins
|
|
62
|
+
stroke_width: Border stroke width
|
|
63
|
+
stroke_type: Border stroke type (solid, dashed, etc.)
|
|
64
|
+
project_name: Project name for this sheet
|
|
65
|
+
page_number: Page number for this sheet
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
UUID of created sheet
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(position, tuple):
|
|
71
|
+
position = Point(position[0], position[1])
|
|
72
|
+
if isinstance(size, tuple):
|
|
73
|
+
size = Point(size[0], size[1])
|
|
74
|
+
|
|
75
|
+
if uuid_str is None:
|
|
76
|
+
uuid_str = str(uuid.uuid4())
|
|
77
|
+
|
|
78
|
+
if sheet_pins is None:
|
|
79
|
+
sheet_pins = []
|
|
80
|
+
|
|
81
|
+
# Validate filename
|
|
82
|
+
if not filename.endswith(".kicad_sch"):
|
|
83
|
+
filename = f"{filename}.kicad_sch"
|
|
84
|
+
|
|
85
|
+
sheet_data = {
|
|
86
|
+
"uuid": uuid_str,
|
|
87
|
+
"position": {"x": position.x, "y": position.y},
|
|
88
|
+
"size": {"width": size.x, "height": size.y},
|
|
89
|
+
"stroke_width": stroke_width if stroke_width is not None else 0.1524,
|
|
90
|
+
"stroke_type": stroke_type,
|
|
91
|
+
"fill_color": (0, 0, 0, 0.0),
|
|
92
|
+
"name": name,
|
|
93
|
+
"filename": filename,
|
|
94
|
+
"exclude_from_sim": False,
|
|
95
|
+
"in_bom": True,
|
|
96
|
+
"on_board": True,
|
|
97
|
+
"dnp": False,
|
|
98
|
+
"fields_autoplaced": True,
|
|
99
|
+
"pins": [],
|
|
100
|
+
"project_name": project_name,
|
|
101
|
+
"page_number": page_number if page_number else "2",
|
|
102
|
+
"instances": [
|
|
103
|
+
{"project": project_name, "path": f"/{uuid_str}", "reference": name, "unit": 1}
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Add sheet pins if provided (though usually added separately)
|
|
108
|
+
if sheet_pins:
|
|
109
|
+
sheet_data["pins"] = sheet_pins
|
|
110
|
+
|
|
111
|
+
# Add to schematic data
|
|
112
|
+
if "sheets" not in self._data:
|
|
113
|
+
self._data["sheets"] = []
|
|
114
|
+
self._data["sheets"].append(sheet_data)
|
|
115
|
+
|
|
116
|
+
logger.debug(f"Added sheet '{name}' ({filename}) at {position}")
|
|
117
|
+
return uuid_str
|
|
118
|
+
|
|
119
|
+
def add_sheet_pin(
|
|
120
|
+
self,
|
|
121
|
+
sheet_uuid: str,
|
|
122
|
+
name: str,
|
|
123
|
+
pin_type: str,
|
|
124
|
+
position: Union[Point, Tuple[float, float]],
|
|
125
|
+
rotation: float = 0,
|
|
126
|
+
justify: str = "left",
|
|
127
|
+
uuid_str: Optional[str] = None,
|
|
128
|
+
) -> Optional[str]:
|
|
129
|
+
"""
|
|
130
|
+
Add a pin to an existing sheet.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
sheet_uuid: UUID of target sheet
|
|
134
|
+
name: Pin name
|
|
135
|
+
pin_type: Pin type (input, output, bidirectional, tri_state, passive)
|
|
136
|
+
position: Pin position relative to sheet
|
|
137
|
+
rotation: Pin rotation in degrees
|
|
138
|
+
justify: Text justification (left, right, center)
|
|
139
|
+
uuid_str: Optional pin UUID
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
UUID of created pin, or None if sheet not found
|
|
143
|
+
"""
|
|
144
|
+
if isinstance(position, tuple):
|
|
145
|
+
position = Point(position[0], position[1])
|
|
146
|
+
|
|
147
|
+
if uuid_str is None:
|
|
148
|
+
uuid_str = str(uuid.uuid4())
|
|
149
|
+
|
|
150
|
+
valid_pin_types = ["input", "output", "bidirectional", "tri_state", "passive"]
|
|
151
|
+
if pin_type not in valid_pin_types:
|
|
152
|
+
logger.warning(f"Invalid sheet pin type: {pin_type}. Using 'input'")
|
|
153
|
+
pin_type = "input"
|
|
154
|
+
|
|
155
|
+
# Find the sheet
|
|
156
|
+
sheets = self._data.get("sheets", [])
|
|
157
|
+
for sheet in sheets:
|
|
158
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
159
|
+
pin_data = {
|
|
160
|
+
"uuid": uuid_str,
|
|
161
|
+
"name": name,
|
|
162
|
+
"pin_type": pin_type,
|
|
163
|
+
"position": {"x": position.x, "y": position.y},
|
|
164
|
+
"rotation": rotation,
|
|
165
|
+
"size": 1.27,
|
|
166
|
+
"justify": justify,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# Add to sheet's pins array (already initialized in add_sheet)
|
|
170
|
+
sheet["pins"].append(pin_data)
|
|
171
|
+
|
|
172
|
+
logger.debug(f"Added pin '{name}' to sheet {sheet_uuid}")
|
|
173
|
+
return uuid_str
|
|
174
|
+
|
|
175
|
+
logger.warning(f"Sheet not found: {sheet_uuid}")
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
def remove_sheet(self, sheet_uuid: str) -> bool:
|
|
179
|
+
"""
|
|
180
|
+
Remove a sheet by UUID.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
sheet_uuid: UUID of sheet to remove
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
True if sheet was removed, False if not found
|
|
187
|
+
"""
|
|
188
|
+
sheets = self._data.get("sheets", [])
|
|
189
|
+
for i, sheet in enumerate(sheets):
|
|
190
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
191
|
+
# Also remove from sheet instances
|
|
192
|
+
self._remove_sheet_from_instances(sheet_uuid)
|
|
193
|
+
del sheets[i]
|
|
194
|
+
logger.debug(f"Removed sheet: {sheet_uuid}")
|
|
195
|
+
return True
|
|
196
|
+
|
|
197
|
+
logger.warning(f"Sheet not found for removal: {sheet_uuid}")
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
def remove_sheet_pin(self, sheet_uuid: str, pin_uuid: str) -> bool:
|
|
201
|
+
"""
|
|
202
|
+
Remove a pin from a sheet.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
sheet_uuid: UUID of parent sheet
|
|
206
|
+
pin_uuid: UUID of pin to remove
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
True if pin was removed, False if not found
|
|
210
|
+
"""
|
|
211
|
+
sheets = self._data.get("sheets", [])
|
|
212
|
+
for sheet in sheets:
|
|
213
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
214
|
+
pins = sheet.get("pins", [])
|
|
215
|
+
for i, pin in enumerate(pins):
|
|
216
|
+
if pin.get("uuid") == pin_uuid:
|
|
217
|
+
del pins[i]
|
|
218
|
+
logger.debug(f"Removed pin {pin_uuid} from sheet {sheet_uuid}")
|
|
219
|
+
return True
|
|
220
|
+
|
|
221
|
+
logger.warning(f"Sheet pin not found: {pin_uuid} in sheet {sheet_uuid}")
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
def get_sheet_by_name(self, name: str) -> Optional[Dict[str, Any]]:
|
|
225
|
+
"""
|
|
226
|
+
Find sheet by name.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
name: Sheet name to find
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Sheet data or None if not found
|
|
233
|
+
"""
|
|
234
|
+
sheets = self._data.get("sheets", [])
|
|
235
|
+
for sheet in sheets:
|
|
236
|
+
if sheet.get("name") == name:
|
|
237
|
+
return sheet
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
def get_sheet_by_filename(self, filename: str) -> Optional[Dict[str, Any]]:
|
|
241
|
+
"""
|
|
242
|
+
Find sheet by filename.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
filename: Filename to find
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Sheet data or None if not found
|
|
249
|
+
"""
|
|
250
|
+
# Normalize filename
|
|
251
|
+
if not filename.endswith(".kicad_sch"):
|
|
252
|
+
filename = f"{filename}.kicad_sch"
|
|
253
|
+
|
|
254
|
+
sheets = self._data.get("sheets", [])
|
|
255
|
+
for sheet in sheets:
|
|
256
|
+
if sheet.get("filename") == filename:
|
|
257
|
+
return sheet
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
def list_sheet_pins(self, sheet_uuid: str) -> List[Dict[str, Any]]:
|
|
261
|
+
"""
|
|
262
|
+
Get all pins for a sheet.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
sheet_uuid: UUID of sheet
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
List of pin data
|
|
269
|
+
"""
|
|
270
|
+
sheets = self._data.get("sheets", [])
|
|
271
|
+
for sheet in sheets:
|
|
272
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
273
|
+
pins = sheet.get("pins", [])
|
|
274
|
+
return [
|
|
275
|
+
{
|
|
276
|
+
"uuid": pin.get("uuid"),
|
|
277
|
+
"name": pin.get("name"),
|
|
278
|
+
"pin_type": pin.get("pin_type"),
|
|
279
|
+
"position": (
|
|
280
|
+
Point(pin["position"]["x"], pin["position"]["y"])
|
|
281
|
+
if "position" in pin
|
|
282
|
+
else None
|
|
283
|
+
),
|
|
284
|
+
"data": pin,
|
|
285
|
+
}
|
|
286
|
+
for pin in pins
|
|
287
|
+
]
|
|
288
|
+
return []
|
|
289
|
+
|
|
290
|
+
def update_sheet_size(self, sheet_uuid: str, size: Union[Point, Tuple[float, float]]) -> bool:
|
|
291
|
+
"""
|
|
292
|
+
Update sheet size.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
sheet_uuid: UUID of sheet
|
|
296
|
+
size: New size (width, height)
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
True if updated, False if not found
|
|
300
|
+
"""
|
|
301
|
+
if isinstance(size, tuple):
|
|
302
|
+
size = Point(size[0], size[1])
|
|
303
|
+
|
|
304
|
+
sheets = self._data.get("sheets", [])
|
|
305
|
+
for sheet in sheets:
|
|
306
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
307
|
+
sheet["size"] = {"width": size.x, "height": size.y}
|
|
308
|
+
logger.debug(f"Updated sheet size: {sheet_uuid}")
|
|
309
|
+
return True
|
|
310
|
+
|
|
311
|
+
logger.warning(f"Sheet not found for size update: {sheet_uuid}")
|
|
312
|
+
return False
|
|
313
|
+
|
|
314
|
+
def update_sheet_position(
|
|
315
|
+
self, sheet_uuid: str, position: Union[Point, Tuple[float, float]]
|
|
316
|
+
) -> bool:
|
|
317
|
+
"""
|
|
318
|
+
Update sheet position.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
sheet_uuid: UUID of sheet
|
|
322
|
+
position: New position
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
True if updated, False if not found
|
|
326
|
+
"""
|
|
327
|
+
if isinstance(position, tuple):
|
|
328
|
+
position = Point(position[0], position[1])
|
|
329
|
+
|
|
330
|
+
sheets = self._data.get("sheets", [])
|
|
331
|
+
for sheet in sheets:
|
|
332
|
+
if sheet.get("uuid") == sheet_uuid:
|
|
333
|
+
sheet["position"] = {"x": position.x, "y": position.y}
|
|
334
|
+
logger.debug(f"Updated sheet position: {sheet_uuid}")
|
|
335
|
+
return True
|
|
336
|
+
|
|
337
|
+
logger.warning(f"Sheet not found for position update: {sheet_uuid}")
|
|
338
|
+
return False
|
|
339
|
+
|
|
340
|
+
def get_sheet_hierarchy(self) -> Dict[str, Any]:
|
|
341
|
+
"""
|
|
342
|
+
Get hierarchical structure of all sheets.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
Dictionary representing sheet hierarchy
|
|
346
|
+
"""
|
|
347
|
+
sheets = self._data.get("sheets", [])
|
|
348
|
+
|
|
349
|
+
hierarchy = {"root": {"uuid": self._data.get("uuid"), "name": "Root Sheet", "children": []}}
|
|
350
|
+
|
|
351
|
+
# Build sheet tree
|
|
352
|
+
for sheet in sheets:
|
|
353
|
+
sheet_info = {
|
|
354
|
+
"uuid": sheet.get("uuid"),
|
|
355
|
+
"name": sheet.get("name"),
|
|
356
|
+
"filename": sheet.get("filename"),
|
|
357
|
+
"pin_count": len(sheet.get("pins", [])),
|
|
358
|
+
"position": (
|
|
359
|
+
Point(sheet["position"]["x"], sheet["position"]["y"])
|
|
360
|
+
if "position" in sheet
|
|
361
|
+
else None
|
|
362
|
+
),
|
|
363
|
+
"size": (
|
|
364
|
+
Point(sheet["size"]["width"], sheet["size"]["height"])
|
|
365
|
+
if "size" in sheet
|
|
366
|
+
else None
|
|
367
|
+
),
|
|
368
|
+
}
|
|
369
|
+
hierarchy["root"]["children"].append(sheet_info)
|
|
370
|
+
|
|
371
|
+
return hierarchy
|
|
372
|
+
|
|
373
|
+
def validate_sheet_references(self) -> List[str]:
|
|
374
|
+
"""
|
|
375
|
+
Validate sheet file references and connections.
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
List of validation warnings
|
|
379
|
+
"""
|
|
380
|
+
warnings = []
|
|
381
|
+
sheets = self._data.get("sheets", [])
|
|
382
|
+
|
|
383
|
+
for sheet in sheets:
|
|
384
|
+
sheet_name = sheet.get("name", "Unknown")
|
|
385
|
+
filename = sheet.get("filename")
|
|
386
|
+
|
|
387
|
+
# Check filename format
|
|
388
|
+
if filename and not filename.endswith(".kicad_sch"):
|
|
389
|
+
warnings.append(f"Sheet '{sheet_name}' has invalid filename: {filename}")
|
|
390
|
+
|
|
391
|
+
# Check for duplicate filenames
|
|
392
|
+
filename_count = sum(1 for s in sheets if s.get("filename") == filename)
|
|
393
|
+
if filename_count > 1:
|
|
394
|
+
warnings.append(f"Duplicate sheet filename: {filename}")
|
|
395
|
+
|
|
396
|
+
# Check sheet pins
|
|
397
|
+
pins = sheet.get("pins", [])
|
|
398
|
+
pin_names = [pin.get("name") for pin in pins]
|
|
399
|
+
duplicate_pins = set([name for name in pin_names if pin_names.count(name) > 1])
|
|
400
|
+
if duplicate_pins:
|
|
401
|
+
warnings.append(f"Sheet '{sheet_name}' has duplicate pin names: {duplicate_pins}")
|
|
402
|
+
|
|
403
|
+
return warnings
|
|
404
|
+
|
|
405
|
+
def get_sheet_statistics(self) -> Dict[str, Any]:
|
|
406
|
+
"""
|
|
407
|
+
Get statistics about sheets in the schematic.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
Dictionary with sheet statistics
|
|
411
|
+
"""
|
|
412
|
+
sheets = self._data.get("sheets", [])
|
|
413
|
+
|
|
414
|
+
total_pins = sum(len(sheet.get("pins", [])) for sheet in sheets)
|
|
415
|
+
sheet_instances = self._data.get("sheet_instances", [])
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
"total_sheets": len(sheets),
|
|
419
|
+
"total_sheet_pins": total_pins,
|
|
420
|
+
"average_pins_per_sheet": total_pins / len(sheets) if sheets else 0,
|
|
421
|
+
"sheet_instances": len(sheet_instances),
|
|
422
|
+
"filenames": [sheet.get("filename") for sheet in sheets if sheet.get("filename")],
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
def _remove_sheet_from_instances(self, sheet_uuid: str) -> None:
|
|
426
|
+
"""Remove sheet from sheet instances tracking."""
|
|
427
|
+
sheet_instances = self._data.get("sheet_instances", [])
|
|
428
|
+
for i, instance in enumerate(sheet_instances):
|
|
429
|
+
if instance.get("uuid") == sheet_uuid:
|
|
430
|
+
del sheet_instances[i]
|
|
431
|
+
break
|
|
432
|
+
|
|
433
|
+
def add_sheet_instance(self, sheet_uuid: str, project: str, path: str, reference: str) -> None:
|
|
434
|
+
"""
|
|
435
|
+
Add sheet instance tracking.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
sheet_uuid: UUID of sheet
|
|
439
|
+
project: Project identifier
|
|
440
|
+
path: Hierarchical path
|
|
441
|
+
reference: Sheet reference
|
|
442
|
+
"""
|
|
443
|
+
if "sheet_instances" not in self._data:
|
|
444
|
+
self._data["sheet_instances"] = []
|
|
445
|
+
|
|
446
|
+
instance_data = {
|
|
447
|
+
"uuid": sheet_uuid,
|
|
448
|
+
"project": project,
|
|
449
|
+
"path": path,
|
|
450
|
+
"reference": reference,
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
self._data["sheet_instances"].append(instance_data)
|
|
454
|
+
logger.debug(f"Added sheet instance: {reference} at {path}")
|