logical_layers/backend/serializer.py

80 lines
2.6 KiB
Python

# backend/serializer.py
import pcbnew
class Serializer:
@staticmethod
def serialize(item):
"""
Returns (sexpr_string, error_message).
"""
if not item: return None, "Item is None"
last_error = ""
# Method 1: PCB_IO_KICAD_SEXPR (Robust, KiCad 6+)
try:
sf = pcbnew.STRING_FORMATTER()
plugin = pcbnew.PCB_IO_KICAD_SEXPR()
plugin.SetOutputFormatter(sf)
plugin.Format(item)
res = sf.GetString()
if res and len(res) > 0:
return res, None
else:
last_error = "Format returned empty string"
except Exception as e:
last_error = str(e)
# Method 2: Fallback to direct Serialize
try:
sf = pcbnew.STRING_FORMATTER()
if hasattr(item, 'Serialize'):
item.Serialize(sf)
res = sf.GetString()
if res and len(res) > 0:
return res, None
except Exception as e:
last_error = f"{last_error} | Fallback: {str(e)}"
return None, last_error
@staticmethod
def deserialize(data, board):
"""
Returns (item, error_message).
"""
if not data: return None, "No data provided"
cls_name = data.get('class')
sexpr = data.get('sexpr')
if not cls_name or not sexpr: return None, "Missing class or sexpr"
try:
if not hasattr(pcbnew, cls_name):
return None, f"Class {cls_name} not found in pcbnew"
cls = getattr(pcbnew, cls_name)
item = None
# Instantiate item
try:
item = cls(board)
except:
try:
item = cls()
except Exception as e:
return None, f"Constructor failed for {cls_name}: {e}"
# Deserialize with KiCad version compatibility
# KiCad 9+ requires (data, source_name), older versions take (data)
try:
lr = pcbnew.STRING_LINE_READER(sexpr, "restore")
except:
try:
lr = pcbnew.STRING_LINE_READER(sexpr)
except Exception as e:
return None, f"STRING_LINE_READER init failed: {e}"
item.Deserialize(lr)
return item, None
except Exception as e:
return None, f"Deserialization error for {cls_name}: {e}"