fix: apply sexpdata round-trip write to delete_schematic_net_label
delete_schematic_net_label was using kicad-skip's write() which silently discards in-memory _elements mutations. Replaced with WireManager.delete_label() that uses the same sexpdata round-trip approach already used by delete_schematic_wire. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -406,6 +406,66 @@ class WireManager:
|
|||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_label(schematic_path: Path, net_name: str,
|
||||||
|
position: Optional[List[float]] = None,
|
||||||
|
tolerance: float = 0.5) -> bool:
|
||||||
|
"""
|
||||||
|
Delete a net label from the schematic by name (and optionally position).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
schematic_path: Path to .kicad_sch file
|
||||||
|
net_name: Net label text to match
|
||||||
|
position: Optional [x, y] to disambiguate when multiple labels share a name
|
||||||
|
tolerance: Maximum coordinate difference to consider a match (mm)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if a label was found and removed, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(schematic_path, 'r', encoding='utf-8') as f:
|
||||||
|
sch_content = f.read()
|
||||||
|
|
||||||
|
sch_data = sexpdata.loads(sch_content)
|
||||||
|
|
||||||
|
for i, item in enumerate(sch_data):
|
||||||
|
if not (isinstance(item, list) and len(item) > 0
|
||||||
|
and item[0] == Symbol('label')):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Second element is the label text
|
||||||
|
if len(item) < 2 or item[1] != net_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if position is not None:
|
||||||
|
# Find (at x y ...) sub-expression and check coordinates
|
||||||
|
at_entry = next(
|
||||||
|
(p for p in item[1:] if isinstance(p, list)
|
||||||
|
and len(p) >= 3 and p[0] == Symbol('at')),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if at_entry is None:
|
||||||
|
continue
|
||||||
|
lx, ly = float(at_entry[1]), float(at_entry[2])
|
||||||
|
if not (abs(lx - position[0]) < tolerance
|
||||||
|
and abs(ly - position[1]) < tolerance):
|
||||||
|
continue
|
||||||
|
|
||||||
|
del sch_data[i]
|
||||||
|
with open(schematic_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(sexpdata.dumps(sch_data))
|
||||||
|
logger.info(f"Deleted label '{net_name}'")
|
||||||
|
return True
|
||||||
|
|
||||||
|
logger.warning(f"No matching label found for '{net_name}'")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deleting label: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_orthogonal_path(start: List[float], end: List[float],
|
def create_orthogonal_path(start: List[float], end: List[float],
|
||||||
prefer_horizontal_first: bool = True) -> List[List[float]]:
|
prefer_horizontal_first: bool = True) -> List[List[float]]:
|
||||||
|
|||||||
@@ -1926,36 +1926,15 @@ class KiCADInterface:
|
|||||||
if not schematic_path or not net_name:
|
if not schematic_path or not net_name:
|
||||||
return {"success": False, "message": "schematicPath and netName are required"}
|
return {"success": False, "message": "schematicPath and netName are required"}
|
||||||
|
|
||||||
schematic = SchematicManager.load_schematic(schematic_path)
|
from pathlib import Path
|
||||||
if not schematic:
|
from commands.wire_manager import WireManager
|
||||||
return {"success": False, "message": "Failed to load schematic"}
|
|
||||||
|
|
||||||
if not hasattr(schematic, "label"):
|
|
||||||
return {"success": False, "message": "Schematic has no labels"}
|
|
||||||
|
|
||||||
tolerance = 0.5
|
|
||||||
label_to_remove = None
|
|
||||||
|
|
||||||
for label in schematic.label:
|
|
||||||
if not hasattr(label, "value") or label.value != net_name:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
pos_list = None
|
||||||
if position:
|
if position:
|
||||||
# Match by position too
|
pos_list = [position.get("x", 0), position.get("y", 0)]
|
||||||
pos = label.at.value if hasattr(label, "at") and hasattr(label.at, "value") else None
|
|
||||||
if pos:
|
|
||||||
px, py = position.get("x", 0), position.get("y", 0)
|
|
||||||
if abs(float(pos[0]) - px) < tolerance and abs(float(pos[1]) - py) < tolerance:
|
|
||||||
label_to_remove = label
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# First match
|
|
||||||
label_to_remove = label
|
|
||||||
break
|
|
||||||
|
|
||||||
if label_to_remove:
|
deleted = WireManager.delete_label(Path(schematic_path), net_name, pos_list)
|
||||||
schematic.label._elements.remove(label_to_remove)
|
if deleted:
|
||||||
SchematicManager.save_schematic(schematic, schematic_path)
|
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
else:
|
else:
|
||||||
return {"success": False, "message": f"Label '{net_name}' not found"}
|
return {"success": False, "message": f"Label '{net_name}' not found"}
|
||||||
|
|||||||
Reference in New Issue
Block a user