From 1a5ae3079b1fe1b4fadd57d067d871b702740c51 Mon Sep 17 00:00:00 2001 From: Frozen Date: Mon, 26 Feb 2024 22:00:36 +0100 Subject: [PATCH 1/2] Fix handling of top level schematic lib symbols --- src/kiutils/schematic.py | 6 ++-- src/kiutils/symbol.py | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/kiutils/schematic.py b/src/kiutils/schematic.py index a3396ff..deafc5c 100644 --- a/src/kiutils/schematic.py +++ b/src/kiutils/schematic.py @@ -21,7 +21,7 @@ from kiutils.items.common import Image, PageSettings, TitleBlock from kiutils.items.schitems import * -from kiutils.symbol import Symbol +from kiutils.symbol import Symbol, SchematicLibSymbol from kiutils.utils import sexpr from kiutils.misc.config import KIUTILS_CREATE_NEW_GENERATOR_STR, KIUTILS_CREATE_NEW_VERSION_STR @@ -48,7 +48,7 @@ class Schematic(): titleBlock: Optional[TitleBlock] = None """The ``titleBlock`` token defines author, date, revision, company and comments of the schematic""" - libSymbols: List[Symbol] = field(default_factory=list) + libSymbols: List[SchematicLibSymbol] = field(default_factory=list) """The ``libSymbols`` token defines a list of symbols that are used in the schematic""" schematicSymbols: List[SchematicSymbol] = field(default_factory=list) @@ -143,7 +143,7 @@ def from_sexpr(cls, exp: list) -> Schematic: if item[0] == 'title_block': object.titleBlock = TitleBlock().from_sexpr(item) if item[0] == 'lib_symbols': for symbol in item[1:]: - object.libSymbols.append(Symbol().from_sexpr(symbol)) + object.libSymbols.append(SchematicLibSymbol().from_sexpr(symbol)) if item[0] == 'junction': object.junctions.append(Junction().from_sexpr(item)) if item[0] == 'no_connect': object.noConnects.append(NoConnect().from_sexpr(item)) if item[0] == 'bus_entry': object.busEntries.append(BusEntry().from_sexpr(item)) diff --git a/src/kiutils/symbol.py b/src/kiutils/symbol.py index 022a229..267e851 100644 --- a/src/kiutils/symbol.py +++ b/src/kiutils/symbol.py @@ -479,6 +479,82 @@ def to_sexpr(self, indent: int = 2, newline: bool = True) -> str: expression += f'{indents}){endline}' return expression +@dataclass +class SchematicLibSymbol(Symbol): + """The ``symbol`` token defines a symbol or sub-unit of a parent symbol. There can be zero or more + ``symbol`` tokens in a symbol library file. + + Documentation: + https://dev-docs.kicad.org/en/file-formats/sexpr-intro/index.html#_symbols + """ + + """Each symbol must have """ + @property + def libId(self) -> str: + """The ``lib_id`` token defines a unique "LIBRARY_ID" for each top level symbol in the + library or a unique "UNIT_ID" for each unit embedded in a parent symbol. Library identifiers + are only valid it top level symbols and unit identifiers are on valid as unit symbols inside + a parent symbol. + + The following conventions apply: + - "LIBRARY_ID" (top-level symbol): ``[:]`` (the library + nickname part is optional here) + + In ``kiutils``, the ``lib_id`` token is a combination of ``libraryNickname``, ``entryName``, + ``unitId`` and ``styleId`` tokens. Setting the ``lib_id`` token will update all those tokens + accordingly. + + Returns: + - If the ``libraryNickname`` is set: ``:`` + - If the ``libraryNickname`` is ``None``: ```` + depending if these tokens are set. + """ + if (self.unitId is not None and self.styleId is not None): + unit_style_ids = f"_{self.unitId}_{self.styleId}" + else: + unit_style_ids = "" + + if self.libraryNickname: + return f'{self.libraryNickname}:{self.entryName}' + else: + return f'{self.entryName}{unit_style_ids}' + + @libId.setter + def libId(self, symbol_id: str): + """Sets the ``lib_id`` token and parses its contents into the ``libraryNickname``, + ``entryName`` and ``styleId`` token. + + See self.libId property description for more information. + + Args: + - symbol_id (str): The symbol id in the following format: ``:`` + or only ````, depending on if the symbol + is a top-level symbol or a child symbol + + Raises: + - Exception: If the given ID is neither a top-level nor a child symbol + """ + # Try to parse the given ID + parse_symbol_id = re.match(r"^(.+?):(.+?)$", symbol_id) + if parse_symbol_id: + # The symbol is a top-level symbol with a library nickname + self.libraryNickname = parse_symbol_id.group(1) + self.entryName = parse_symbol_id.group(2) + self.unitId = None + self.styleId = None + else: + # The symbol is a top-level symbol without a library nickname + self.libraryNickname = None + self.entryName = symbol_id + self.unitId = None + self.styleId = None + + # Update units id to match parent id + for unit in self.units: + unit.entryName = self.entryName + + + @dataclass class SymbolLib(): """A symbol library defines the common format of ``.kicad_sym`` files. A symbol library may contain From 73e2ae711266ae1642d80b7bf1aff83833eb1dc0 Mon Sep 17 00:00:00 2001 From: PingPongun <46752179+PingPongun@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:46:06 +0100 Subject: [PATCH 2/2] Update zone serialization --- src/kiutils/items/zones.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kiutils/items/zones.py b/src/kiutils/items/zones.py index 2fb7bce..714a035 100644 --- a/src/kiutils/items/zones.py +++ b/src/kiutils/items/zones.py @@ -629,7 +629,7 @@ def to_sexpr(self, indent: int = 2, newline: bool = True) -> str: if len(self.layers) == 0: raise Exception("Zone: No layers set for this zone") - elif len(self.layers) == 1 and self.layers[0] != "F&B.Cu": + elif len(self.layers) == 1 and self.layers[0] != "F&B.Cu" and self.layers[0] != "*.Cu": layer_token = f' (layer{layers})' else: layer_token = f' (layers{layers})'