import re import sys from itertools import groupby from pathlib import Path from typing import List from ee import EeException from ee.db import ObjDb from ee.part import Part, load_db __all__ = ["load_bom"] def uri_fn(part: Part): return part.uri def supplier_fn(part: Part): return part.supplier class BomItem(object): def __init__(self, references, part: Part): self.references = references self.part = part def load_bom(bom_path: Path, part_files: List[Path]) -> (ObjDb[Part](), ObjDb[Part]()): bom: ObjDb[Part] = ObjDb[Part]() for xml in load_db(bom_path).iterparts(): bom.add(Part(xml)) parts: ObjDb[Part] = ObjDb[Part]() parts.add_unique_index("uri", uri_fn) parts.add_index("supplier", supplier_fn) for part_file in part_files: for xml in load_db(part_file).iterparts(): parts.add(Part(xml)) return bom, parts def check_bom(bom: ObjDb[Part](), parts: ObjDb[Part]()): pass def split_ref(ref): """Split "C12" into a tuple that's useful for sorting by component reference. For example: "C12" => ("C", 12, None). "Cfoo" => ("C", sys.maxsize, ""). """ m = split_ref.r.match(ref) if not m: return ref, sys.maxsize, "" groups = m.groups() ref = groups[0] val = groups[1] rest = groups[2] try: return ref, int(val), rest except ValueError: pass return ref, val, rest split_ref.r = re.compile("([A-Za-z]+)([0-9]+)(.*)") def join_refs(refs: List[str], max=None) -> str: refs = [ref.strip() for ref in refs] rs = sorted([split_ref(ref) for ref in refs]) for r in rs: if r[1] is None: raise EeException("Bad ref, must match '[A-Z]+[0-9]+'.") s = "" for kind, items in groupby(rs, lambda x: x[0]): items = list(items) groups = [] start = cur = items[0][1] for r in items[1:]: num = r[1] if cur + 1 != num: groups.append([start, cur]) start = cur = num else: cur = num groups.append([start, cur]) parts = [] for start, end in groups: if start == end: parts.append(str(start)) elif start + 1 == end: parts.append("{},{}".format(start, end)) else: parts.append("{}-{}".format(start, end)) s += kind + ",".join(parts) return s