From 0149fcfa2bd9ac8c9f6b05851f7264f005aa2305 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 11 May 2019 14:48:15 +0200 Subject: drawio-to-parts: new tool. ee.xsd: new type: Assembly and AssemblyPart. Should probably be its own file type. ee.part: Better DSL instead of using the raw xml types. --- src/ee/digikey/search_parts.py | 2 +- src/ee/drawio.py | 153 +++++++++++---- src/ee/part/__init__.py | 202 ++++++++++++++++++- src/ee/part/excel.py | 9 +- src/ee/supplier/seeed.py | 2 +- src/ee/tools/drawio-to-parts.py | 20 -- src/ee/tools/drawio_decompress.py | 2 +- src/ee/tools/drawio_to_parts.py | 25 +++ src/ee/tools/templates/build.ninja.j2 | 9 + src/ee/xml/types.py | 357 ++++++++++++++++++++++++++++++++-- xsd/ee.xsd | 27 ++- 11 files changed, 713 insertions(+), 95 deletions(-) delete mode 100644 src/ee/tools/drawio-to-parts.py create mode 100644 src/ee/tools/drawio_to_parts.py diff --git a/src/ee/digikey/search_parts.py b/src/ee/digikey/search_parts.py index c7f981e..c248831 100644 --- a/src/ee/digikey/search_parts.py +++ b/src/ee/digikey/search_parts.py @@ -17,7 +17,7 @@ def resolved(supplier, p: DigikeyProduct) -> Part: distributor_info=types.DistributorInfo(state="resolved"), links=types.LinkList(), facts=types.FactList(), - references=types.ReferencesList()) + references=types.ReferenceList()) part = Part(xml) if p.url: diff --git a/src/ee/drawio.py b/src/ee/drawio.py index de98986..b079979 100644 --- a/src/ee/drawio.py +++ b/src/ee/drawio.py @@ -2,10 +2,14 @@ import base64 import urllib.parse import zlib from pathlib import Path -from typing import Mapping, MutableMapping +from typing import Mapping, MutableMapping, List, Optional from xml.dom import minidom + from lxml import etree +from ee.db import ObjDb +from ee.part import PartDb, save_db, load_db, Part, AssemblyPart + def decompress(input_stream, output_stream): doc = minidom.parse(input_stream) @@ -48,8 +52,8 @@ class GraphEdge(object): self.target_id = target_id self.value = value - self.source: GraphObject = None - self.target: GraphObject = None + self.source: Optional[GraphObject] = None + self.target: Optional[GraphObject] = None def add_attr(self, key, value): self.attrs[key] = value @@ -60,6 +64,10 @@ class GraphModel(object): self.objects = objects self.edges = edges + @property + def roots(self): + return [o for o in self.objects.values() if len(o.incoming) == 0] + @staticmethod def create(objects: Mapping[str, GraphObject], edges: Mapping[str, GraphEdge]) -> "GraphModel": for id_, edge in edges.items(): @@ -130,10 +138,72 @@ def load_graph(doc) -> GraphModel: return GraphModel.create(objects, edges) -def to_parts(in_path: Path, out_path: Path): +def to_parts(in_path: Path, out_path: Path, part_dbs: List[Path]): + parts: ObjDb[Part] = ObjDb[Part]() + description_idx = parts.add_index("description", lambda p: p.underlying.descriptionProp) + + def find_part(o: GraphObject): + if "part" in o.attrs: + d = o.attrs["part"] + else: + d = o.value + + hits = description_idx.get(d) + if len(hits) == 0: + # print("No part with description found in database: '{}'".format(d)) + return + elif len(hits) == 1: + found = hits[0] + return found + else: + # print("Found multiple parts with description '{}'".format(d)) + return + + def add_part(o: GraphObject): + print("obj: {}".format(o.value)) + + p = find_part(o) + + uri = p.uri if p else None + ap = AssemblyPart(uri) + + if uri: + ap.references.add_part_reference(uri) + + ap.references.add_description_reference(o.value) + + for out in o.outgoing.values(): + sub_part = add_part(out.target) + ap.add_sub_part(sub_part) + + # description = out.target.value + # print(" out: {}".format(description)) + # + # p = find_part(out.target) + # + # if p is None: + # continue + # + # ap.add_sub_part(p.uri) + + return ap + + for part_db in part_dbs: + for xml in load_db(part_db).iterparts(): + parts.add(Part(xml)) + doc = etree.parse(str(in_path)) + print(doc) graph = load_graph(doc) + db = PartDb() + a = db.assembly + + for root in graph.roots: + a.parts.append(add_part(root)) + + save_db(out_path, db) + def to_dot(in_path: Path, out_path: Path): def to_id(s: str): @@ -145,43 +215,44 @@ def to_dot(in_path: Path, out_path: Path): doc = etree.parse(str(in_path)) graph = load_graph(doc) - print("digraph parts {") - for id_, obj in graph.objects.items(): - if len(obj.attrs): - attr_str = "\\n".join(["{}={}".format(k, quote(v)) for k, v in obj.attrs.items()]) - print(" {}_attrs [shape=plaintext, label=\"{}\"]".format(to_id(obj.id), quote(attr_str))) - print(" {}_attrs -> {} [arrowhead=none,style=dotted]".format(to_id(obj.id), to_id(obj.id))) - - attrs = {} - if obj.value: - attrs["label"] = obj.value - - attr_str = ",".join(["{}=\"{}\"".format(k, quote(v)) for k, v in attrs.items()]) - print(" {} [{}];".format(to_id(obj.id), attr_str)) - - for id_, edge in graph.edges.items(): - source_id = edge.source.id - target_id = edge.target.id - - if len(edge.attrs): - print(" // source={}, target={}".format(source_id, target_id)) - attr_str = "\\n".join(["{}={}".format(k, quote(v)) for k, v in edge.attrs.items()]) - - print(" {}_fake [shape=plaintext, label=\"{}\"]".format(to_id(edge.target.id), attr_str)) - print(" {}_fake -> {}".format(to_id(edge.target.id), to_id(edge.target.id))) - # source_id = "{}_fake".format(to_id(edge.id)) - target_id = "{}_fake".format(to_id(edge.target.id)) - arrowhead="none" - else: - arrowhead="normal" + with open(str(out_path), "w") as f: + print("digraph parts {", file=f) + for id_, obj in graph.objects.items(): + if len(obj.attrs): + attr_str = "\\n".join(["{}={}".format(k, quote(v)) for k, v in obj.attrs.items()]) + print(" {}_attrs [shape=plaintext, label=\"{}\"]".format(to_id(obj.id), quote(attr_str)), file=f) + print(" {}_attrs -> {} [arrowhead=none,style=dotted]".format(to_id(obj.id), to_id(obj.id)), file=f) + + attrs = {} + if obj.value: + attrs["label"] = obj.value + + attr_str = ",".join(["{}=\"{}\"".format(k, quote(v)) for k, v in attrs.items()]) + print(" {} [{}];".format(to_id(obj.id), attr_str), file=f) + + for id_, edge in graph.edges.items(): + source_id = edge.source.id + target_id = edge.target.id + + if len(edge.attrs): + print(" // source={}, target={}".format(source_id, target_id), file=f) + attr_str = "\\n".join(["{}={}".format(k, quote(v)) for k, v in edge.attrs.items()]) - attrs = {} - # if edge.value: - # attrs["label"] = edge.value + print(" {}_fake [shape=plaintext, label=\"{}\"]".format(to_id(edge.target.id), attr_str), file=f) + print(" {}_fake -> {}".format(to_id(edge.target.id), to_id(edge.target.id)), file=f) + # source_id = "{}_fake".format(to_id(edge.id)) + target_id = "{}_fake".format(to_id(edge.target.id)) + arrowhead = "none" + else: + arrowhead = "normal" + + attrs = {} + # if edge.value: + # attrs["label"] = edge.value - # attr_str = ",".join(["{}=\"{}\"".format(k, quote(v)) for k, v in attrs.items()]) + # attr_str = ",".join(["{}=\"{}\"".format(k, quote(v)) for k, v in attrs.items()]) - print(" {} -> {} [arrowhead={}];".format(to_id(source_id), to_id(target_id), arrowhead)) - for k, v in edge.attrs.items(): - print(" // {}={}".format(k, v)) - print("}") + print(" {} -> {} [arrowhead={}];".format(to_id(source_id), to_id(target_id), arrowhead), file=f) + for k, v in edge.attrs.items(): + print(" // {}={}".format(k, v)) + print("}") diff --git a/src/ee/part/__init__.py b/src/ee/part/__init__.py index 4354771..996eeff 100644 --- a/src/ee/part/__init__.py +++ b/src/ee/part/__init__.py @@ -13,11 +13,152 @@ __all__ = [ ] +class Reference(object): + pass + + def to_xml(self): + return None + + +class PartReference(Reference): + def __init__(self, uri: str): + self.uri = uri + + def to_xml(self): + return types.PartReference(part_uri=self.uri) + + +class SchematicReference(Reference): + def __init__(self, reference: str): + self.reference = reference + + def to_xml(self): + return types.SchematicReference(reference=self.reference) + + +class PartNumber(Reference): + def __init__(self, value: str): + self.value = value + + def to_xml(self): + return types.PartNumber(value=self.value) + + +class SupplierPartNumber(Reference): + def __init__(self, value: str): + self.value = value + + def to_xml(self): + return types.SupplierPartNumber(value=self.value) + + +class ReferenceList(object): + def __init__(self, part_uri): + self.part_uri_ = part_uri + self.part_references: List[PartReference] = [] + self.schematic_references: List[SchematicReference] = [] + self.mpns: List[PartNumber] = [] + self.spns: List[SupplierPartNumber] = [] + self.description_references: List[str] = [] + + def to_xml(self): + part_references = [r.to_xml() for r in self.part_references if isinstance(r, PartReference)] + schematic_references = [r.to_xml() for r in self.schematic_references if isinstance(r, SchematicReference)] + mpns = [r.to_xml() for r in self.mpns if isinstance(r, PartNumber)] + spns = [r.to_xml() for r in self.spns if isinstance(r, SupplierPartNumber)] + description_references = self.description_references + + if len(part_references) or len(schematic_references) or len(mpns) or len(spns) or \ + len(description_references): + return types.ReferenceList(part_reference=part_references, + schematic_reference=schematic_references, + part_number=mpns, + supplier_part_number=spns, + description=description_references) + + # Part Reference + + def add_part_reference(self, uri): + self.part_references.append(PartReference(uri)) + + def get_exactly_one_part_reference(self) -> PartReference: + refs = self.part_references + if len(refs) == 0: + raise EeException("This part does not contain any part references{}". + format(", uri=" + self.part_uri_ if self.part_uri_ else "")) + if len(refs) != 1: + raise EeException("This part does not contain exactly one part reference: {}". + format(", ".join([ref.uri for ref in refs]))) + + return refs[0] + + # Schematic references + + def add_schematic_reference(self, ref): + self.schematic_references.append(SchematicReference(reference=ref)) + + def get_only_schematic_reference(self) -> Optional[SchematicReference]: + return next(iter(self.schematic_references), None) + + def get_exactly_one_schematic_reference(self) -> SchematicReference: + refs = self.schematic_references + if len(refs) == 0: + raise EeException("This part does not contain any schematic references{}". + format(", uri=" + self.part_uri_ if self.part_uri_ else "")) + if len(refs) != 1: + raise EeException("This part does not contain exactly one schematic reference: {}". + format(", ".join([ref.reference for ref in refs]))) + + return refs[0] + + # MPNs + + def add_mpn(self, mpn: str): + self.mpns.append(PartNumber(value=mpn)) + + def get_only_mpn(self) -> Optional[PartNumber]: + return next(iter(self.mpns), None) + + def get_exactly_one_mpn(self) -> PartNumber: + mpns = self.mpns + if len(mpns) == 0: + raise EeException("This part does not contain any manufacturer part numbers{}". + format(", uri=" + self.part_uri_ if self.part_uri_ else "")) + if len(mpns) != 1: + raise EeException("This part does not contain exactly one mpn: {}". + format(", ".join([mpn.value for mpn in mpns]))) + + return mpns[0] + + # SPNs + + def add_spn(self, mpn: str): + self.spns.append(SupplierPartNumber(value=mpn)) + + def get_only_spn(self) -> Optional[SupplierPartNumber]: + return next(iter(self.spns), None) + + def get_exactly_one_spn(self) -> SupplierPartNumber: + spns = self.spns + if len(spns) == 0: + raise EeException("This part does not contain any supplier part numbers{}". + format(", uri=" + self.part_uri_ if self.part_uri_ else "")) + if len(spns) != 1: + raise EeException("This part does not contain exactly one spn: {}". + format(", ".join([spn.value for spn in spns]))) + + return spns[0] + + def add_description_reference(self, description: str): + self.description_references.append(description) + + +# TODO: Replace self.xml.referencesProp with ReferenceList 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.referencesProp = xml.referencesProp if xml.referencesProp is not None else types.ReferenceList() 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() @@ -172,11 +313,27 @@ class Entry(object): self.pn = next((p.valueProp for p in Part(part).get_mpns()), None) +class AssemblyPart(object): + def __init__(self, uri: Optional[str]): + self.count = 0 + self.sub_parts: List[AssemblyPart] = [] + self.references = ReferenceList(uri) + + def add_sub_part(self, ap: "AssemblyPart"): + self.sub_parts.append(ap) + + +class Assembly(object): + def __init__(self): + self.parts: List[AssemblyPart] = [] + + class PartDb(object): def __init__(self): self.parts: List[Entry] = [] self.pn_index: MutableMapping[str, Entry] = {} self.new_entries = 0 + self._assembly: Optional[Assembly] = None def add_entry(self, part: Union[Part, types.Part], new: bool): if isinstance(part, Part): @@ -202,6 +359,16 @@ class PartDb(object): entry = self.pn_index.get(pn, None) return entry.part if entry else None + @property + def has_assembly(self): + return self._assembly is not None + + @property + def assembly(self): + if self._assembly is None: + self._assembly = Assembly() + return self._assembly + def load_db(path: Path) -> PartDb: db = PartDb() @@ -223,12 +390,35 @@ def find_root_tag(root): def save_db(path: Path, db: PartDb, sort=False): part_db = types.PartDb() - parts = part_db.parts = types.PartList() - for part in db.iterparts(sort=sort): - p = Part(part) - p.clean_xml() - parts.partProp.append(p.underlying) + if db.size() > 0: + part_db.parts = types.PartList() + + for part in db.iterparts(sort=sort): + p = Part(part) + p.clean_xml() + part_db.parts.partProp.append(p.underlying) + + if db.has_assembly: + + def to_xml(ap: AssemblyPart): + xml = types.AssemblyPart() + if ap.count != 0: + xml.countProp = ap.count + if ap.sub_parts: + xml.sub_partsProp = types.AssemblyPartList([to_xml(ap_) for ap_ in ap.sub_parts]) + + xml.set_references(ap.references.to_xml()) + + return xml + + assembly = db.assembly + part_list = types.AssemblyPartList() + + for ap in assembly.parts: + part_list.add_assembly_part(to_xml(ap)) + + part_db.assemblyProp = types.Assembly(assembly_parts=part_list) with path.open("w") as f: part_db.export(outfile=f, level=0, name_=find_root_tag(part_db)) diff --git a/src/ee/part/excel.py b/src/ee/part/excel.py index 12b583d..b0c4a2b 100644 --- a/src/ee/part/excel.py +++ b/src/ee/part/excel.py @@ -1,3 +1,4 @@ +import uuid from pathlib import Path from typing import Optional, Mapping @@ -38,12 +39,12 @@ def from_excel(path: Path, sheet_name: Optional[str]) -> PartDb: print("Bad part, line #{}. MPN or description is required".format(idx)) continue - part = Part(types.Part()) + uri = "urn:uuid:{}".format(uuid.uuid5(uuid.NAMESPACE_URL, url)) + part = Part(types.Part(uri=uri)) - if not mpn: - mpn = desc.replace(" ", "-").lower() + if mpn: + part.add_mpn(mpn) - part.add_mpn(mpn) part.xml.descriptionProp = desc if price: diff --git a/src/ee/supplier/seeed.py b/src/ee/supplier/seeed.py index b4b17e9..1982f68 100644 --- a/src/ee/supplier/seeed.py +++ b/src/ee/supplier/seeed.py @@ -110,7 +110,7 @@ def download_opl(out_path: Path, cache_dir: Path, opl_type: str): ladder_price = p["ladder_price"] - xml = types.Part(references=types.ReferencesList(), price_breaks=types.PriceBreakList()) + xml = types.Part(references=types.ReferenceList(), price_breaks=types.PriceBreakList()) xml.supplierProp = supplier_uri xml.descriptionProp = desc diff --git a/src/ee/tools/drawio-to-parts.py b/src/ee/tools/drawio-to-parts.py deleted file mode 100644 index 562e341..0000000 --- a/src/ee/tools/drawio-to-parts.py +++ /dev/null @@ -1,20 +0,0 @@ -import argparse -from pathlib import Path - -import ee.drawio - -parser = argparse.ArgumentParser() - -parser.add_argument("--in", - dest="in_path", - required=True, - metavar="XML") - -parser.add_argument("--out", - required=True, - metavar="PART DB") - -args = parser.parse_args() - -# ee.drawio.to_parts(Path(args.in_path), Path(args.out)) -ee.drawio.to_dot(Path(args.in_path), Path(args.out)) diff --git a/src/ee/tools/drawio_decompress.py b/src/ee/tools/drawio_decompress.py index 8949eec..8fafd54 100644 --- a/src/ee/tools/drawio_decompress.py +++ b/src/ee/tools/drawio_decompress.py @@ -18,7 +18,7 @@ in_stream = out_stream = None try: in_stream = open(args.in_path, "rb") if args.in_path else sys.stdin - out_stream = open(args.out, "wr") if args.out else sys.stdout + out_stream = open(args.out, "w") if args.out else sys.stdout decompress(in_stream, out_stream) except IOError: diff --git a/src/ee/tools/drawio_to_parts.py b/src/ee/tools/drawio_to_parts.py new file mode 100644 index 0000000..671aaea --- /dev/null +++ b/src/ee/tools/drawio_to_parts.py @@ -0,0 +1,25 @@ +import argparse +from pathlib import Path + +import ee.drawio + +parser = argparse.ArgumentParser() + +parser.add_argument("--in", + dest="in_path", + required=True, + metavar="XML") + +parser.add_argument("--out", + required=True, + metavar="PART DB") + +parser.add_argument("--parts", + nargs="*", + metavar="PART DB") + +args = parser.parse_args() + +parts = args.parts or [] +ee.drawio.to_parts(Path(args.in_path), Path(args.out), [Path(path) for path in parts]) +# ee.drawio.to_dot(Path(args.in_path), Path(args.out)) diff --git a/src/ee/tools/templates/build.ninja.j2 b/src/ee/tools/templates/build.ninja.j2 index d62f350..b9a65df 100644 --- a/src/ee/tools/templates/build.ninja.j2 +++ b/src/ee/tools/templates/build.ninja.j2 @@ -53,6 +53,15 @@ rule import-parts-yaml description = import-parts-yaml $in command = $ee import-parts-yaml --in $in --out $out +rule drawio-decompress + command = $ee drawio-decompress --in $in --out $out + +rule drawio-to-parts + command = $ee drawio-to-parts --in $in --out $out $args + +rule part-from-excel + command = $ee part-from-excel --in $in --out $out --sheet "$sheet" + {% if gerber_zip is defined %} build gerbers: phony {{ gerber_zip }} build {{ gerber_zip }}: kicad-gerber $pcb diff --git a/src/ee/xml/types.py b/src/ee/xml/types.py index 8e5e39f..a6ef46b 100644 --- a/src/ee/xml/types.py +++ b/src/ee/xml/types.py @@ -3,7 +3,7 @@ # # Generated by generateDS.py. -# Python 3.7.2+ (default, Feb 2 2019, 14:31:48) [GCC 8.2.0] +# Python 3.7.3rc1 (default, Mar 13 2019, 11:01:15) [GCC 8.3.0] # # Command line options: # ('-f', '') @@ -729,10 +729,11 @@ def _cast(typ, value): class PartDb(GeneratedsSuper): subclass = None superclass = None - def __init__(self, parts=None, **kwargs_): + def __init__(self, parts=None, assembly=None, **kwargs_): self.original_tagname_ = None self.parent_object_ = kwargs_.get('parent_object_') self.parts = parts + self.assembly = assembly def factory(*args_, **kwargs_): if CurrentSubclassModule_ is not None: subclass = getSubclassFromModule_( @@ -749,9 +750,15 @@ class PartDb(GeneratedsSuper): def set_parts(self, parts): self.parts = parts partsProp = property(get_parts, set_parts) + def get_assembly(self): + return self.assembly + def set_assembly(self, assembly): + self.assembly = assembly + assemblyProp = property(get_assembly, set_assembly) def hasContent_(self): if ( - self.parts is not None + self.parts is not None or + self.assembly is not None ): return True else: @@ -786,6 +793,8 @@ class PartDb(GeneratedsSuper): eol_ = '' if self.parts is not None: self.parts.export(outfile, level, namespaceprefix_, namespacedef_='', name_='parts', pretty_print=pretty_print) + if self.assembly is not None: + self.assembly.export(outfile, level, namespaceprefix_, namespacedef_='', name_='assembly', pretty_print=pretty_print) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -801,6 +810,11 @@ class PartDb(GeneratedsSuper): obj_.build(child_) self.parts = obj_ obj_.original_tagname_ = 'parts' + elif nodeName_ == 'assembly': + obj_ = Assembly.factory(parent_object_=self) + obj_.build(child_) + self.assembly = obj_ + obj_.original_tagname_ = 'assembly' # end class PartDb @@ -969,7 +983,7 @@ class Part(GeneratedsSuper): self.links = obj_ obj_.original_tagname_ = 'links' elif nodeName_ == 'references': - obj_ = ReferencesList.factory(parent_object_=self) + obj_ = ReferenceList.factory(parent_object_=self) obj_.build(child_) self.references = obj_ obj_.original_tagname_ = 'references' @@ -1392,10 +1406,10 @@ class SchematicReference(GeneratedsSuper): # end class SchematicReference -class ReferencesList(GeneratedsSuper): +class ReferenceList(GeneratedsSuper): subclass = None superclass = None - def __init__(self, part_reference=None, schematic_reference=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, description=None, **kwargs_): self.original_tagname_ = None self.parent_object_ = kwargs_.get('parent_object_') if part_reference is None: @@ -1414,16 +1428,20 @@ class ReferencesList(GeneratedsSuper): self.supplier_part_number = [] else: self.supplier_part_number = supplier_part_number + if description is None: + self.description = [] + else: + self.description = description def factory(*args_, **kwargs_): if CurrentSubclassModule_ is not None: subclass = getSubclassFromModule_( - CurrentSubclassModule_, ReferencesList) + CurrentSubclassModule_, ReferenceList) if subclass is not None: return subclass(*args_, **kwargs_) - if ReferencesList.subclass: - return ReferencesList.subclass(*args_, **kwargs_) + if ReferenceList.subclass: + return ReferenceList.subclass(*args_, **kwargs_) else: - return ReferencesList(*args_, **kwargs_) + return ReferenceList(*args_, **kwargs_) factory = staticmethod(factory) def get_part_reference(self): return self.part_reference @@ -1477,18 +1495,32 @@ class ReferencesList(GeneratedsSuper): def replace_supplier_part_number_at(self, index, value): self.supplier_part_number[index] = value supplier_part_numberProp = property(get_supplier_part_number, set_supplier_part_number) + def get_description(self): + return self.description + def set_description(self, description): + self.description = description + def add_description(self, value): + self.description.append(value) + def add_description(self, value): + self.description.append(value) + def insert_description_at(self, index, value): + self.description.insert(index, value) + def replace_description_at(self, index, value): + self.description[index] = value + descriptionProp = property(get_description, set_description) def hasContent_(self): if ( self.part_reference or self.schematic_reference or self.part_number or - self.supplier_part_number + self.supplier_part_number or + self.description ): return True else: return False - def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ReferencesList', pretty_print=True): - imported_ns_def_ = GenerateDSNamespaceDefs_.get('ReferencesList') + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ReferenceList', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('ReferenceList') if imported_ns_def_ is not None: namespacedef_ = imported_ns_def_ if pretty_print: @@ -1500,17 +1532,17 @@ class ReferencesList(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_='ReferencesList') + self.exportAttributes(outfile, level, already_processed, namespaceprefix_, name_='ReferenceList') if self.hasContent_(): outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='ReferencesList', pretty_print=pretty_print) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='ReferenceList', pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespaceprefix_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='ReferencesList'): + def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='ReferenceList'): pass - def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ReferencesList', fromsubclass_=False, pretty_print=True): + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ReferenceList', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: @@ -1523,6 +1555,9 @@ class ReferencesList(GeneratedsSuper): part_number_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-number', pretty_print=pretty_print) for supplier_part_number_ in self.supplier_part_number: supplier_part_number_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='supplier-part-number', pretty_print=pretty_print) + for description_ in self.description: + showIndent(outfile, level, pretty_print) + outfile.write('<%sdescription>%s%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(description_), input_name='description')), namespaceprefix_ , eol_)) def build(self, node): already_processed = set() self.buildAttributes(node, node.attrib, already_processed) @@ -1553,7 +1588,11 @@ class ReferencesList(GeneratedsSuper): obj_.build(child_) self.supplier_part_number.append(obj_) obj_.original_tagname_ = 'supplier-part-number' -# end class ReferencesList + elif nodeName_ == 'description': + description_ = child_.text + description_ = self.gds_validate_string(description_, node, 'description') + self.description.append(description_) +# end class ReferenceList class Fact(GeneratedsSuper): @@ -2297,6 +2336,283 @@ class LinkList(GeneratedsSuper): # end class LinkList +class AssemblyPart(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, references=None, count=None, sub_parts=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.references = references + self.count = count + self.sub_parts = sub_parts + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, AssemblyPart) + if subclass is not None: + return subclass(*args_, **kwargs_) + if AssemblyPart.subclass: + return AssemblyPart.subclass(*args_, **kwargs_) + else: + return AssemblyPart(*args_, **kwargs_) + factory = staticmethod(factory) + def get_references(self): + return self.references + def set_references(self, references): + self.references = references + referencesProp = property(get_references, set_references) + def get_count(self): + return self.count + def set_count(self, count): + self.count = count + countProp = property(get_count, set_count) + def get_sub_parts(self): + return self.sub_parts + def set_sub_parts(self, sub_parts): + self.sub_parts = sub_parts + sub_partsProp = property(get_sub_parts, set_sub_parts) + def hasContent_(self): + if ( + self.references is not None or + self.count is not None or + self.sub_parts is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='AssemblyPart', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('AssemblyPart') + if imported_ns_def_ is not None: + namespacedef_ = imported_ns_def_ + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.original_tagname_ is not None: + name_ = self.original_tagname_ + 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_='AssemblyPart') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='AssemblyPart', pretty_print=pretty_print) + showIndent(outfile, level, pretty_print) + outfile.write('%s' % (namespaceprefix_, name_, eol_)) + else: + outfile.write('/>%s' % (eol_, )) + def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='AssemblyPart'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='AssemblyPart', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.references is not None: + self.references.export(outfile, level, namespaceprefix_, namespacedef_='', name_='references', pretty_print=pretty_print) + if self.count is not None: + showIndent(outfile, level, pretty_print) + outfile.write('<%scount>%s%s' % (namespaceprefix_ , self.gds_format_double(self.count, input_name='count'), namespaceprefix_ , eol_)) + if self.sub_parts is not None: + self.sub_parts.export(outfile, level, namespaceprefix_, namespacedef_='', name_='sub-parts', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + return self + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'references': + obj_ = ReferenceList.factory(parent_object_=self) + obj_.build(child_) + self.references = obj_ + obj_.original_tagname_ = 'references' + elif nodeName_ == 'count' and child_.text: + sval_ = child_.text + try: + fval_ = float(sval_) + except (TypeError, ValueError) as exp: + raise_parse_error(child_, 'requires float or double: %s' % exp) + fval_ = self.gds_validate_float(fval_, node, 'count') + self.count = fval_ + elif nodeName_ == 'sub-parts': + obj_ = AssemblyPartList.factory(parent_object_=self) + obj_.build(child_) + self.sub_parts = obj_ + obj_.original_tagname_ = 'sub-parts' +# end class AssemblyPart + + +class AssemblyPartList(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, assembly_part=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + if assembly_part is None: + self.assembly_part = [] + else: + self.assembly_part = assembly_part + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, AssemblyPartList) + if subclass is not None: + return subclass(*args_, **kwargs_) + if AssemblyPartList.subclass: + return AssemblyPartList.subclass(*args_, **kwargs_) + else: + return AssemblyPartList(*args_, **kwargs_) + factory = staticmethod(factory) + def get_assembly_part(self): + return self.assembly_part + def set_assembly_part(self, assembly_part): + self.assembly_part = assembly_part + def add_assembly_part(self, value): + self.assembly_part.append(value) + def add_assembly_part(self, value): + self.assembly_part.append(value) + def insert_assembly_part_at(self, index, value): + self.assembly_part.insert(index, value) + def replace_assembly_part_at(self, index, value): + self.assembly_part[index] = value + assembly_partProp = property(get_assembly_part, set_assembly_part) + def hasContent_(self): + if ( + self.assembly_part + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='AssemblyPartList', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('AssemblyPartList') + if imported_ns_def_ is not None: + namespacedef_ = imported_ns_def_ + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.original_tagname_ is not None: + name_ = self.original_tagname_ + 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_='AssemblyPartList') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='AssemblyPartList', pretty_print=pretty_print) + showIndent(outfile, level, pretty_print) + outfile.write('%s' % (namespaceprefix_, name_, eol_)) + else: + outfile.write('/>%s' % (eol_, )) + def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='AssemblyPartList'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='AssemblyPartList', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for assembly_part_ in self.assembly_part: + assembly_part_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='assembly-part', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + return self + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'assembly-part': + obj_ = AssemblyPart.factory(parent_object_=self) + obj_.build(child_) + self.assembly_part.append(obj_) + obj_.original_tagname_ = 'assembly-part' +# end class AssemblyPartList + + +class Assembly(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, assembly_parts=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.assembly_parts = assembly_parts + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, Assembly) + if subclass is not None: + return subclass(*args_, **kwargs_) + if Assembly.subclass: + return Assembly.subclass(*args_, **kwargs_) + else: + return Assembly(*args_, **kwargs_) + factory = staticmethod(factory) + def get_assembly_parts(self): + return self.assembly_parts + def set_assembly_parts(self, assembly_parts): + self.assembly_parts = assembly_parts + assembly_partsProp = property(get_assembly_parts, set_assembly_parts) + def hasContent_(self): + if ( + self.assembly_parts is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Assembly', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('Assembly') + if imported_ns_def_ is not None: + namespacedef_ = imported_ns_def_ + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.original_tagname_ is not None: + name_ = self.original_tagname_ + 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_='Assembly') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='Assembly', pretty_print=pretty_print) + showIndent(outfile, level, pretty_print) + outfile.write('%s' % (namespaceprefix_, name_, eol_)) + else: + outfile.write('/>%s' % (eol_, )) + def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='', name_='Assembly'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Assembly', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.assembly_parts is not None: + self.assembly_parts.export(outfile, level, namespaceprefix_, namespacedef_='', name_='assembly-parts', pretty_print=pretty_print) + def build(self, node): + already_processed = set() + self.buildAttributes(node, node.attrib, already_processed) + for child in node: + nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] + self.buildChildren(child, node, nodeName_) + return self + def buildAttributes(self, node, attrs, already_processed): + pass + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'assembly-parts': + obj_ = AssemblyPartList.factory(parent_object_=self) + obj_.build(child_) + self.assembly_parts = obj_ + obj_.original_tagname_ = 'assembly-parts' +# end class Assembly + + GDSClassesMapping = { 'part': Part, 'part-db': PartDb, @@ -2428,6 +2744,9 @@ if __name__ == '__main__': __all__ = [ "Amount", + "Assembly", + "AssemblyPart", + "AssemblyPartList", "DistributorInfo", "Fact", "FactList", @@ -2440,7 +2759,7 @@ __all__ = [ "PartReference", "PriceBreak", "PriceBreakList", - "ReferencesList", + "ReferenceList", "SchematicReference", "SupplierPartNumber" ] diff --git a/xsd/ee.xsd b/xsd/ee.xsd index 446bab7..32c97b3 100644 --- a/xsd/ee.xsd +++ b/xsd/ee.xsd @@ -39,6 +39,7 @@ TODO: rename 'id' to 'url'. + @@ -49,7 +50,7 @@ TODO: rename 'id' to 'url'. - + @@ -87,13 +88,14 @@ TODO: rename 'id' to 'url'. - + + @@ -149,4 +151,25 @@ TODO: rename 'id' to 'url'. + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3