from pathlib import Path from typing import List from ee.digikey import Digikey, DigikeyParser, DigikeyClient, SearchResponseTypes, DigikeyProduct from ee.part import PartDb, load_db, save_db from ee.xml import bomFile, bom_file_utils from ee.xml.uris import DIGIKEY_URI, make_digikey_fact_key __all__ = ["search_parts"] def resolved(p: DigikeyProduct) -> bomFile.Part: part = bomFile.Part(id=p.part_number, distributor_info=bomFile.DistributorInfo(), facts=bomFile.FactList(), part_numbers=bomFile.PartNumberList()) part.distributor_infoProp.stateProp = "resolved" part_numbers = part.part_numbersProp.part_numberProp part_numbers.append(bomFile.PartNumber(value=p.part_number, distributor=DIGIKEY_URI)) if p.mpn: part_numbers.append(bomFile.PartNumber(value=p.mpn)) facts: List[bomFile.Fact] = part.factsProp.factProp for a in p.attributes: key = make_digikey_fact_key(a.attribute_type.id) facts.append(bomFile.Fact(key=key, label=a.attribute_type.label, value=a.value)) if len(p.price_breaks): part.price_breaksProp = bomFile.PriceBreakList() price_breaks: List[bomFile.PriceBreak] = part.price_breaksProp.price_break for pb in p.price_breaks: amount = bomFile.Amount(value=str(pb.per_piece_price.amount), currency=pb.per_piece_price.currency) price_breaks.append(bomFile.PriceBreak(pb.quantity, amount=amount)) return part def search_parts(in_dir: Path, out_dir: Path, cache_dir: Path, force_refresh: bool): print("in: {}, out: {}".format(in_dir, out_dir)) in_db = load_db(in_dir) out_parts = PartDb() parser = DigikeyParser(Digikey()) client = DigikeyClient(cache_dir) for part in in_db.iterparts(): dpn = bom_file_utils.find_dpn(part, DIGIKEY_URI) mpn = bom_file_utils.find_pn(part) is_mpn = query = None if dpn is not None: query = dpn is_mpn = False elif mpn is not None: query = mpn is_mpn = True if query is None: print("could not find pn or dpn: part.id={}".format(part.idProp)) continue out_id = query out_part = bomFile.Part(id=out_id, distributor_info=bomFile.DistributorInfo(), part_numbers=part.part_numbersProp) di = out_part.distributor_infoProp text = client.search(query) response = parser.parse_string(text) if response.response_type == SearchResponseTypes.SINGLE: out_part = resolved(response.products[0]) elif response.response_type == SearchResponseTypes.MANY: # find those with an exact match. Digikey uses a prefix search so a query for "FOO" will return "FOO" # and "FOOT". def get_field(p): return p.mpn if is_mpn else p.part_number filtered_products = [p for p in response.products if get_field(p) == query] if len(filtered_products) == 0: di.stateProp = "not-found" else: dpn = sorted(filtered_products, key=lambda p: p.part_number)[0].part_number response = parser.parse_string(client.search(dpn)) if response.response_type == SearchResponseTypes.SINGLE: out_part = resolved(response.products[0]) else: di.stateProp = "many" elif response.response_type == SearchResponseTypes.TOO_MANY: di.stateProp = "too-many" elif response.response_type == SearchResponseTypes.NO_MATCHES: di.stateProp = "not-found" out_parts.add_entry(out_part, True) print("Saving {} work parts".format(out_parts.size())) save_db(out_dir, out_parts)