aboutsummaryrefslogtreecommitdiff
path: root/src/ee/part
diff options
context:
space:
mode:
Diffstat (limited to 'src/ee/part')
-rw-r--r--src/ee/part/__init__.py159
-rw-r--r--src/ee/part/create_distributor_search_list.py15
2 files changed, 158 insertions, 16 deletions
diff --git a/src/ee/part/__init__.py b/src/ee/part/__init__.py
index 4ed6edb..7a58f75 100644
--- a/src/ee/part/__init__.py
+++ b/src/ee/part/__init__.py
@@ -1,24 +1,154 @@
from pathlib import Path
-from typing import List, MutableMapping, Optional, Iterator
+from typing import List, MutableMapping, Optional, Iterator, Union
-from ee.xml import types, bom_file_utils
+from ee import EeException
+from ee.money import Money
+from ee.xml import types
__all__ = [
+ "Part",
"PartDb",
"load_db",
"save_db",
]
+class Part(object):
+ def __init__(self, xml: types.Part):
+ assert type(xml) == types.Part
+ self.xml = xml
+ xml.referencesProp = xml.referencesProp if xml.referencesProp is not None else types.ReferencesList()
+ xml.price_breaksProp = xml.price_breaksProp if xml.price_breaksProp is not None else types.PriceBreakList()
+ xml.linksProp = xml.linksProp if xml.linksProp is not None else types.LinkList()
+ xml.factsProp = xml.factsProp if xml.factsProp is not None else types.FactList()
+
+ def clean_xml(self):
+ x = self.xml
+ if len(x.referencesProp.part_referenceProp) == 0 and \
+ len(x.referencesProp.schematic_referenceProp) == 0 and \
+ len(x.referencesProp.part_numberProp) == 0 and \
+ len(x.referencesProp.supplier_part_numberProp) == 0:
+ x.referencesProp = None
+ if len(x.price_breaksProp.price_break) == 0:
+ x.price_breaksProp = None
+ if len(x.linksProp.link) == 0:
+ x.linksProp = None
+ if len(x.factsProp.fact) == 0:
+ x.factsProp = None
+
+ @property
+ def underlying(self) -> types.Part:
+ return self.xml
+
+ @property
+ def uri(self) -> str:
+ return self.xml.uriProp
+
+ @property
+ def supplier(self) -> str:
+ return self.xml.supplierProp
+
+ # Part number ref
+
+ def add_part_reference(self, uri):
+ self.get_part_references().append(types.PartReference(part_uri=uri))
+
+ def get_part_references(self) -> List[types.PartReference]:
+ return self.xml.referencesProp.part_referenceProp
+
+ # Schematic references
+
+ def add_schematic_reference(self, ref):
+ self.get_schematic_references().append(types.SchematicReference(reference=ref))
+
+ def get_schematic_references(self) -> List[types.SchematicReference]:
+ return self.xml.referencesProp.schematic_referenceProp
+
+ def get_only_schematic_reference(self) -> Optional[types.SchematicReference]:
+ return next(iter(self.get_schematic_references()), None)
+
+ def get_exactly_one_schematic_reference(self) -> types.SchematicReference:
+ refs = self.get_schematic_references()
+ if len(refs) == 0:
+ raise EeException("This part does not contain any schematic references{}".
+ format(", uri=" + self.uri if self.uri else ""))
+ if len(refs) != 1:
+ raise EeException("This part does not contain exactly one schematic reference: {}".
+ format(", ".join([ref.referenceProp for ref in refs])))
+
+ return refs[0]
+
+ # MPNs
+
+ def add_mpn(self, mpn: str):
+ self.get_mpns().append(types.PartNumber(value=mpn))
+
+ def get_mpns(self) -> List[types.PartNumber]:
+ return self.xml.referencesProp.part_numberProp
+
+ def get_only_mpn(self) -> Optional[types.PartNumber]:
+ return next(iter(self.get_mpns()), None)
+
+ def get_exactly_one_mpn(self) -> types.PartNumber:
+ mpns = self.get_mpns()
+ if len(mpns) == 0:
+ raise EeException("This part does not contain any manufacturer part numbers{}".
+ format(", uri=" + self.uri if self.uri else ""))
+ if len(mpns) != 1:
+ raise EeException("This part does not contain exactly one mpn: {}".
+ format(", ".join([mpn.valueProp for mpn in mpns])))
+
+ return mpns[0]
+
+ # SPNs
+
+ def add_spn(self, mpn: str):
+ self.get_spns().append(types.SupplierPartNumber(value=mpn))
+
+ def get_spns(self) -> List[types.SupplierPartNumber]:
+ return self.xml.referencesProp.supplier_part_numberProp
+
+ def get_only_spn(self) -> Optional[types.SupplierPartNumber]:
+ return next(iter(self.get_spns()), None)
+
+ def get_exactly_one_spn(self) -> types.SupplierPartNumber:
+ spns = self.get_spns()
+ if len(spns) == 0:
+ raise EeException("This part does not contain any manufacturer part numbers{}".
+ format(", uri=" + self.uri if self.uri else ""))
+ if len(spns) != 1:
+ raise EeException("This part does not contain exactly one spn: {}".
+ format(", ".join([spn.valueProp for spn in spns])))
+
+ return spns[0]
+
+ # Price breaks
+
+ def add_price_break(self, quantity, price: Money):
+ amount = types.Amount(value=price.amount, currency=price.currency)
+ pb = types.PriceBreak(quantity=quantity, amount=amount)
+ self.xml.price_breaksProp.price_break.append(pb)
+
+ # Links
+
+ def get_links(self) -> List[types.Link]:
+ return self.xml.linksProp.link
+
+ # Facts
+
+ def get_facts(self) -> List[types.Fact]:
+ return self.xml.factsProp.fact
+
+ def find_fact(self, key: str) -> Optional[types.Fact]:
+ return next((f for f in self.get_facts() if f.keyProp == key), None)
+
+
class Entry(object):
def __init__(self, new: bool, part: types.Part):
self.new = new
self.part = part
- self.pn = next((p.valueProp for p in bom_file_utils.part_numbers(part)), None)
-
- def dpn(self, uri: str):
- return [spn for spn in bom_file_utils.supplier_part_numbers(self.part) if spn.supplierProp == uri]
+ self.pn = next((p.valueProp for p in Part(part).get_mpns()), None)
class PartDb(object):
@@ -27,7 +157,10 @@ class PartDb(object):
self.pn_index: MutableMapping[str, Entry] = {}
self.new_entries = 0
- def add_entry(self, part: types.Part, new: bool):
+ def add_entry(self, part: Union[Part, types.Part], new: bool):
+ if isinstance(part, Part):
+ part = part.underlying
+
e = Entry(new, part)
self.parts.append(e)
@@ -63,10 +196,18 @@ def load_db(path: Path) -> PartDb:
return db
+def find_root_tag(root):
+ return next((tag for tag, klass in types.GDSClassesMapping.items() if klass == type(root)), None)
+
+
def save_db(path: Path, db: PartDb, sort=False):
part_db = types.PartDb()
parts = part_db.parts = types.PartList()
- parts.partProp.extend(db.iterparts(sort=sort))
+
+ for part in db.iterparts(sort=sort):
+ p = Part(part)
+ p.clean_xml()
+ parts.partProp.append(p.underlying)
with path.open("w") as f:
- part_db.export(outfile=f, level=0, name_=bom_file_utils.find_root_tag(part_db))
+ part_db.export(outfile=f, level=0, name_=find_root_tag(part_db))
diff --git a/src/ee/part/create_distributor_search_list.py b/src/ee/part/create_distributor_search_list.py
index 10160d4..be362a8 100644
--- a/src/ee/part/create_distributor_search_list.py
+++ b/src/ee/part/create_distributor_search_list.py
@@ -1,7 +1,7 @@
from pathlib import Path
-from ee.part import PartDb, load_db, save_db
-from ee.xml import types, bom_file_utils
+from ee.part import PartDb, load_db, save_db, Part
+from ee.xml import types
__all__ = ["create_distributor_search_list"]
@@ -12,12 +12,13 @@ def create_distributor_search_list(in_path: Path, out_path: Path):
print("loaded {} existing parts".format(in_parts.size()))
- for part in in_parts.iterparts():
- pn_value = next((p.valueProp for p in bom_file_utils.part_numbers(part)), None)
+ for xml in in_parts.iterparts():
+ part = Part(xml)
+ pn_value = next((p.valueProp for p in part.get_mpns()), None)
if pn_value is None:
# TODO: use schematic reference if found
- print("Skipping part with no part number: uri={}".format(part.uriProp))
+ print("Skipping part with no part number: uri={}".format(xml.uriProp))
continue
entry = out_parts.find_by_pn(pn_value)
@@ -25,8 +26,8 @@ def create_distributor_search_list(in_path: Path, out_path: Path):
if entry is not None:
continue
- new_part = types.Part(id=pn_value)
- new_part.referencesProp = part.referencesProp
+ new_part = types.Part()
+ new_part.referencesProp = xml.referencesProp
out_parts.add_entry(new_part, True)