aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2019-05-14 23:08:20 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2019-05-14 23:08:20 +0200
commit702d7900b646a9d873e6eaa4c61088c618eba9f1 (patch)
tree144689c62b77622cefee5b47d6bb0d91095082f0
parent2cdf0c4b9865f025e52938fb9b772cc79319db09 (diff)
downloadee-python-702d7900b646a9d873e6eaa4c61088c618eba9f1.tar.gz
ee-python-702d7900b646a9d873e6eaa4c61088c618eba9f1.tar.bz2
ee-python-702d7900b646a9d873e6eaa4c61088c618eba9f1.tar.xz
ee-python-702d7900b646a9d873e6eaa4c61088c618eba9f1.zip
ee.logging: New module to handle logging. Need something better for
messages too. create-bom: Resolving parts from their value fact too.
-rw-r--r--src/ee/bom.py67
-rw-r--r--src/ee/logging.py20
-rw-r--r--src/ee/part/__init__.py15
-rw-r--r--src/ee/tools/__init__.py24
4 files changed, 89 insertions, 37 deletions
diff --git a/src/ee/bom.py b/src/ee/bom.py
index f8cca71..731f5b4 100644
--- a/src/ee/bom.py
+++ b/src/ee/bom.py
@@ -4,21 +4,32 @@ from pathlib import Path
from typing import List, MutableMapping, Optional
from ee import EeException
+from ee.logging import log
from ee.db import ObjDb
from ee.part import PartDb, load_db, save_db, Part
from ee.project import Project, report, SupplierDescriptor
from ee.xml import types
+from ee.xml.uris import make_fact_key
__all__ = ["create_bom"]
+class Hit(object):
+ def __init__(self, part: Part, method: str):
+ self.part = part
+ self.method = method
+
+
class BomPart(object):
- def __init__(self, part: types.Part):
- self.part = Part(part)
+ def __init__(self, part: Part):
+ self.part = part
ref = self.part.get_only_schematic_reference()
self.ref = ref.referenceProp if ref else None
- self.available_from: MutableMapping[str, Part] = {}
- self.selected_part = None
+ self.hits = []
+ self.selected_part: Optional[Part] = None
+
+ def add_hit(self, part, method):
+ self.hits.append(Hit(part, method))
def make_report(out_file, unresolved_parts, bom_parts: ObjDb[BomPart], supplier_parts: ObjDb[Path]):
@@ -41,6 +52,7 @@ def create_bom(project: Project, schematic_path: Path, out_path: Path, part_dbs:
strategy = pydoc.locate(strategy_name)
if not callable(strategy):
raise EeException("Not a callable: {}, is a {}".format(strategy_name, type(strategy)))
+ log.info("Using strategy '{}'".format(strategy_name))
supplier_parts = ObjDb[Part]()
supplier_parts.add_unique_index("uri", lambda p: p.uri)
@@ -65,40 +77,55 @@ def create_bom(project: Project, schematic_path: Path, out_path: Path, part_dbs:
op.part.get_mpns()] if op.part.supplier else None, multiple=True)
for sch_part in sch_db.iterparts():
- part = BomPart(sch_part)
- part.part = strategy(part.part)
- if part.part is None:
+ part = Part(sch_part)
+
+ part = strategy(part)
+ if part is None:
continue
- bom_parts.add(part)
+ bom_parts.add(BomPart(part))
for bom_part in bom_parts:
sch_part_numbers = [pn.valueProp for pn in bom_part.part.get_mpns()]
sch_supplier_part_numbers = [spn.valueProp for spn in bom_part.part.get_spns()]
+ value_fact = bom_part.part.find_fact(make_fact_key("value"))
+ if value_fact:
+ value_fact = value_fact.valueProp
+
for supplier in suppliers:
+ # Part number search
pns = supplier_pn_idx.get(supplier.uri)
- spns = supplier_spn_idx.get(supplier.uri)
-
for sch_pn in sch_part_numbers:
for supplier_part in pns.get(sch_pn, []):
- bom_part.available_from[supplier_part.uri] = supplier_part
+ bom_part.add_hit(supplier_part, "pn")
+
+ if value_fact:
+ for supplier_part in pns.get(value_fact, []):
+ bom_part.add_hit(supplier_part, "pn_value_fact")
+
+ # Supplier number search
+ spns = supplier_spn_idx.get(supplier.uri)
for sch_spn in sch_supplier_part_numbers:
for supplier_part in spns.get(sch_spn, []):
- bom_part.available_from[supplier_part.uri] = supplier_part
+ bom_part.add_hit(supplier_part, "spn")
+
+ if value_fact:
+ for supplier_part in spns.get(value_fact, []):
+ bom_part.add_hit(supplier_part, "spn_value_fact")
unresolved_parts = []
for bom_part in bom_parts:
- af = bom_part.available_from
- if len(af) == 0:
+ if len(bom_part.hits) == 0:
unresolved_parts.append(bom_part)
- elif len(af) == 1:
- bom_part.selected_part = next(iter(af.values()))
+ elif len(bom_part.hits) == 1:
+ bom_part.selected_part = bom_part.hits[0].part
else:
- raise EeException("unimplemented: part ({}) available from multiple suppliers: {}".
- format(bom_part.ref, ",".join(af.keys())))
+ references = [hit.part.printable_reference for hit in bom_part.hits]
+ raise EeException("Multiple hits when looking for part: {}".
+ format(bom_part.ref, ",".join(references)))
- bom_parts.add_index("uri", lambda op: op.selected_part.uri if op.selected_part else None)
+ bom_parts.add_index("uri", lambda bp: bp.selected_part.uri if bp.selected_part else None)
bom_parts.add_multi_index("supplier,part", lambda op: (
op.selected_part.supplier, op.selected_part.uri) if op.selected_part else None)
@@ -111,6 +138,7 @@ def create_bom(project: Project, schematic_path: Path, out_path: Path, part_dbs:
out_parts = PartDb()
for bom_part in bom_parts:
if not bom_part.selected_part:
+ log.info("No part selected for {}".format(bom_part.part.printable_reference))
continue
supplier_part = bom_part.selected_part
@@ -121,4 +149,5 @@ def create_bom(project: Project, schematic_path: Path, out_path: Path, part_dbs:
out_parts.add_entry(part, True)
+ log.info("Found {} of {} parts, missing {}".format(len(out_parts), len(sch_db), len(unresolved_parts)))
save_db(out_path, out_parts)
diff --git a/src/ee/logging.py b/src/ee/logging.py
new file mode 100644
index 0000000..c8fd48a
--- /dev/null
+++ b/src/ee/logging.py
@@ -0,0 +1,20 @@
+from colors import color
+
+__all__ = ["Log", "log"]
+
+
+class Log(object):
+ def __init__(self):
+ pass
+
+ def warn(self, msg):
+ print(color(msg, "orange"))
+
+ def info(self, msg):
+ print(color(msg, "white"))
+
+ def debug(self, msg):
+ print(color(msg, "grey"))
+
+
+log = Log()
diff --git a/src/ee/part/__init__.py b/src/ee/part/__init__.py
index 43e4cfa..ff6c7f1 100644
--- a/src/ee/part/__init__.py
+++ b/src/ee/part/__init__.py
@@ -203,6 +203,18 @@ class Part(object):
def supplier(self) -> str:
return self.xml.supplierProp
+ @property
+ def printable_reference(self):
+ for refs, value in [(self.get_schematic_references(), lambda sr: sr.referenceProp),
+ (self.get_part_references(), lambda pr: pr.part_uriProp),
+ (self.get_mpns(), lambda mpn: mpn.valueProp),
+ (self.get_spns(), lambda spn: spn.valueProp)]:
+ ref = next(iter(refs), None)
+ if ref:
+ return value(ref)
+
+ return self.uri
+
# Part number ref
def add_part_reference(self, uri):
@@ -366,6 +378,9 @@ class PartDb(object):
def size(self) -> int:
return len(self.parts)
+ def __len__(self):
+ return self.size()
+
@property
def has_assembly(self):
return self._assembly is not None
diff --git a/src/ee/tools/__init__.py b/src/ee/tools/__init__.py
index b0c1051..46004e9 100644
--- a/src/ee/tools/__init__.py
+++ b/src/ee/tools/__init__.py
@@ -2,7 +2,12 @@ import os.path
from pathlib import Path
from typing import Union
-from colors import color
+from ee.logging import log
+
+__all__ = [
+ "mk_parents",
+ "log" # for compatibility, should be removed
+]
def _mkdir_and_open(path):
@@ -23,20 +28,3 @@ def mk_parents(path: Union[str, Path]):
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, "white"))
-
- def debug(self, msg):
- print(color(msg, "grey"))
-
-
-log = Log()