import re from functools import total_ordering from typing import List, Set, Tuple, Optional from ee import EeException class Position(object): def __init__(self, x, y): self._x = x self._y = y @property def x(self): return self._x @property def y(self): return self._y class ComponentField(object): names = ["Reference", "Value", "Footprint", "Datasheet"] def __init__(self, index, name, value, position): value = value.strip() if value and len(value.strip()) > 0 else None self._index = index self._name = name if index >= len(ComponentField.names) else ComponentField.names[index] self._value = value self._position = position @property def index(self): return self._index @property def name(self): return self._name @property def value(self): return self._value @property def position(self): return self._position @property def is_custom(self): return self._index >= len(ComponentField.names) class Symbol(object): def __init__(self, symbol: str): assert symbol is not None self._symbol = symbol i = symbol.find(":") if i == -1: # KiCAD 4 self.library = None self.name = symbol else: self.library = symbol[0:i] self.name = symbol[i + 1:] def split_ref(ref: str) -> Tuple[Optional[str], Optional[int]]: r = re.compile("([^0-9]+)(.+)") try: parts = r.split(ref) return parts[1], int(parts[2]) except ValueError: return None, None @total_ordering class Component(object): def __init__(self, position, timestamp, library, symbol, unit, ref, fields): self._position = position self._timestamp = timestamp self._library = library self._symbol = symbol self._unit = unit self._ref = ref self._fields = fields # type List[ComponentField] self._ref_type, self._ref_num = split_ref(self._ref) def __eq__(self, o: object) -> bool: other = o # type: Component return isinstance(o, Component) and self.ref == other.ref def __lt__(self, o: object) -> bool: if not isinstance(o, Component): return True other = o # type Component if self.has_ref_num and other.has_ref_num: return (self.ref_type, self.ref_num) < (other.ref_type, other.ref_num) else: # raise Exception("fail, ref={}".format(self.ref)) return self.ref < other.ref def __hash__(self) -> int: return self._ref.__hash__() @property def timestamp(self): return self._timestamp @property def symbol(self) -> Symbol: return self._symbol @property def unit(self): return self._unit @property def ref(self): return self._ref @property def has_ref_num(self): return self._ref_num is not None @property def ref_type(self) -> str: if self._ref_type is not None: return self._ref_type raise EeException("This component does not have a ref type") @property def ref_num(self) -> int: if self._ref_num is not None: return self._ref_num raise EeException("This component does not have a ref num") @property def is_pwr(self) -> bool: return self.ref_type == "#PWR" @property def is_flg(self) -> bool: return self.ref_type == "#FLG" @property def value(self) -> str: return self._fields[1].value @property def footprint(self) -> str: return self._fields[2].value @property def fields(self) -> List[ComponentField]: return list(self._fields) @property def named_fields(self) -> List[ComponentField]: return [f for f in self._fields if f.name] def get_field(self, name) -> ComponentField: for f in self.fields: if name.lower() == f.name.lower(): return f class Sheet(object): def __init__(self, name, path): self._name = name self._path = path @property def path(self): return self._path @property def name(self): return self._name class Library(object): def __init__(self, name): self.name = name class Schematic(object): def __init__(self, path): self.path = path self._libraries = set() self._sheets = [] self._components = [] @property def libraries(self): return frozenset(self._libraries) def add_library(self, library): self._libraries.add(Library(library)) @property def sheets(self): return frozenset(self._sheets) def add_sheet(self, sheet): self._sheets.append(sheet) @property def components(self) -> Set[Component]: return frozenset(self._components) def add_component(self, component): self._components.append(component) def get_component(self, ref, unit=1): c = self.find_component(ref, unit) if c: return c raise KeyError("No such component: {}".format(ref)) def find_component(self, ref, unit=1) -> Component: for c in self.components: if c.ref == ref and unit == unit: return c class Schematics(object): def __init__(self, schematics): self._schematics = schematics @property def schematics(self) -> List[Schematic]: return list(self._schematics) @property def components(self) -> List[Component]: cs = [] for s in self._schematics: for c in s.components: cs.append(c) return cs def get_component(self, ref, unit=1) -> Component: for s in self._schematics: c = s.find_component(ref, unit) if c: return c raise KeyError("No such component: {}".format(ref)) @property def libraries(self) -> List[Library]: ls = [] for s in self._schematics: for l in s.libraries: ls.append(l) return ls