diff options
-rw-r--r-- | src/ee/__init__.py | 121 | ||||
-rw-r--r-- | src/ee/digikey/__init__.py | 8 | ||||
-rw-r--r-- | src/ee/kicad/__init__.py | 7 | ||||
-rw-r--r-- | src/ee/kicad/bom/__init__.py | 1 | ||||
-rw-r--r-- | src/ee/kicad/bom_tool/__init__.py | 12 | ||||
-rw-r--r-- | src/ee/kicad/model.py | 2 | ||||
-rw-r--r-- | src/ee/kicad/to_bom.py | 3 | ||||
-rw-r--r-- | src/ee/tools/__init__.py | 18 | ||||
-rw-r--r-- | src/ee/tools/digikey_download_facts.py | 33 |
9 files changed, 116 insertions, 89 deletions
diff --git a/src/ee/__init__.py b/src/ee/__init__.py index d3885c3..7fa2243 100644 --- a/src/ee/__init__.py +++ b/src/ee/__init__.py @@ -10,69 +10,72 @@ __all__ = [ "read_ltspice_raw" ] + class EeException(Exception): pass + @total_ordering class EeVal(object): - from decimal import Decimal - units = ['F', 'Ohm', '\u2126', 'H'] - exponents = { - 'f': -15, - 'p': -12, - 'n': -9, - 'u': -6, - '\u00B5': -6, # The micro symbol - 'm': -3, - - 'k': 3, - 'M': 6, - 'G': 9, - 'T': 12, - 'P': 15, - 'E': 18, - } - r = re.compile("([0-9]+\\.[0-9]+|\\.?[0-9]+|[0-9]+\\.?) *([" + "".join(exponents.keys()) + "]?) *(" + "|".join(units) + "?)") - - def __init__(self, s): - m = EeVal.r.match(s) - if not m: - raise EeException("Could not parse value: " + str(s)) - gs = m.groups() - value = float(gs[0]) - exp = gs[1].strip() - exp = EeVal.exponents.get(exp) if len(exp) > 0 else 0 - unit = gs[2] - if value < 1: - e = math.ceil(math.log10(value)) - exp = exp + e - value = value * math.pow(10, -e) - self._value = float(value) - self._exp = exp - self._unit = unit if len(unit) > 0 else None - - @property - def value(self): - return self.__float__() - - @property - def unit(self): - return self._unit - - def __hash__(self): - return hash((self.__float__(), self._unit)) - - def __eq__(self, other): - return ((self.__float__(), self._unit) == (other.__float__(), other._unit)) - - def __lt__(self, other): - return ((self.__float__(), self._unit) < (other.__float__(), other._unit)) - - def __str__(self): - return eng_str(self.__float__(), self._unit) - - def __float__(self): - return self._value * math.pow(10, self._exp) + from decimal import Decimal + units = ['F', 'Ohm', '\u2126', 'H'] + exponents = { + 'f': -15, + 'p': -12, + 'n': -9, + 'u': -6, + '\u00B5': -6, # The micro symbol + 'm': -3, + + 'k': 3, + 'M': 6, + 'G': 9, + 'T': 12, + 'P': 15, + 'E': 18, + } + r = re.compile( + "([0-9]+\\.[0-9]+|\\.?[0-9]+|[0-9]+\\.?) *([" + "".join(exponents.keys()) + "]?) *(" + "|".join(units) + "?)") + + def __init__(self, s): + m = EeVal.r.match(s) + if not m: + raise EeException("Could not parse value: " + str(s)) + gs = m.groups() + value = float(gs[0]) + exp = gs[1].strip() + exp = EeVal.exponents.get(exp) if len(exp) > 0 else 0 + unit = gs[2] + if value < 1: + e = math.ceil(math.log10(value)) + exp = exp + e + value = value * math.pow(10, -e) + self._value = float(value) + self._exp = exp + self._unit = unit if len(unit) > 0 else None + + @property + def value(self): + return self.__float__() + + @property + def unit(self): + return self._unit + + def __hash__(self): + return hash((self.__float__(), self._unit)) + + def __eq__(self, other): + return ((self.__float__(), self._unit) == (other.__float__(), other._unit)) + + def __lt__(self, other): + return ((self.__float__(), self._unit) < (other.__float__(), other._unit)) + + def __str__(self): + return eng_str(self.__float__(), self._unit) + + def __float__(self): + return self._value * math.pow(10, self._exp) class LtSpiceRaw(object): @@ -187,7 +190,7 @@ class LtSpiceReader(object): if line[-1] == '\n' or line[-1] == 0x0a: line = line[:-1] - # print("len(line)={}, line={}".format(len(line), str(line))) + # print("len(line)={}, line={}".format(len(line), str(line))) line = line.decode(encoding="utf-16") if self.mode == 'header': diff --git a/src/ee/digikey/__init__.py b/src/ee/digikey/__init__.py index 1315f96..23569f9 100644 --- a/src/ee/digikey/__init__.py +++ b/src/ee/digikey/__init__.py @@ -93,11 +93,13 @@ class DigikeyProduct(object): def to_ini(self): c = configparser.ConfigParser() - c["overview"] = {}; overview = c["overview"] + c["overview"] = {}; + overview = c["overview"] overview["part_number"] = self.part_number if self.mpn: overview["mpn"] = self.mpn - c["attributes"] = {}; attributes = c["attributes"] + c["attributes"] = {}; + attributes = c["attributes"] for a in self.attributes: key = "{}/{}".format(a.attribute_type.id, a.attribute_type.label) key = key.replace("%", "_") @@ -112,7 +114,6 @@ class DigikeyProduct(object): overview = c["overview"] attributes = [] for k, value in c.items("attributes"): -# print("k={}".format(k)) (type_id, label) = DigikeyProduct.from_ini_r.match(k).groups() a_type = digikey.get_attribute_type(type_id, label) attributes.append(DigikeyAttributeValue(value, a_type)) @@ -291,6 +292,7 @@ class DigikeyClient(object): else: return DigikeySearchResponse(1, SearchResponseTypes.NO_MATCHES) + class DigikeyRepository(object): def __init__(self, digikey, path): self._digikey = digikey diff --git a/src/ee/kicad/__init__.py b/src/ee/kicad/__init__.py index 5187a9c..d2d48da 100644 --- a/src/ee/kicad/__init__.py +++ b/src/ee/kicad/__init__.py @@ -29,6 +29,7 @@ def to_pandas(obj: Any, **kwarg): def to_pandas_schematic(sch: Schematic): # These fields will always be put first. special_fields = ["ref", "ref_type", "ref_num", "value"] + def make_dict(c: Component): fields = { "ref": c.ref, @@ -37,7 +38,7 @@ def to_pandas(obj: Any, **kwarg): "value": c.value, "footprint": c.footprint, } - fields.update({f.name:f.value for f in c.fields if f.is_custom}) + fields.update({f.name: f.value for f in c.fields if f.is_custom}) return fields components = sch.components @@ -56,8 +57,8 @@ def to_pandas(obj: Any, **kwarg): columns = set([key for row in data for key in list(row)]) - set(special_fields) columns = special_fields + list(columns) - return pandas.DataFrame(data=data, columns=columns).\ - set_index("ref").\ + return pandas.DataFrame(data=data, columns=columns). \ + set_index("ref"). \ sort_values(["ref_type", "ref_num"]) if isinstance(obj, Schematic): diff --git a/src/ee/kicad/bom/__init__.py b/src/ee/kicad/bom/__init__.py index a36068b..0392d66 100644 --- a/src/ee/kicad/bom/__init__.py +++ b/src/ee/kicad/bom/__init__.py @@ -97,7 +97,6 @@ class Bom(object): for field in fields: data[field].append(c[field] if field in c else None) - # del data[ref_field_name] data[ref_field_name] = refs data[value_field_name] = values return pandas.DataFrame(data=data, index=refs) diff --git a/src/ee/kicad/bom_tool/__init__.py b/src/ee/kicad/bom_tool/__init__.py index f5d2e4f..3e28eaf 100644 --- a/src/ee/kicad/bom_tool/__init__.py +++ b/src/ee/kicad/bom_tool/__init__.py @@ -103,12 +103,12 @@ def to_panda(bom, bom_settings, csv_format): # type: (Bom, BomSettings, CsvForm # refs.append(functools.reduce(lambda a, b: a + ' ' + b, [c.ref for c in cs], '')) print("group={}".format(gs)) - # return pd.DataFrame(data={ - # 'count': counts, - # 'mpn': mpns, - # 'dpn': dpns, - # 'refs': refs, - # }) + # return pd.DataFrame(data={ + # 'count': counts, + # 'mpn': mpns, + # 'dpn': dpns, + # 'refs': refs, + # }) else: for ref, c in filtered: for key, value in c: diff --git a/src/ee/kicad/model.py b/src/ee/kicad/model.py index a9b0c02..7d9a437 100644 --- a/src/ee/kicad/model.py +++ b/src/ee/kicad/model.py @@ -129,7 +129,7 @@ class Component(object): def get_field(self, name) -> ComponentField: for f in self.fields: if name.lower() == f.name.lower(): - return f + return f class Sheet(object): diff --git a/src/ee/kicad/to_bom.py b/src/ee/kicad/to_bom.py index 9a4f950..62eb075 100644 --- a/src/ee/kicad/to_bom.py +++ b/src/ee/kicad/to_bom.py @@ -1,3 +1,4 @@ +from typing import Iterable from xml.etree.ElementTree import Element from ee.kicad.model import * @@ -34,7 +35,7 @@ def comp(c: Component) -> Element: return comp -def to_bom(schematic: Schematic) -> Component: +def to_bom(schematic: Schematic) -> Iterable[Component]: return [c for c in sorted(schematic.components) if c.ref_type != "#PWR" and c.ref_type != "#FLG"] diff --git a/src/ee/tools/__init__.py b/src/ee/tools/__init__.py index 893ee31..136bdf1 100644 --- a/src/ee/tools/__init__.py +++ b/src/ee/tools/__init__.py @@ -1,4 +1,5 @@ import os.path +from colors import color def _mkdir_and_open(path): @@ -19,3 +20,20 @@ def mk_parents(path: str): if not os.path.isdir(dirname): os.mkdir(dirname) + + +class Log(object): + def __init__(self): + pass + + def warn(self, msg): + print(color(msg, "orange")) + + def info(self, msg): + print(color(msg, "orange")) + + def debug(self, msg): + print(color(msg, "orange")) + + +log = Log() diff --git a/src/ee/tools/digikey_download_facts.py b/src/ee/tools/digikey_download_facts.py index 950623f..c947b67 100644 --- a/src/ee/tools/digikey_download_facts.py +++ b/src/ee/tools/digikey_download_facts.py @@ -2,11 +2,9 @@ import argparse from itertools import * from functools import total_ordering -from colors import color - import ee.digikey as dk from ee.digikey import SearchResponseTypes, DigikeyProduct -from ee.tools import mk_parents +from ee.tools import log @total_ordering @@ -24,6 +22,7 @@ class Query(object): def __hash__(self): return hash((self.is_mpn, self.query)) + parser = argparse.ArgumentParser(description="Download facts about parts from Digi-Key") parser.add_argument("--out", @@ -47,7 +46,7 @@ parser.add_argument("--force", args = parser.parse_args() digikey = dk.Digikey() -client = dk.DigikeyClient(digikey, on_download=lambda s: print(color(s, 'grey'))) +client = dk.DigikeyClient(digikey, on_download=log.debug) repo = dk.DigikeyRepository(digikey, args.out) @@ -62,6 +61,7 @@ if args.part: if args.sch: from ee.kicad import read_schematic, to_bom + sch = read_schematic(args.sch) for c in to_bom(sch): digikey = c.get_field("digikey") @@ -75,43 +75,46 @@ parts = sorted(set(parts)) for q in parts: p = q.query - if repo.has_product(mpn = p if q.is_mpn else None, dpn = p if not q.is_mpn else None) and not args.force: - print(color("Already have facts for {}".format(p), "white")) + if repo.has_product(mpn=p if q.is_mpn else None, dpn=p if not q.is_mpn else None) and not args.force: + log.info("Already have facts for {}".format(p)) continue - print(color("Searching for {}".format(p), "white")) + log.info("Searching for {}".format(p)) response = client.search(p) todos = [] if response.response_type == SearchResponseTypes.SINGLE: p = response.products[0] - print(color("Direct match mpn/dpn: {}/{}".format(p.mpn, p.part_number), "white")) + log.info("Direct match mpn/dpn: {}/{}".format(p.mpn, p.part_number)) on_product(p) elif response.response_type == SearchResponseTypes.MANY: - hits = [(mpn, list(products)) for mpn, products in groupby(sorted(response.products, key=lambda p: p.mpn), lambda p: p.mpn)] + hits = [(mpn, list(products)) for mpn, products in + groupby(sorted(response.products, key=lambda p: p.mpn), lambda p: p.mpn)] if len(hits) == 1: (mpn, products) = hits[0] part_number = products[0].part_number - print(color("Got many results, but they all point to the same part: {}. Will use {} for downloading attributes.".format(mpn, ", ".join([p.part_number for p in products])), "white")) + product_strings = ", ".join([p.part_number for p in products]) + log.info("Got many results, but they all point to the same part: {}. " + "Will use {} for downloading attributes.".format(mpn, product_strings)) todos.append(part_number) else: for k, g in hits: - print(color("Got many results with many parts: {}: {}".format(k, list(g)), "white")) + log.info("Got many results with many parts: {}: {}".format(k, list(g))) on_product(list(g)[0]) elif response.response_type == SearchResponseTypes.TOO_MANY: - print(color("Too many results ({}), select a category first".format(response.count), 'red')) + log.warn("Too many results ({}), select a category first".format(response.count)) elif response.response_type == SearchResponseTypes.NO_MATCHES: - print(color("Part not found", "orange")) + log.warn("Part not found") for part_number in todos: response = client.search(part_number) if response.response_type == SearchResponseTypes.SINGLE: p = response.products[0] - print(color("Downloaded {}".format(p.mpn), "white")) + log.info("Downloaded {}".format(p.mpn)) on_product(p) else: - print("Got response of type {} when really expecting a single product.".format(response.response_type)) + log.warn("Got response of type {} when really expecting a single product.".format(response.response_type)) |