aboutsummaryrefslogtreecommitdiff
path: root/src/ee
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2019-03-28 16:38:50 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2019-03-28 16:43:14 +0100
commitfa85d46af0b91477cf354947df628af0dc0d2800 (patch)
treeb18b775d232560f57eaeb3f43d0861b98201d4ef /src/ee
parent52401b170d8f1c9deaa153acca76e7d6060a06df (diff)
downloadee-python-fa85d46af0b91477cf354947df628af0dc0d2800.tar.gz
ee-python-fa85d46af0b91477cf354947df628af0dc0d2800.tar.bz2
ee-python-fa85d46af0b91477cf354947df628af0dc0d2800.tar.xz
ee-python-fa85d46af0b91477cf354947df628af0dc0d2800.zip
ee.xsd:
o Renaming <part-uri> to <part-reference>. o Adding <supplier> on <part>, removing from <supplier-part-number>. A part can have exactly one part. create-order: o Creating anonymous part objects, with two references, one schematic reference and one part-uri reference to the selected part. o Redoing how the order is calculated with the new ObjDb structure. ee.part.Part: o Absorbing bom_file_utils into Part. Much better wrapper object around the xml goop.
Diffstat (limited to 'src/ee')
-rw-r--r--src/ee/db.py117
-rw-r--r--src/ee/digikey/search_parts.py60
-rw-r--r--src/ee/kicad/make_bom.py45
-rw-r--r--src/ee/order/__init__.py115
-rw-r--r--src/ee/order/templates/order.rst.j228
-rw-r--r--src/ee/part/__init__.py159
-rw-r--r--src/ee/part/create_distributor_search_list.py15
-rw-r--r--src/ee/project/__init__.py17
-rw-r--r--src/ee/project/report.py16
-rw-r--r--src/ee/supplier/seeed.py22
-rw-r--r--src/ee/xml/bom_file_utils.py49
-rw-r--r--src/ee/xml/types.py144
12 files changed, 490 insertions, 297 deletions
diff --git a/src/ee/db.py b/src/ee/db.py
index e471278..57533ef 100644
--- a/src/ee/db.py
+++ b/src/ee/db.py
@@ -1,4 +1,4 @@
-from typing import TypeVar, Generic, Callable, MutableMapping, List, Iterable, Union, Any
+from typing import TypeVar, Generic, Callable, MutableMapping, List, Iterable, Union, Any, Mapping
K = TypeVar('K')
V = TypeVar('V')
@@ -34,9 +34,11 @@ class Index(Generic[K, V]):
class ListIndex(Index[K, V]):
- def __init__(self, key_callable: KeyCallable):
+ def __init__(self, name, key_callable: KeyCallable, multiple=False):
+ self.name = name
self.idx: MutableMapping[K, V] = {}
self.key_callable = key_callable
+ self.multiple = multiple
def add(self, value: V):
keys = self.key_callable(value)
@@ -44,6 +46,9 @@ class ListIndex(Index[K, V]):
if keys is None:
return
+ if not self.multiple:
+ keys = [keys]
+
for key in keys:
if key is None:
continue
@@ -54,8 +59,9 @@ class ListIndex(Index[K, V]):
else:
self.idx[key] = [value]
- def get(self, key: K) -> Iterable[V]:
- return [self.idx[key]]
+ def get(self, key: K) -> List[V]:
+ items = self.idx.get(key, None)
+ return self.idx[key] if items is not None else []
def clear(self):
return self.idx.clear()
@@ -71,12 +77,15 @@ class ListIndex(Index[K, V]):
class UniqueIndex(Index[K, V]):
- def __init__(self, key_callable: KeyCallable):
+ def __init__(self, name, key_callable: KeyCallable, multiple=False):
+ self.name = name
self.idx: MutableMapping[K, V] = {}
self.key_callable = key_callable
+ self.multiple = multiple
def get(self, key: K) -> Iterable[V]:
- return [self.idx[key]]
+ items = self.idx.get(key, None)
+ return [self.idx[key]] if items is not None else []
def get_single(self, key: K) -> V:
return self.idx[key]
@@ -84,16 +93,75 @@ class UniqueIndex(Index[K, V]):
def add(self, value: V):
keys = self.key_callable(value)
- if not isinstance(keys, Iterable):
+ if keys is None:
+ return
+
+ if not self.multiple:
keys = [keys]
for key in keys:
- key = self.key_callable(value)
present = self.idx.get(key, None)
if present is not None:
- raise KeyError("Duplicate part in index: {}".format(key))
+ raise KeyError("Duplicate key in index '{}': key={}, value={}".format(self.name, key, repr(value)))
+
+ self.idx[key] = value
+
+ def clear(self):
+ return self.idx.clear()
+
+ def __iter__(self):
+ return self.idx.__iter__()
+
+ def items(self):
+ return self.idx.items()
+
+ def values(self):
+ return self.idx.values()
+
+
+class MultiIndex(Index[K, V]):
+ def __init__(self, name, key_callable: KeyCallable, multiple=False):
+ self.name = name
+ self.idx: MutableMapping[K, V] = {}
+ self.key_callable = key_callable
+ self.multiple = multiple
+
+ # TODO: this should return a new index
+ def get(self, key: K) -> Mapping[K, V]:
+ items = self.idx.get(key, None)
+ return self.idx[key] if items is not None else {}
- self.idx[key] = True
+ def get_single(self, key: K) -> V:
+ return self.idx[key]
+
+ def add(self, value: V):
+ keys = self.key_callable(value)
+
+ if keys is None:
+ return
+
+ if not self.multiple:
+ keys = [keys]
+
+ for tpl in keys:
+ if not isinstance(tpl, tuple):
+ raise KeyError("The key must be a tuple, index='{}', key='{}'".format(self.name, repr(tpl)))
+
+ parent_idx = self.idx
+ for sub_key in tpl[0:-1]:
+ if sub_key is None:
+ raise KeyError("Got None sub-key: index='{}', key='{}'".format(self.name, repr(tpl)))
+ idx = parent_idx.get(sub_key, None)
+ if idx is None:
+ idx = {}
+ parent_idx[sub_key] = idx
+ parent_idx = idx
+
+ values = parent_idx.get(tpl[-1], None)
+ if values is None:
+ values = []
+ parent_idx[tpl[-1]] = values
+ values.append(value)
def clear(self):
return self.idx.clear()
@@ -125,19 +193,28 @@ class ObjDb(Generic[V]):
def __len__(self) -> int:
return len(self.values)
- def add_index(self, name, key_callable: KeyCallable) -> ListIndex[Any, V]:
- idx = ListIndex(key_callable)
- self._indexes[name] = idx
+ def add_index(self, name, key_callable: KeyCallable, **kwargs) -> ListIndex[Any, V]:
+ idx = ListIndex(name, key_callable, **kwargs)
+ return self._add(name, idx)
+
+ def add_unique_index(self, name, key_callable: KeyCallable, **kwargs) -> UniqueIndex[Any, V]:
+ idx = UniqueIndex(name, key_callable, **kwargs)
+ return self._add(name, idx)
+
+ def add_multi_index(self, name, key_callable: KeyCallable, **kwargs) -> MultiIndex[Any, V]:
+ idx = MultiIndex(name, key_callable, **kwargs)
+ return self._add(name, idx)
+
+ def index(self, name) -> Index:
+ return self._indexes[name]
+
+ def _add(self, name, idx):
+ if name in self._indexes:
+ raise KeyError("Index already exist: {}".format(name))
for value in self.values:
idx.add(value)
- return idx
-
- def add_unique_index(self, name, key_callable: KeyCallable) -> UniqueIndex[Any, V]:
- idx = UniqueIndex(key_callable)
self._indexes[name] = idx
- return idx
- def index(self, name) -> Index:
- return self._indexes[name]
+ return idx
diff --git a/src/ee/digikey/search_parts.py b/src/ee/digikey/search_parts.py
index 358266a..7d19c5b 100644
--- a/src/ee/digikey/search_parts.py
+++ b/src/ee/digikey/search_parts.py
@@ -2,47 +2,46 @@ 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 types, bom_file_utils
+from ee.part import PartDb, load_db, save_db, Part
+from ee.xml import types
from ee.xml.uris import DIGIKEY_URI, make_digikey_fact_key
__all__ = ["search_parts"]
-def resolved(p: DigikeyProduct) -> types.Part:
+def resolved(p: DigikeyProduct) -> Part:
# TODO: fix uri
- part = types.Part(uri="https://digikey.com/pn#{}".format(p.part_number),
- distributor_info=types.DistributorInfo(),
- links=types.LinkList(),
- facts=types.FactList(),
- references=types.ReferencesList())
- part.distributor_infoProp.stateProp = "resolved"
- links = part.linksProp.link
+ xml = types.Part(uri="https://digikey.com/pn#{}".format(p.part_number),
+ supplier=DIGIKEY_URI,
+ description=p.description,
+ distributor_info=types.DistributorInfo(state="resolved"),
+ links=types.LinkList(),
+ facts=types.FactList(),
+ references=types.ReferencesList())
+ part = Part(xml)
if p.url:
- links.append(types.Link(url=p.url, relation="canonical", media_type="text/html"))
+ part.get_links().append(types.Link(url=p.url, relation="canonical", media_type="text/html"))
for d in p.documents:
title = "{}: {}".format(d.kind, d.title)
- links.append(types.Link(url=d.url, relation="http://purl.org/ee/link-relation#documentation",
- media_type="text/html", title=title))
+ part.get_links().append(types.Link(url=d.url, relation="http://purl.org/ee/link-relation#documentation",
+ media_type="text/html", title=title))
- supplier_part_numbers = part.referencesProp.supplier_part_numberProp
- supplier_part_numbers.append(types.SupplierPartNumber(value=p.part_number, supplier=DIGIKEY_URI))
+ part.add_spn(p.part_number)
- part_numbers = part.referencesProp.part_numberProp
if p.mpn:
- part_numbers.append(types.PartNumber(value=p.mpn))
- facts: List[types.Fact] = part.factsProp.factProp
+ part.add_mpn(p.mpn)
+ facts: List[types.Fact] = xml.factsProp.factProp
for a in p.attributes:
key = make_digikey_fact_key(a.attribute_type.id)
facts.append(types.Fact(key=key, label=a.attribute_type.label, value=a.value))
if len(p.price_breaks):
- part.price_breaksProp = types.PriceBreakList()
+ xml.price_breaksProp = types.PriceBreakList()
- price_breaks: List[types.PriceBreak] = part.price_breaksProp.price_break
+ price_breaks: List[types.PriceBreak] = xml.price_breaksProp.price_break
for pb in p.price_breaks:
amount = types.Amount(value=str(pb.per_piece_price.amount), currency=pb.per_piece_price.currency)
price_breaks.append(types.PriceBreak(pb.quantity, amount=amount))
@@ -57,29 +56,34 @@ def search_parts(in_path: Path, out_path: Path, cache_dir: Path):
parser = DigikeyParser(Digikey())
client = DigikeyClient(cache_dir)
- for part in in_db.iterparts():
- dpn = next((p.valueProp for p in bom_file_utils.supplier_part_numbers(part)
- if p.supplierProp == DIGIKEY_URI), None)
- mpn = next((p.valueProp for p in bom_file_utils.part_numbers(part)), None)
+ for xml in in_db.iterparts():
+ if xml.supplierProp is not None and xml.supplierProp != DIGIKEY_URI:
+ continue
+
+ part = Part(xml)
+
+ dpn = part.get_only_spn()
+ mpn = part.get_only_mpn()
is_mpn = query = None
if dpn is not None:
- query = dpn
+ query = dpn.valueProp
is_mpn = False
elif mpn is not None:
- query = mpn
+ query = mpn.valueProp
is_mpn = True
if query is None:
# TODO: use schematic reference
- print("could not find pn or dpn: part.uri={}".format(part.uriProp))
+ print("could not find pn or dpn: part.uri={}".format(xml.uriProp))
continue
out_id = query
out_part = types.Part(uri=out_id,
distributor_info=types.DistributorInfo(),
- references=part.referencesProp)
+ supplier=DIGIKEY_URI,
+ references=xml.referencesProp)
di = out_part.distributor_infoProp
text = client.search(query)
diff --git a/src/ee/kicad/make_bom.py b/src/ee/kicad/make_bom.py
index 0a8f4bb..ddaa6b9 100644
--- a/src/ee/kicad/make_bom.py
+++ b/src/ee/kicad/make_bom.py
@@ -8,7 +8,7 @@ from ee import EeException
from ee.kicad.model import Component
from ee.kicad.read_schematic import read_schematics
from ee.kicad.to_bom import to_bom, to_bom_xml
-from ee.part import PartDb, save_db
+from ee.part import PartDb, save_db, Part
from ee.xml import types, uris
__all__ = [
@@ -21,61 +21,60 @@ __all__ = [
"make_bom",
]
-StrategyCallable = Callable[[Component, types.Part], Optional[types.Part]]
+StrategyCallable = Callable[[Component, Part], Optional[Part]]
-def apply_strategies(c: Component, part: types.Part, strategies: List[StrategyCallable]):
+def apply_strategies(c: Component, part: Part, strategies: List[StrategyCallable]):
for strategy in strategies:
part = strategy(c, part)
if part is None:
return
- if not isinstance(part, types.Part):
- raise EeException("Values returned from strategy must be a types.Part, got {}".format(type(part)))
+ if not isinstance(part, Part):
+ raise EeException("Values returned from strategy must be a Part, got {}".format(type(part)))
return part
-def part_type_strategy(component: Component, part: types.Part) -> types.Part:
+def part_type_strategy(component: Component, part: Part) -> Part:
fp = component.footprint
if fp is None:
return part
lib, part_name = fp.split(":")
+ xml = part.underlying
if lib == "Capacitor_SMD":
- part.part_typeProp = uris.CAPACITOR
+ xml.part_typeProp = uris.CAPACITOR
elif lib == "Resistor_SMD":
- part.part_typeProp = uris.RESISTOR
+ xml.part_typeProp = uris.RESISTOR
elif lib == "Diode_SMD":
- part.part_typeProp = uris.DIODE
+ xml.part_typeProp = uris.DIODE
elif lib == "Inductor_SMD":
- part.part_typeProp = uris.INDUCTOR
+ xml.part_typeProp = uris.INDUCTOR
elif lib == "Crystal":
- part.part_typeProp = uris.CRYSTAL
+ xml.part_typeProp = uris.CRYSTAL
return part
-def mpn_strategy(component: Component, part: types.Part) -> types.Part:
+def mpn_strategy(component: Component, part: Part) -> Part:
mpn = component.get_field("mpn")
if mpn is not None:
- pn = types.PartNumber(value=mpn.value)
- part.referencesProp.add_part_number(pn)
+ part.add_mpn(mpn.value)
return part
def dpn_strategy_factory(dpn_mappings: Mapping[str, str]) -> StrategyCallable:
- def dpn_strategy(component: Component, part: types.Part) -> types.Part:
+ def dpn_strategy(component: Component, part: Part) -> Part:
for field_name, distributor in dpn_mappings:
s = component.get_field(field_name)
if s is None:
continue
- pn = types.SupplierPartNumber(value=s.value, supplier=distributor)
- part.referencesProp.add_part_number(pn)
+ part.add_spn(s.value)
return part
@@ -111,21 +110,15 @@ def work(sch, out: Path, strategy: MakeBomStrategy, new_mode, pretty):
parts = PartDb()
components = to_bom(sch)
for c in components:
- part = types.Part()
- part.referencesProp = types.ReferencesList()
- part.referencesProp.schematic_reference.append(types.SchematicReference(reference=c.ref))
+ xml = types.Part()
+ part = Part(xml)
+ part.add_schematic_reference(c.ref)
part = strategy.process_part(c, part)
if part is None:
continue
- if len(part.referencesProp.schematic_reference) == 0 and \
- len(part.referencesProp.part_number) == 0 and \
- len(part.referencesProp.supplier_part_number) == 0:
- # No need to dirty the xml with empty lists
- part.referencesProp = None
-
parts.add_entry(part, True)
save_db(out, parts)
diff --git a/src/ee/order/__init__.py b/src/ee/order/__init__.py
index a384cb7..83723ba 100644
--- a/src/ee/order/__init__.py
+++ b/src/ee/order/__init__.py
@@ -4,111 +4,104 @@ from typing import List, Tuple
from ee import EeException
from ee.db import ObjDb
-from ee.part import PartDb, load_db, save_db
-from ee.project import Project, report
-from ee.xml import types, bom_file_utils
+from ee.part import PartDb, load_db, save_db, Part
+from ee.project import Project, report, SupplierDescriptor
+from ee.xml import types
__all__ = ["create_order"]
class OrderPart(object):
def __init__(self, part: types.Part):
- self.part = part
- self.ref = next((ref.referenceProp for ref in bom_file_utils.schematic_references(part)), None)
+ self.part = Part(part)
+ ref = self.part.get_only_schematic_reference()
+ self.ref = ref.referenceProp if ref else None
self.available_from: List[Tuple[str, types.Part]] = []
- self.selected_supplier_and_part = None
+ self.selected_part = None
- rl = part.referencesProp = part.referencesProp or types.ReferencesList() # type: types.ReferencesList
- rl.schematic_referenceProp = rl.schematic_referenceProp or []
- rl.part_numberProp = rl.part_numberProp or []
- rl.supplier_part_numberProp = rl.supplier_part_numberProp or []
-
-
-def make_report(out_file, order_parts: ObjDb[OrderPart], has_unresolved_parts):
- parts_by_supplier = {}
-
- for supplier, order_parts in order_parts.index("selected_part").items():
- parts = {}
- for op in order_parts:
- p = op.selected_supplier_and_part[1]
- parts[p.uriProp] = p
- parts_by_supplier[supplier] = parts.values()
+def make_report(out_file, has_unresolved_parts, order_parts: ObjDb[OrderPart], supplier_parts: ObjDb[Path]):
kwargs = {
"order_parts": order_parts,
- "parts_by_supplier": parts_by_supplier,
+ "supplier_parts": supplier_parts,
"has_unresolved_parts": has_unresolved_parts,
}
report.save_report("ee.order", "order.rst.j2", out_file, **kwargs)
-def create_order(project: Project, schematic_path: Path, out_path: Path, part_db_dirs: List[Path],
+def create_order(project: Project, schematic_path: Path, out_path: Path, part_dbs: List[Path],
fail_on_missing_parts: bool):
- sch_db = load_db(schematic_path)
-
- dbs = [(path.parent.name, load_db(path)) for path in part_db_dirs]
-
- def supplier_index(op: OrderPart):
- return [spn.supplierProp for spn in bom_file_utils.supplier_part_numbers(op.part)]
-
- def selected_part_index(op: OrderPart):
- return [op.selected_supplier_and_part[0]] if op.selected_supplier_and_part else None
-
- def available_from_index(op: OrderPart):
- return set([s for s, s_part in op.available_from])
-
- def supplier_part_index(op: OrderPart):
- return set([s_part.uriProp for s, s_part in op.available_from])
-
- def pn_index(op: OrderPart):
- return [pn.value for pn in bom_file_utils.part_numbers(op.part)]
+ supplier_parts = ObjDb[Part]()
+ supplier_parts.add_unique_index("uri", lambda p: p.uri)
+ supplier_parts.add_index("spn", lambda p: [ref.valueProp for ref in p.get_spns()],
+ multiple=True)
+ supplier_pn_idx = supplier_parts.add_multi_index("supplier,pn", lambda p: [
+ (p.supplier, ref.valueProp) for ref in p.get_mpns()], multiple=True)
+ supplier_spn_idx = supplier_parts.add_multi_index("supplier,spn", lambda p: [
+ (p.supplier, ref.valueProp) for ref in p.get_spns()], multiple=True)
+
+ suppliers: List[SupplierDescriptor] = [project.get_supplier_by_key(path.parent.name) for path in part_dbs]
+ for path in part_dbs:
+ for xml in load_db(path).iterparts():
+ if not xml.supplierProp:
+ continue
+ supplier_parts.add(Part(xml))
+ sch_db = load_db(schematic_path)
order_parts: ObjDb[OrderPart] = ObjDb[OrderPart]()
+ order_parts.add_multi_index("supplier,pn", lambda op: [
+ (op.part.supplierProp, ref.valueProp) for ref in
+ op.part.get_mpns()] if op.part.supplier else None, multiple=True)
+ order_parts.add_multi_index("supplier,spn", lambda op: [
+ (op.part.supplier, ref.valueProp) for ref in op.part.get_spns()], multiple=True)
+
for sch_part in sch_db.iterparts():
order_parts.add(OrderPart(sch_part))
for order_part in order_parts:
- sch_part_numbers = order_part.part.referencesProp.part_number
- sch_supplier_part_numbers: List[types.SupplierPartNumber] = order_part.part.referencesProp.supplier_part_number
+ sch_part_numbers = [pn.valueProp for pn in order_part.part.get_mpns()]
+ sch_supplier_part_numbers = [spn.valueProp for spn in order_part.part.get_spns()]
- for supplier, db in dbs:
- for supplier_part in db.iterparts(sort=True):
- for sch_pn in sch_part_numbers:
- for pn in bom_file_utils.part_numbers(supplier_part):
- if sch_pn.valueProp == pn.valueProp:
- order_part.available_from.append((supplier, supplier_part))
+ for supplier in suppliers:
+ pns = supplier_pn_idx.get(supplier.uri)
+ spns = supplier_spn_idx.get(supplier.uri)
- for sch_spn in sch_supplier_part_numbers:
- for spn in bom_file_utils.supplier_part_numbers(supplier_part):
- if sch_spn.valueProp == spn.valueProp and sch_spn.supplierProp == spn.supplierProp:
- order_part.available_from.append((supplier, supplier_part))
+ for sch_pn in sch_part_numbers:
+ for supplier_part in pns.get(sch_pn, []):
+ order_part.available_from.append((supplier.uri, supplier_part))
+ for sch_spn in sch_supplier_part_numbers:
+ for supplier_part in spns.get(sch_spn, []):
+ order_part.available_from.append((supplier.uri, supplier_part))
has_unresolved_parts = False
for order_part in order_parts:
if len(order_part.available_from) == 0:
has_unresolved_parts = True
elif len(order_part.available_from) == 1:
- order_part.selected_supplier_and_part = order_part.available_from[0]
+ order_part.selected_part = order_part.available_from[0]
else:
raise EeException("unimplemented: part available from multiple suppliers")
+ order_parts.add_index("partUri", lambda op: op.selected_part[1].uri if op.selected_part else None)
+ order_parts.add_multi_index("supplier,part", lambda op: (
+ op.selected_part[0], op.selected_part[1].uri) if op.selected_part else None)
+
if has_unresolved_parts and fail_on_missing_parts:
raise EeException("The order has parts that can't be found from any supplier")
- order_parts.add_index("selected_part", selected_part_index)
-
out_file = project.report_dir / (os.path.splitext(out_path.name)[0] + ".rst")
- make_report(out_file, order_parts, has_unresolved_parts)
+ make_report(out_file, has_unresolved_parts, order_parts, supplier_parts)
out_parts = PartDb()
for order_part in order_parts:
- if not order_part.selected_supplier_and_part:
+ if not order_part.selected_part:
continue
- supplier, supplier_part = order_part.selected_supplier_and_part
+ supplier, supplier_part = order_part.selected_part
- references = types.ReferencesList(schematic_reference=order_part.part.referencesProp.schematic_reference)
- part = types.Part(uri=supplier_part.uri, references=references)
+ part = Part(types.Part(supplier=supplier_part.supplier))
+ part.add_schematic_reference(order_part.part.get_exactly_one_schematic_reference().referenceProp)
+ part.add_part_reference(supplier_part.uri)
out_parts.add_entry(part, True)
diff --git a/src/ee/order/templates/order.rst.j2 b/src/ee/order/templates/order.rst.j2
index bc382a2..8dad217 100644
--- a/src/ee/order/templates/order.rst.j2
+++ b/src/ee/order/templates/order.rst.j2
@@ -1,3 +1,4 @@
+{% set order_part_uri_idx = order_parts.index("partUri") -%}
Order
=====
@@ -6,6 +7,8 @@ Has unresolved parts: {{ "yes" if has_unresolved_parts else "no" }}.
Parts for Order
===============
{% for op in order_parts %}
+.. _ref-{{ op.ref }}:
+
{{ op.ref | subsection }}
{% if op.available_from|length == 0 %}
Part not resolved.
@@ -23,30 +26,39 @@ MANY
Part details
============
-{% for supplier, parts in parts_by_supplier.items() %}
+{%- set part_by_uri=supplier_parts.index("uri") %}
+{% for supplier, partUris in order_parts.index("supplier,part").items() %}
{{ ("From " + supplier) | subsection }}
-{% for part in parts %}
+{% for partUri in partUris %}
+{%- set part=part_by_uri.get_single(partUri) %}
{%- set pn=part|first_pn %}
{%- set spn=part|first_spn %}
{%- set title=pn.valueProp if pn else (spn.valueProp if spn else "???") %}
-{%- set links=part.linksProp.link %}
.. _part-{{title}}:
{{ title|subsubsection }}
-{#-
+=========== ===
+{%- if part.description %}
+Description {{ part.description }}
+{%- endif %}
+MPN {{ pn.value }}
+SPN {{ spn.value }}
+Used by: {% for op in order_part_uri_idx.get(part.uriProp) %}`{{ op.ref }} <ref-{{ op.ref }}_>`_{{ ", " if not loop.last }}{% endfor %}
+=========== ===
+{#
Facts
.....
{% for f in part.facts.fact %}
f={{f}}
{% endfor %}
-#}
-Media
-.....
+#}
+Documentation
+.............
-{% for l in links %}
+{% for l in part.get_links() %}
{%- if l.relationProp == "http://purl.org/ee/link-relation#documentation" %}
* `{{ l.title }} <{{ l.url }}>`__
{%- endif %}
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)
diff --git a/src/ee/project/__init__.py b/src/ee/project/__init__.py
index 6851256..bca9984 100644
--- a/src/ee/project/__init__.py
+++ b/src/ee/project/__init__.py
@@ -1,7 +1,9 @@
import configparser
from pathlib import Path
+from ee import EeException
from ee.tools import mk_parents
+from ee.xml.uris import DIGIKEY_URI
def load_config(project_dir: Path) -> configparser.ConfigParser:
@@ -17,6 +19,12 @@ def load_config(project_dir: Path) -> configparser.ConfigParser:
return config
+class SupplierDescriptor(object):
+ def __init__(self, key: str, uri: str):
+ self.key = key
+ self.uri = uri
+
+
class Project(object):
def __init__(self, project_dir: Path, cfg: configparser.ConfigParser):
self.report_dir = project_dir / "ee" / "reports"
@@ -24,6 +32,15 @@ class Project(object):
self.project_dir = project_dir
self._cfg = cfg
+ # TODO: read from config
+ self._suppliers = [SupplierDescriptor("digikey", DIGIKEY_URI)]
+
+ def get_supplier_by_key(self, key) -> SupplierDescriptor:
+ sd = next((s for s in self._suppliers if s.key == key), None)
+ if sd:
+ return sd
+ raise EeException("No such supplier configured: {}".format(key))
+
@property
def cfg(self):
return self._cfg
diff --git a/src/ee/project/report.py b/src/ee/project/report.py
index 80e590a..26cdaa3 100644
--- a/src/ee/project/report.py
+++ b/src/ee/project/report.py
@@ -3,8 +3,9 @@ from typing import Optional
from jinja2 import Environment, PackageLoader, select_autoescape
+from ee.part import Part
from ee.tools import mk_parents
-from ee.xml import types, bom_file_utils
+from ee.xml import types
class Message(object):
@@ -29,12 +30,16 @@ def subsubsubsection_filter(s: str):
return "{}\n{}".format(s, "." * len(s))
-def first_pn_filter(part: types.Part):
- return next(iter(bom_file_utils.part_numbers(part)), None)
+def first_ref_filter(part: Part) -> Optional[types.SchematicReference]:
+ return part.get_only_schematic_reference()
-def first_spn_filter(part: types.Part):
- return next(iter(bom_file_utils.supplier_part_numbers(part)), None)
+def first_pn_filter(part: Part) -> Optional[types.PartNumber]:
+ return part.get_only_mpn()
+
+
+def first_spn_filter(part: Part) -> Optional[types.SupplierPartNumber]:
+ return part.get_only_spn()
def save_report(package: str, template_name: str, out_file: Path, **kwargs):
@@ -45,6 +50,7 @@ def save_report(package: str, template_name: str, out_file: Path, **kwargs):
env.filters["subsection"] = subsection_filter
env.filters["subsubsection"] = subsubsection_filter
env.filters["subsubsubsection"] = subsubsubsection_filter
+ env.filters["first_ref"] = first_ref_filter
env.filters["first_pn"] = first_pn_filter
env.filters["first_spn"] = first_spn_filter
diff --git a/src/ee/supplier/seeed.py b/src/ee/supplier/seeed.py
index 2df2068..45cff44 100644
--- a/src/ee/supplier/seeed.py
+++ b/src/ee/supplier/seeed.py
@@ -9,7 +9,7 @@ import requests
from selenium import webdriver
import ee._utils
-from ee.part import PartDb, save_db
+from ee.part import Part, PartDb, save_db
from ee.xml import types
_title_re = re.compile(r"^([^(]*)\( *[0-9]* *\) *")
@@ -113,13 +113,10 @@ def download_opls(out_dir: Path, cache_dir: Path):
ladder_price = p["ladder_price"]
- part = types.Part(references=types.ReferencesList(), price_breaks=types.PriceBreakList())
- part_numbers = part.referencesProp.part_numberProp
- supplier_part_numbers = part.referencesProp.supplier_part_numberProp
- pbs = part.price_breaksProp.price_breakProp
+ xml = types.Part(references=types.ReferencesList(), price_breaks=types.PriceBreakList())
+ xml.supplierProp = supplier_uri
- if desc:
- part.descriptionProp = desc
+ xml.descriptionProp = desc
uri_params = {
"opl": opls_type,
@@ -128,17 +125,18 @@ def download_opls(out_dir: Path, cache_dir: Path):
uri_params["sku"] = sku
if mpn:
uri_params["mpn"] = mpn
- part.uriProp = "http://purl.org/ee/supplier/seeed?{}".format(urlencode(uri_params))
+ xml.uriProp = "http://purl.org/ee/supplier/seeed?{}".format(urlencode(uri_params))
+
+ part = Part(xml)
if mpn:
- part_numbers.append(types.PartNumber(mpn))
+ part.add_mpn(mpn)
if sku:
- supplier_part_numbers.append(types.SupplierPartNumber(value=mpn, supplier=supplier_uri))
+ part.add_spn(sku)
for item in ladder_price:
price = money.parse(item["price"], currency="USD")
- amount = types.Amount(value=price.amount, currency=price.currency)
- pbs.append(types.PriceBreak(quantity=item["qty"], amount=amount))
+ part.add_price_break(item["qty"], price)
db.add_entry(part, True)
diff --git a/src/ee/xml/bom_file_utils.py b/src/ee/xml/bom_file_utils.py
deleted file mode 100644
index 97b609f..0000000
--- a/src/ee/xml/bom_file_utils.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from typing import List, Optional
-
-from ee.xml import types
-
-__all__ = [
- "facts",
- "find_root_tag",
- "schematic_references",
- "part_numbers",
- "supplier_part_numbers",
-]
-
-
-def find_root_tag(root):
- return next((tag for tag, klass in types.GDSClassesMapping.items() if klass == type(root)), None)
-
-
-def schematic_references(part: types.Part) -> List[types.SchematicReference]:
- return [] if part.referencesProp is None or part.referencesProp.schematic_reference is None else \
- part.referencesProp.schematic_reference
-
-
-def part_numbers(part: types.Part) -> List[types.PartNumber]:
- return [] if part.referencesProp is None or part.referencesProp.part_number is None else \
- part.referencesProp.part_number
-
-
-def supplier_part_numbers(part: types.Part) -> List[types.SupplierPartNumber]:
- return [] if part.referencesProp is None or part.referencesProp.supplier_part_number is None else \
- part.referencesProp.supplier_part_number
-
-
-def facts(part: types.Part, create=False) -> Optional[types.FactList]:
- fs: types.FactList = part.factsProp
-
- if fs is not None:
- return fs
-
- if not create:
- return
-
- fs = types.FactList()
- part.factsProp = fs
- return fs
-
-
-def find_fact(fs: types.FactList, key: str) -> Optional[types.Fact]:
- l: List[types.Fact] = fs.factProp
- return next((f for f in l if f.keyProp == key), None)
diff --git a/src/ee/xml/types.py b/src/ee/xml/types.py
index 60d659d..8e5e39f 100644
--- a/src/ee/xml/types.py
+++ b/src/ee/xml/types.py
@@ -807,10 +807,11 @@ class PartDb(GeneratedsSuper):
class Part(GeneratedsSuper):
subclass = None
superclass = None
- def __init__(self, uri=None, part_type=None, description=None, links=None, references=None, distributor_info=None, facts=None, price_breaks=None, **kwargs_):
+ def __init__(self, uri=None, supplier=None, part_type=None, description=None, links=None, references=None, distributor_info=None, facts=None, price_breaks=None, **kwargs_):
self.original_tagname_ = None
self.parent_object_ = kwargs_.get('parent_object_')
self.uri = _cast(None, uri)
+ self.supplier = supplier
self.part_type = part_type
self.description = description
self.links = links
@@ -829,6 +830,11 @@ class Part(GeneratedsSuper):
else:
return Part(*args_, **kwargs_)
factory = staticmethod(factory)
+ def get_supplier(self):
+ return self.supplier
+ def set_supplier(self, supplier):
+ self.supplier = supplier
+ supplierProp = property(get_supplier, set_supplier)
def get_part_type(self):
return self.part_type
def set_part_type(self, part_type):
@@ -871,6 +877,7 @@ class Part(GeneratedsSuper):
uriProp = property(get_uri, set_uri)
def hasContent_(self):
if (
+ self.supplier is not None or
self.part_type is not None or
self.description is not None or
self.links is not None or
@@ -912,6 +919,9 @@ class Part(GeneratedsSuper):
eol_ = '\n'
else:
eol_ = ''
+ if self.supplier is not None:
+ showIndent(outfile, level, pretty_print)
+ outfile.write('<%ssupplier>%s</%ssupplier>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.supplier), input_name='supplier')), namespaceprefix_ , eol_))
if self.part_type is not None:
showIndent(outfile, level, pretty_print)
outfile.write('<%spart-type>%s</%spart-type>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.part_type), input_name='part-type')), namespaceprefix_ , eol_))
@@ -941,7 +951,11 @@ class Part(GeneratedsSuper):
already_processed.add('uri')
self.uri = value
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
- if nodeName_ == 'part-type':
+ if nodeName_ == 'supplier':
+ supplier_ = child_.text
+ supplier_ = self.gds_validate_string(supplier_, node, 'supplier')
+ self.supplier = supplier_
+ elif nodeName_ == 'part-type':
part_type_ = child_.text
part_type_ = self.gds_validate_string(part_type_, node, 'part_type')
self.part_type = part_type_
@@ -1066,38 +1080,38 @@ class PartList(GeneratedsSuper):
# end class PartList
-class PartUri(GeneratedsSuper):
+class PartReference(GeneratedsSuper):
subclass = None
superclass = None
- def __init__(self, value=None, **kwargs_):
+ def __init__(self, part_uri=None, **kwargs_):
self.original_tagname_ = None
self.parent_object_ = kwargs_.get('parent_object_')
- self.value = value
+ self.part_uri = part_uri
def factory(*args_, **kwargs_):
if CurrentSubclassModule_ is not None:
subclass = getSubclassFromModule_(
- CurrentSubclassModule_, PartUri)
+ CurrentSubclassModule_, PartReference)
if subclass is not None:
return subclass(*args_, **kwargs_)
- if PartUri.subclass:
- return PartUri.subclass(*args_, **kwargs_)
+ if PartReference.subclass:
+ return PartReference.subclass(*args_, **kwargs_)
else:
- return PartUri(*args_, **kwargs_)
+ return PartReference(*args_, **kwargs_)
factory = staticmethod(factory)
- def get_value(self):
- return self.value
- def set_value(self, value):
- self.value = value
- valueProp = property(get_value, set_value)
+ def get_part_uri(self):
+ return self.part_uri
+ def set_part_uri(self, part_uri):
+ self.part_uri = part_uri
+ part_uriProp = property(get_part_uri, set_part_uri)
def hasContent_(self):
if (
- self.value is not None
+ self.part_uri is not None
):
return True
else:
return False
- def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartUri', pretty_print=True):
- imported_ns_def_ = GenerateDSNamespaceDefs_.get('PartUri')
+ def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartReference', pretty_print=True):
+ imported_ns_def_ = GenerateDSNamespaceDefs_.get('PartReference')
if imported_ns_def_ is not None:
namespacedef_ = imported_ns_def_
if pretty_print:
@@ -1109,24 +1123,24 @@ class PartUri(GeneratedsSuper):
showIndent(outfile, level, pretty_print)
outfile.write('<%s%s%s' % (namespaceprefix_, name_, namespacedef_ and ' ' + namespacedef_ or '', ))
already_processed = set()
- self.exportAttributes(outfile, level, already_processed, namespaceprefix_, name_='PartUri')
+ self.exportAttributes(outfile, level, already_processed, namespaceprefix_, name_='PartReference')
if self.hasContent_():
outfile.write('>%s' % (eol_, ))
- self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='PartUri', pretty_print=pretty_print)
+ self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='PartReference', pretty_print=pretty_print)
showIndent(outfile, level, pretty_print)
outfile.write('</%s%s>%s' % (namespaceprefix_, name_, eol_))
else:
outfile.write('/>%s' % (eol_, ))
- def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='PartUri'):
+ def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='PartReference'):
pass
- def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartUri', fromsubclass_=False, pretty_print=True):
+ def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartReference', fromsubclass_=False, pretty_print=True):
if pretty_print:
eol_ = '\n'
else:
eol_ = ''
- if self.value is not None:
+ if self.part_uri is not None:
showIndent(outfile, level, pretty_print)
- outfile.write('<%svalue>%s</%svalue>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.value), input_name='value')), namespaceprefix_ , eol_))
+ outfile.write('<%spart-uri>%s</%spart-uri>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.part_uri), input_name='part-uri')), namespaceprefix_ , eol_))
def build(self, node):
already_processed = set()
self.buildAttributes(node, node.attrib, already_processed)
@@ -1137,11 +1151,11 @@ class PartUri(GeneratedsSuper):
def buildAttributes(self, node, attrs, already_processed):
pass
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
- if nodeName_ == 'value':
- value_ = child_.text
- value_ = self.gds_validate_string(value_, node, 'value')
- self.value = value_
-# end class PartUri
+ if nodeName_ == 'part-uri':
+ part_uri_ = child_.text
+ part_uri_ = self.gds_validate_string(part_uri_, node, 'part_uri')
+ self.part_uri = part_uri_
+# end class PartReference
class PartNumber(GeneratedsSuper):
@@ -1225,11 +1239,10 @@ class PartNumber(GeneratedsSuper):
class SupplierPartNumber(GeneratedsSuper):
subclass = None
superclass = None
- def __init__(self, value=None, supplier=None, **kwargs_):
+ def __init__(self, value=None, **kwargs_):
self.original_tagname_ = None
self.parent_object_ = kwargs_.get('parent_object_')
self.value = value
- self.supplier = supplier
def factory(*args_, **kwargs_):
if CurrentSubclassModule_ is not None:
subclass = getSubclassFromModule_(
@@ -1246,15 +1259,9 @@ class SupplierPartNumber(GeneratedsSuper):
def set_value(self, value):
self.value = value
valueProp = property(get_value, set_value)
- def get_supplier(self):
- return self.supplier
- def set_supplier(self, supplier):
- self.supplier = supplier
- supplierProp = property(get_supplier, set_supplier)
def hasContent_(self):
if (
- self.value is not None or
- self.supplier is not None
+ self.value is not None
):
return True
else:
@@ -1290,9 +1297,6 @@ class SupplierPartNumber(GeneratedsSuper):
if self.value is not None:
showIndent(outfile, level, pretty_print)
outfile.write('<%svalue>%s</%svalue>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.value), input_name='value')), namespaceprefix_ , eol_))
- if self.supplier is not None:
- showIndent(outfile, level, pretty_print)
- outfile.write('<%ssupplier>%s</%ssupplier>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.supplier), input_name='supplier')), namespaceprefix_ , eol_))
def build(self, node):
already_processed = set()
self.buildAttributes(node, node.attrib, already_processed)
@@ -1307,10 +1311,6 @@ class SupplierPartNumber(GeneratedsSuper):
value_ = child_.text
value_ = self.gds_validate_string(value_, node, 'value')
self.value = value_
- elif nodeName_ == 'supplier':
- supplier_ = child_.text
- supplier_ = self.gds_validate_string(supplier_, node, 'supplier')
- self.supplier = supplier_
# end class SupplierPartNumber
@@ -1395,17 +1395,17 @@ class SchematicReference(GeneratedsSuper):
class ReferencesList(GeneratedsSuper):
subclass = None
superclass = None
- def __init__(self, schematic_reference=None, part_uri=None, part_number=None, supplier_part_number=None, **kwargs_):
+ def __init__(self, part_reference=None, schematic_reference=None, part_number=None, supplier_part_number=None, **kwargs_):
self.original_tagname_ = None
self.parent_object_ = kwargs_.get('parent_object_')
+ if part_reference is None:
+ self.part_reference = []
+ else:
+ self.part_reference = part_reference
if schematic_reference is None:
self.schematic_reference = []
else:
self.schematic_reference = schematic_reference
- if part_uri is None:
- self.part_uri = []
- else:
- self.part_uri = part_uri
if part_number is None:
self.part_number = []
else:
@@ -1425,6 +1425,19 @@ class ReferencesList(GeneratedsSuper):
else:
return ReferencesList(*args_, **kwargs_)
factory = staticmethod(factory)
+ def get_part_reference(self):
+ return self.part_reference
+ def set_part_reference(self, part_reference):
+ self.part_reference = part_reference
+ def add_part_reference(self, value):
+ self.part_reference.append(value)
+ def add_part_reference(self, value):
+ self.part_reference.append(value)
+ def insert_part_reference_at(self, index, value):
+ self.part_reference.insert(index, value)
+ def replace_part_reference_at(self, index, value):
+ self.part_reference[index] = value
+ part_referenceProp = property(get_part_reference, set_part_reference)
def get_schematic_reference(self):
return self.schematic_reference
def set_schematic_reference(self, schematic_reference):
@@ -1438,19 +1451,6 @@ class ReferencesList(GeneratedsSuper):
def replace_schematic_reference_at(self, index, value):
self.schematic_reference[index] = value
schematic_referenceProp = property(get_schematic_reference, set_schematic_reference)
- def get_part_uri(self):
- return self.part_uri
- def set_part_uri(self, part_uri):
- self.part_uri = part_uri
- def add_part_uri(self, value):
- self.part_uri.append(value)
- def add_part_uri(self, value):
- self.part_uri.append(value)
- def insert_part_uri_at(self, index, value):
- self.part_uri.insert(index, value)
- def replace_part_uri_at(self, index, value):
- self.part_uri[index] = value
- part_uriProp = property(get_part_uri, set_part_uri)
def get_part_number(self):
return self.part_number
def set_part_number(self, part_number):
@@ -1479,8 +1479,8 @@ class ReferencesList(GeneratedsSuper):
supplier_part_numberProp = property(get_supplier_part_number, set_supplier_part_number)
def hasContent_(self):
if (
+ self.part_reference or
self.schematic_reference or
- self.part_uri or
self.part_number or
self.supplier_part_number
):
@@ -1515,10 +1515,10 @@ class ReferencesList(GeneratedsSuper):
eol_ = '\n'
else:
eol_ = ''
+ for part_reference_ in self.part_reference:
+ part_reference_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-reference', pretty_print=pretty_print)
for schematic_reference_ in self.schematic_reference:
schematic_reference_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='schematic-reference', pretty_print=pretty_print)
- for part_uri_ in self.part_uri:
- part_uri_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-uri', pretty_print=pretty_print)
for part_number_ in self.part_number:
part_number_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-number', pretty_print=pretty_print)
for supplier_part_number_ in self.supplier_part_number:
@@ -1533,16 +1533,16 @@ class ReferencesList(GeneratedsSuper):
def buildAttributes(self, node, attrs, already_processed):
pass
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
- if nodeName_ == 'schematic-reference':
+ if nodeName_ == 'part-reference':
+ obj_ = PartReference.factory(parent_object_=self)
+ obj_.build(child_)
+ self.part_reference.append(obj_)
+ obj_.original_tagname_ = 'part-reference'
+ elif nodeName_ == 'schematic-reference':
obj_ = SchematicReference.factory(parent_object_=self)
obj_.build(child_)
self.schematic_reference.append(obj_)
obj_.original_tagname_ = 'schematic-reference'
- elif nodeName_ == 'part-uri':
- obj_ = PartUri.factory(parent_object_=self)
- obj_.build(child_)
- self.part_uri.append(obj_)
- obj_.original_tagname_ = 'part-uri'
elif nodeName_ == 'part-number':
obj_ = PartNumber.factory(parent_object_=self)
obj_.build(child_)
@@ -2437,7 +2437,7 @@ __all__ = [
"PartDb",
"PartList",
"PartNumber",
- "PartUri",
+ "PartReference",
"PriceBreak",
"PriceBreakList",
"ReferencesList",