import re from typing import List from functools import total_ordering 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) @total_ordering class Component(object): def __init__(self, position, timestamp, library, name, unit, ref, fields): self._position = position self._timestamp = timestamp self._library = library self._name = name self._unit = unit self._ref = ref self._fields = fields # type List[ComponentField] 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 unit(self): return self._unit @property def ref(self): return self._ref @property def has_ref_num(self): return not self._ref.endswith("?") @property def ref_type(self) -> str: r = re.compile("([^0-9]+)(.+)") return r.split(self._ref)[1] @property def ref_num(self) -> int: r = re.compile("([^0-9]+)(.+)") return int(r.split(self._ref)[2]) @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): return self._fields[1].value @property def footprint(self): return self._fields[2].value @property def fields(self) -> List[ComponentField]: return list(self._fields) @property def named_fields(self): 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): 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): return frozenset(self._components) def add_component(self, component): self._components.append(component) def get_component(self, ref, unit=1): c = find_component(self, ref, unit) if c: return c raise KeyError("No such component: {}".format(ref)) def find_component(self, ref, unit=1): 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): 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