|
|
|
@ -1,9 +1,84 @@
|
|
|
|
|
"""
|
|
|
|
|
Functions from converting between KLayout layer properties files and a custom TOML format
|
|
|
|
|
"""
|
|
|
|
|
from typing import Self, Type, Any
|
|
|
|
|
import tomllib
|
|
|
|
|
from dataclasses import dataclass, fields
|
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def k2t(kfile: str, tfile: str) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Convert from KLayout layer properties xml (.lyp) to TOML
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
kfile: Path to klayout lyp file (input)
|
|
|
|
|
tfile: Path for TOML file (output)
|
|
|
|
|
"""
|
|
|
|
|
tree = ElementTree.parse(kfile)
|
|
|
|
|
root = tree.getroot()
|
|
|
|
|
|
|
|
|
|
assert root.tag == 'layer-properties'
|
|
|
|
|
name = None
|
|
|
|
|
entries = []
|
|
|
|
|
patterns = []
|
|
|
|
|
linestyles = []
|
|
|
|
|
for child in root:
|
|
|
|
|
if child.tag == 'custom-dither-pattern':
|
|
|
|
|
patterns.append(Pattern.from_xml(child))
|
|
|
|
|
elif child.tag == 'custom-line-style':
|
|
|
|
|
linestyles.append(LineStyle.from_xml(child))
|
|
|
|
|
elif child.tag == 'properties':
|
|
|
|
|
entries.append(Entry.from_xml(child))
|
|
|
|
|
elif child.tag == 'name':
|
|
|
|
|
name = child.text
|
|
|
|
|
else:
|
|
|
|
|
raise Exception(f'Unexpected tag: {child.tag}')
|
|
|
|
|
|
|
|
|
|
if name is not None:
|
|
|
|
|
print(f'Discarding tab name: {name}')
|
|
|
|
|
|
|
|
|
|
with open(tfile, 'wt') as ff:
|
|
|
|
|
for entry in entries:
|
|
|
|
|
ff.write(entry.to_toml())
|
|
|
|
|
for pattern in patterns:
|
|
|
|
|
ff.write(pattern.to_toml())
|
|
|
|
|
for linestyle in linestyles:
|
|
|
|
|
ff.write(linestyle.to_toml())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def t2k(tfile: str, kfile: str) -> None:
|
|
|
|
|
"""
|
|
|
|
|
Convert from TOML to KLayout layer properties xml (.lyp)
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
tfile: Path to TOML file (input)
|
|
|
|
|
kfile: Path for klayout lyp file (output)
|
|
|
|
|
"""
|
|
|
|
|
root = ElementTree.Element('layer-properties')
|
|
|
|
|
|
|
|
|
|
with open(tfile, 'rb') as ff:
|
|
|
|
|
ttree = tomllib.load(ff)
|
|
|
|
|
|
|
|
|
|
entries = [Entry.from_toml(entry)
|
|
|
|
|
for entry in ttree['layers']]
|
|
|
|
|
patterns = [Pattern.from_toml(pat)
|
|
|
|
|
for pat in ttree['patterns']]
|
|
|
|
|
linestyles = [LineStyle.from_toml(ls)
|
|
|
|
|
for ls in ttree['linestyles']]
|
|
|
|
|
|
|
|
|
|
for entry in entries:
|
|
|
|
|
root.append(entry.to_xml())
|
|
|
|
|
for pattern in patterns:
|
|
|
|
|
root.append(pattern.to_xml())
|
|
|
|
|
for linestyle in linestyles:
|
|
|
|
|
root.append(linestyle.to_xml())
|
|
|
|
|
|
|
|
|
|
ktree = ElementTree.ElementTree(root)
|
|
|
|
|
ElementTree.indent(ktree)
|
|
|
|
|
ktree.write(kfile)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(slots=True)
|
|
|
|
|
class Entry:
|
|
|
|
|
name: str
|
|
|
|
@ -272,63 +347,5 @@ class LineStyle:
|
|
|
|
|
return cls(**tree)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def k2t(kfile: str, tfile: str) -> None:
|
|
|
|
|
tree = ElementTree.parse(kfile)
|
|
|
|
|
root = tree.getroot()
|
|
|
|
|
|
|
|
|
|
assert root.tag == 'layer-properties'
|
|
|
|
|
name = None
|
|
|
|
|
entries = []
|
|
|
|
|
patterns = []
|
|
|
|
|
linestyles = []
|
|
|
|
|
for child in root:
|
|
|
|
|
if child.tag == 'custom-dither-pattern':
|
|
|
|
|
patterns.append(Pattern.from_xml(child))
|
|
|
|
|
elif child.tag == 'custom-line-style':
|
|
|
|
|
linestyles.append(LineStyle.from_xml(child))
|
|
|
|
|
elif child.tag == 'properties':
|
|
|
|
|
entries.append(Entry.from_xml(child))
|
|
|
|
|
elif child.tag == 'name':
|
|
|
|
|
name = child.text
|
|
|
|
|
else:
|
|
|
|
|
raise Exception(f'Unexpected tag: {child.tag}')
|
|
|
|
|
|
|
|
|
|
if name is not None:
|
|
|
|
|
print(f'Discarding tab name: {name}')
|
|
|
|
|
|
|
|
|
|
with open(tfile, 'wt') as ff:
|
|
|
|
|
for entry in entries:
|
|
|
|
|
ff.write(entry.to_toml())
|
|
|
|
|
for pattern in patterns:
|
|
|
|
|
ff.write(pattern.to_toml())
|
|
|
|
|
for linestyle in linestyles:
|
|
|
|
|
ff.write(linestyle.to_toml())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def t2k(tfile: str, kfile: str) -> None:
|
|
|
|
|
root = ElementTree.Element('layer-properties')
|
|
|
|
|
|
|
|
|
|
with open(tfile, 'rb') as ff:
|
|
|
|
|
ttree = tomllib.load(ff)
|
|
|
|
|
|
|
|
|
|
entries = [Entry.from_toml(entry)
|
|
|
|
|
for entry in ttree['layers']]
|
|
|
|
|
patterns = [Pattern.from_toml(pat)
|
|
|
|
|
for pat in ttree['patterns']]
|
|
|
|
|
linestyles = [LineStyle.from_toml(ls)
|
|
|
|
|
for ls in ttree['linestyles']]
|
|
|
|
|
|
|
|
|
|
for entry in entries:
|
|
|
|
|
root.append(entry.to_xml())
|
|
|
|
|
for pattern in patterns:
|
|
|
|
|
root.append(pattern.to_xml())
|
|
|
|
|
for linestyle in linestyles:
|
|
|
|
|
root.append(linestyle.to_xml())
|
|
|
|
|
|
|
|
|
|
ktree = ElementTree.ElementTree(root)
|
|
|
|
|
ElementTree.indent(ktree)
|
|
|
|
|
ktree.write(kfile)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def toml_escape(string: str) -> str:
|
|
|
|
|
return string.replace('\\', '\\\\').replace('"', '\\"')
|
|
|
|
|