Fix pcb stackup handling
This commit is contained in:
parent
dd8507d202
commit
467e482bf4
2 changed files with 119 additions and 4 deletions
|
|
@ -33,12 +33,12 @@ class PageSettings:
|
|||
page_format: str = 'A4'
|
||||
width: float = None
|
||||
height: float = None
|
||||
portrait: bool = False
|
||||
portrait: Flag() = False
|
||||
|
||||
|
||||
@sexp_type('layers')
|
||||
class LayerSettings:
|
||||
index: int = None
|
||||
index: int = 0
|
||||
canonical_name: str = None
|
||||
layer_type: AtomChoice(Atom.jumper, Atom.mixed, Atom.power, Atom.signal, Atom.user) = Atom.signal
|
||||
custom_name: str = None
|
||||
|
|
@ -206,7 +206,7 @@ class Board:
|
|||
generator: Named(Atom) = Atom.gerbonara
|
||||
general: GeneralSection = field(default_factory=GeneralSection)
|
||||
page: PageSettings = field(default_factory=PageSettings)
|
||||
layers: Named(Array(LayerSettings)) = field(default_factory=list)
|
||||
layers: Named(Array(Untagged(LayerSettings))) = field(default_factory=list)
|
||||
setup: BoardSetup = field(default_factory=BoardSetup)
|
||||
properties: List(Property) = field(default_factory=list)
|
||||
nets: List(Net) = field(default_factory=list)
|
||||
|
|
@ -245,7 +245,10 @@ class Board:
|
|||
|
||||
def write(self, filename=None):
|
||||
with open(filename or self.original_filename, 'w') as f:
|
||||
f.write(build_sexp(sexp(self)))
|
||||
f.write(self.serialize())
|
||||
|
||||
def serialize(self):
|
||||
return build_sexp(sexp(type(self), self)[0])
|
||||
|
||||
@classmethod
|
||||
def open(kls, pcb_file, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -191,6 +191,118 @@ class Array(WrapperType):
|
|||
yield from sexp(self.next_type, e)
|
||||
|
||||
|
||||
class Untagged(WrapperType):
|
||||
def __map__(self, value, parent=None):
|
||||
value, = value
|
||||
return self.next_type.__map__([self.next_type.name_atom, *value], parent=parent)
|
||||
|
||||
def __sexp__(self, value):
|
||||
for inner in sexp(self.next_type, value):
|
||||
_tag, *rest = inner
|
||||
yield rest
|
||||
|
||||
|
||||
class List(WrapperType):
|
||||
def __bind_field__(self, field):
|
||||
self.attr = field.name
|
||||
|
||||
def __map__(self, value, parent):
|
||||
l = getattr(parent, self.attr, [])
|
||||
mapped = map_sexp(self.next_type, value, parent=parent)
|
||||
l.append(mapped)
|
||||
setattr(parent, self.attr, l)
|
||||
|
||||
def __sexp__(self, value):
|
||||
for elem in value:
|
||||
yield from sexp(self.next_type, elem)
|
||||
|
||||
|
||||
class _SexpTemplate:
|
||||
@staticmethod
|
||||
def __atoms__(kls):
|
||||
return [kls.name_atom]
|
||||
|
||||
@staticmethod
|
||||
def __map__(kls, value, *args, parent=None, **kwargs):
|
||||
positional = iter(kls.positional)
|
||||
inst = kls(*args, **kwargs)
|
||||
|
||||
for v in value[1:]: # skip key
|
||||
if isinstance(v, Atom) and v in kls.keys:
|
||||
name, etype = kls.keys[v]
|
||||
mapped = map_sexp(etype, [v], parent=inst)
|
||||
if mapped is not None:
|
||||
setattr(inst, name, mapped)
|
||||
|
||||
elif isinstance(v, list):
|
||||
name, etype = kls.keys[v[0]]
|
||||
mapped = map_sexp(etype, v, parent=inst)
|
||||
if mapped is not None:
|
||||
setattr(inst, name, mapped)
|
||||
|
||||
else:
|
||||
try:
|
||||
pos_key = next(positional)
|
||||
setattr(inst, pos_key.name, v)
|
||||
except StopIteration:
|
||||
raise TypeError(f'Unhandled positional argument {v!r} while parsing {kls}')
|
||||
|
||||
getattr(inst, '__after_parse__', lambda x: None)(parent)
|
||||
return inst
|
||||
|
||||
@staticmethod
|
||||
def __sexp__(kls, value):
|
||||
getattr(value, '__before_sexp__', lambda: None)()
|
||||
|
||||
out = [kls.name_atom]
|
||||
for f in fields(kls):
|
||||
if f.type is SEXP_END:
|
||||
break
|
||||
out += sexp(f.type, getattr(value, f.name))
|
||||
yield out
|
||||
|
||||
@staticmethod
|
||||
def parse(kls, data, *args, **kwargs):
|
||||
return kls.__map__(parse_sexp(data), *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def sexp(self):
|
||||
return next(self.__sexp__(self))
|
||||
|
||||
|
||||
def sexp_type(name=None):
|
||||
def register(cls):
|
||||
cls = dataclass(cls)
|
||||
cls.name_atom = Atom(name) if name is not None else None
|
||||
for key in '__sexp__', '__map__', '__atoms__', 'parse':
|
||||
if not hasattr(cls, key):
|
||||
setattr(cls, key, classmethod(getattr(_SexpTemplate, key)))
|
||||
|
||||
if not hasattr(cls, 'sexp'):
|
||||
setattr(cls, 'sexp', getattr(_SexpTemplate, 'sexp'))
|
||||
cls.positional = []
|
||||
cls.keys = {}
|
||||
for f in fields(cls):
|
||||
f_type = f.type
|
||||
if f_type is SEXP_END:
|
||||
break
|
||||
|
||||
if hasattr(f_type, '__bind_field__'):
|
||||
f_type.__bind_field__(f)
|
||||
|
||||
atoms = getattr(f_type, '__atoms__', lambda: [])
|
||||
atoms = list(atoms())
|
||||
for atom in atoms:
|
||||
cls.keys[atom] = (f.name, f_type)
|
||||
if not atoms:
|
||||
cls.positional.append(f)
|
||||
|
||||
return cls
|
||||
return register
|
||||
|
||||
|
||||
|
||||
|
||||
class List(WrapperType):
|
||||
def __bind_field__(self, field):
|
||||
self.attr = field.name
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue