diff options
-rw-r--r-- | Makefile | 22 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | src/ee/__main__.py | 9 | ||||
-rw-r--r-- | src/ee/bom/part_type_uris.py | 5 | ||||
-rw-r--r-- | src/ee/kicad/make_bom.py | 151 | ||||
-rw-r--r-- | src/ee/tools/kicad_make_bom.py | 24 | ||||
-rw-r--r-- | src/ee/xml/__init__.py | 0 | ||||
-rw-r--r-- | src/ee/xml/bomFile.py | 1326 | ||||
-rw-r--r-- | src/ee/xml/catalogFile.py | 1103 | ||||
-rw-r--r-- | xsd/ee-bom.xsd | 63 | ||||
-rw-r--r-- | xsd/ee-catalog.xsd | 26 |
11 files changed, 2709 insertions, 21 deletions
@@ -1,8 +1,24 @@ -all: env-packages +XSDS = xsd/ee-bom.xsd xsd/ee-catalog.xsd +XSD_PYS = src/ee/xml/bomFile.py src/ee/xml/catalogFile.py -env: +all: env/pip.cookie $(XSD_PYS) + +env/bin/pip: virtualenv -p python3 env -env-packages: env +env/pip.cookie: requirements.txt env/bin/pip env/bin/pip install -r requirements.txt env/bin/pip install -e . + @touch env/pip.cookie + +src/ee/xml/__init__.py: + touch $@ + +src/ee/xml/%File.py: xsd/ee-%.xsd + env/bin/generateDS.py \ + -f \ + --one-file-per-xsd \ + --output-directory=src/ee/xml \ + -m $< + +$(XSDS): env/pip.cookie src/ee/xml/__init__.py diff --git a/requirements.txt b/requirements.txt index 308badc..f0c6837 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ requests==2.19.1 tox==3.1.2 selenium==3.141.0 +generateds==2.30.11 # for development jupyter==1.0.0 diff --git a/src/ee/__main__.py b/src/ee/__main__.py index 6a7517f..a387b1d 100644 --- a/src/ee/__main__.py +++ b/src/ee/__main__.py @@ -1,9 +1,11 @@ -from functools import total_ordering -import ee.tools import importlib import logging import pkgutil import sys +import os +from functools import total_ordering + +import ee.tools def eprint(*args, **kwargs): @@ -50,6 +52,9 @@ def main(): name = sys.argv[1] del sys.argv[1] + if os.path.isdir("py"): + sys.path.append("py") + for t in tools: if t.name != name: continue diff --git a/src/ee/bom/part_type_uris.py b/src/ee/bom/part_type_uris.py new file mode 100644 index 0000000..b7f5e88 --- /dev/null +++ b/src/ee/bom/part_type_uris.py @@ -0,0 +1,5 @@ +CAPACITOR = "http://purl.org/ee/part-type#capacitor" +RESISTOR = "http://purl.org/ee/part-type#resistor" +DIODE = "http://purl.org/ee/part-type#diode" +INDUCTOR = "http://purl.org/ee/part-type#inductor" +CRYSTAL = "http://purl.org/ee/part-type#inductor" diff --git a/src/ee/kicad/make_bom.py b/src/ee/kicad/make_bom.py new file mode 100644 index 0000000..3fa102f --- /dev/null +++ b/src/ee/kicad/make_bom.py @@ -0,0 +1,151 @@ +import sys +from typing import Optional, List, Callable, Mapping +from xml.dom import minidom +from xml.etree import ElementTree + +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.tools import mk_parents +from ee.xml import bomFile +from ee.bom import part_type_uris + +__all__ = [ + "StrategyCallable", + "MakeBomStrategy", + "apply_strategies", + "mpn_strategy", + "part_type_strategy", + "dpn_strategy_factory", + "make_bom", +] + +StrategyCallable = Callable[[Component, bomFile.Part], Optional[bomFile.Part]] + + +def apply_strategies(c: Component, part: bomFile.Part, strategies: List[StrategyCallable]): + for strategy in strategies: + part = strategy(c, part) + + if part is None: + return + + if not isinstance(part, bomFile.Part): + raise EeException("Values returned from strategy must be a bomFile.Part, got {}".format(type(part))) + + return part + + +def part_type_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + fp = component.footprint + if fp is None: + return part + + lib, part_name = fp.split(":") + + if lib == "Capacitor_SMD": + part.part_typeProp = part_type_uris.CAPACITOR + elif lib == "Resistor_SMD": + part.part_typeProp = part_type_uris.RESISTOR + elif lib == "Diode_SMD": + part.part_typeProp = part_type_uris.DIODE + elif lib == "Inductor_SMD": + part.part_typeProp = part_type_uris.INDUCTOR + elif lib == "Crystal": + part.part_typeProp = part_type_uris.CRYSTAL + + return part + + +def mpn_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + mpn = component.get_field("mpn") + if mpn is not None: + pn = bomFile.PartNumber(value=mpn.value) + part.part_numbersProp.add_part_number(pn) + + return part + + +def dpn_strategy_factory(dpn_mappings: Mapping[str, str]) -> StrategyCallable: + def dpn_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + for field_name, distributor in dpn_mappings: + s = component.get_field(field_name) + if s is not None: + pn = bomFile.PartNumber(value=s, distributor=distributor) + part.part_numbersProp.add_part_number(pn) + + return part + + return dpn_strategy + + +class MakeBomStrategy(): + def __init__(self, dpn_mappings: Mapping[str, str] = None): + self.dpn_mappings = dpn_mappings or {} + self.default_strategies = [ + mpn_strategy, + part_type_strategy, + dpn_strategy_factory(self.dpn_mappings), + ] + + def process_part(self, component: Component, part: bomFile.Part): + return self.default_process_part(component, part) + + def default_process_part(self, component: Component, part: bomFile.Part): + return apply_strategies(component, part, self.default_strategies) + + +def work(sch, out_file, strategy: MakeBomStrategy, new_mode, pretty): + if not new_mode: + bom = to_bom_xml(sch) + xml = ElementTree.tostring(bom, encoding="unicode") + + if pretty: + xml = minidom.parseString(xml).toprettyxml(indent=" ") + + print(xml, file=out_file) + else: + file = bomFile.BomFile() + + parts = bomFile.PartList() + file.partsProp = parts + + components = to_bom(sch) + for c in components: + part = bomFile.Part(id=c.ref) + part.schema_reference = c.ref + part.part_numbersProp = bomFile.PartNumberList() + + part = strategy.process_part(c, part) + + if len(part.part_numbersProp.get_part_number()) == 0: + part.part_numbersProp = None + + if part is not None: + parts.add_part(part) + + file.export(out_file, 0, name_="bom-file", namespacedef_="xmlns='http://purl.org/ee/bom-file'", + pretty_print=pretty) + + +def make_bom(sch_file: str, out_file: Optional[str], strategy_name: str, new_mode: bool, pretty: bool): + sch = read_schematics(sch_file) + + import pydoc + make_bom_strategy_factory = pydoc.locate(strategy_name) + + if not callable(make_bom_strategy_factory): + raise EeException("Not a callable: {}, is a {}".format(strategy_name, type(make_bom_strategy_factory))) + + make_bom_strategy = make_bom_strategy_factory() # type: MakeBomStrategy + + if not isinstance(make_bom_strategy, MakeBomStrategy): + raise EeException("Not a MakeBomStrategy: {}, is a {}".format(strategy_name, type(make_bom_strategy))) + + if out_file: + mk_parents(out_file) + with open(out_file, "w") as f: + work(sch, f, make_bom_strategy, new_mode, pretty) + else: + work(sch, sys.stdout, make_bom_strategy, new_mode, pretty) diff --git a/src/ee/tools/kicad_make_bom.py b/src/ee/tools/kicad_make_bom.py index 2600968..769ea0d 100644 --- a/src/ee/tools/kicad_make_bom.py +++ b/src/ee/tools/kicad_make_bom.py @@ -1,8 +1,6 @@ import argparse -import ee.kicad as kicad -from ee.tools import mk_parents -from xml.etree import ElementTree -from xml.dom import minidom + +from ee.kicad.make_bom import make_bom pretty = True # we always pretty print the XML @@ -17,19 +15,13 @@ parser.add_argument("--out", metavar="FILE", help="The output file") -args = parser.parse_args() +parser.add_argument("--strategy", + metavar="FUNC") -sch = kicad.read_schematics(args.sch) +args = parser.parse_args() -bom = kicad.to_bom_xml(sch) -xml = ElementTree.tostring(bom, encoding='unicode') +new_mode = True -if pretty: - xml = minidom.parseString(xml).toprettyxml(indent=" ") +strategy = args.strategy if args.strategy else "ee.kicad.make_bom.MakeBomStrategy" -if args.out: - mk_parents(args.out) - with open(args.out, "w") as f: - f.write(xml) -else: - print(xml) +make_bom(args.sch, args.out, strategy, new_mode, pretty) diff --git a/src/ee/xml/__init__.py b/src/ee/xml/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ee/xml/__init__.py diff --git a/src/ee/xml/bomFile.py b/src/ee/xml/bomFile.py new file mode 100644 index 0000000..d1967a6 --- /dev/null +++ b/src/ee/xml/bomFile.py @@ -0,0 +1,1326 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Generated Thu Feb 21 08:05:29 2019 by generateDS.py version 2.30.11. +# Python 3.7.2+ (default, Feb 2 2019, 14:31:48) [GCC 8.2.0] +# +# Command line options: +# ('-f', '') +# ('--one-file-per-xsd', '') +# ('--output-directory', 'src/ee/xml') +# ('-m', '') +# +# Command line arguments: +# xsd/ee-bom.xsd +# +# Command line: +# env/bin/generateDS.py -f --one-file-per-xsd --output-directory="src/ee/xml" -m xsd/ee-bom.xsd +# +# Current working directory (os.getcwd()): +# ee-python +# + +import sys +import re as re_ +import base64 +import datetime as datetime_ +import warnings as warnings_ +try: + from lxml import etree as etree_ +except ImportError: + from xml.etree import ElementTree as etree_ + + +Validate_simpletypes_ = True +if sys.version_info.major == 2: + BaseStrType_ = basestring +else: + BaseStrType_ = str + + +def parsexml_(infile, parser=None, **kwargs): + if parser is None: + # Use the lxml ElementTree compatible parser so that, e.g., + # we ignore comments. + try: + parser = etree_.ETCompatXMLParser() + except AttributeError: + # fallback to xml.etree + parser = etree_.XMLParser() + doc = etree_.parse(infile, parser=parser, **kwargs) + return doc + +def parsexmlstring_(instring, parser=None, **kwargs): + if parser is None: + # Use the lxml ElementTree compatible parser so that, e.g., + # we ignore comments. + try: + parser = etree_.ETCompatXMLParser() + except AttributeError: + # fallback to xml.etree + parser = etree_.XMLParser() + element = etree_.fromstring(instring, parser=parser, **kwargs) + return element + +# +# Namespace prefix definition table (and other attributes, too) +# +# The module generatedsnamespaces, if it is importable, must contain +# a dictionary named GeneratedsNamespaceDefs. This Python dictionary +# should map element type names (strings) to XML schema namespace prefix +# definitions. The export method for any class for which there is +# a namespace prefix definition, will export that definition in the +# XML representation of that element. See the export method of +# any generated element type class for a example of the use of this +# table. +# A sample table is: +# +# # File: generatedsnamespaces.py +# +# GenerateDSNamespaceDefs = { +# "ElementtypeA": "http://www.xxx.com/namespaceA", +# "ElementtypeB": "http://www.xxx.com/namespaceB", +# } +# + +try: + from generatedsnamespaces import GenerateDSNamespaceDefs as GenerateDSNamespaceDefs_ +except ImportError: + GenerateDSNamespaceDefs_ = {} + +# +# The root super-class for element type classes +# +# Calls to the methods in these classes are generated by generateDS.py. +# You can replace these methods by re-implementing the following class +# in a module named generatedssuper.py. + +try: + from generatedssuper import GeneratedsSuper +except ImportError as exp: + + class GeneratedsSuper(object): + tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') + class _FixedOffsetTZ(datetime_.tzinfo): + def __init__(self, offset, name): + self.__offset = datetime_.timedelta(minutes=offset) + self.__name = name + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return None + def gds_format_string(self, input_data, input_name=''): + return input_data + def gds_validate_string(self, input_data, node=None, input_name=''): + if not input_data: + return '' + else: + return input_data + def gds_format_base64(self, input_data, input_name=''): + return base64.b64encode(input_data) + def gds_validate_base64(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer(self, input_data, input_name=''): + return '%d' % input_data + def gds_validate_integer(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_integer_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + int(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of integers') + return values + def gds_format_float(self, input_data, input_name=''): + return ('%.15f' % input_data).rstrip('0') + def gds_validate_float(self, input_data, node=None, input_name=''): + return input_data + def gds_format_float_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_float_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of floats') + return values + def gds_format_double(self, input_data, input_name=''): + return '%e' % input_data + def gds_validate_double(self, input_data, node=None, input_name=''): + return input_data + def gds_format_double_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_double_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of doubles') + return values + def gds_format_boolean(self, input_data, input_name=''): + return ('%s' % input_data).lower() + def gds_validate_boolean(self, input_data, node=None, input_name=''): + return input_data + def gds_format_boolean_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_boolean_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + if value not in ('true', '1', 'false', '0', ): + raise_parse_error( + node, + 'Requires sequence of booleans ' + '("true", "1", "false", "0")') + return values + def gds_validate_datetime(self, input_data, node=None, input_name=''): + return input_data + def gds_format_datetime(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + @classmethod + def gds_parse_datetime(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + time_parts = input_data.split('.') + if len(time_parts) > 1: + micro_seconds = int(float('0.' + time_parts[1]) * 1000000) + input_data = '%s.%s' % ( + time_parts[0], "{}".format(micro_seconds).rjust(6, "0"), ) + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt + def gds_validate_date(self, input_data, node=None, input_name=''): + return input_data + def gds_format_date(self, input_data, input_name=''): + _svalue = '%04d-%02d-%02d' % ( + input_data.year, + input_data.month, + input_data.day, + ) + try: + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format( + hours, minutes) + except AttributeError: + pass + return _svalue + @classmethod + def gds_parse_date(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') + dt = dt.replace(tzinfo=tz) + return dt.date() + def gds_validate_time(self, input_data, node=None, input_name=''): + return input_data + def gds_format_time(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%02d:%02d:%02d' % ( + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%02d:%02d:%02d.%s' % ( + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + def gds_validate_simple_patterns(self, patterns, target): + # pat is a list of lists of strings/patterns. + # The target value must match at least one of the patterns + # in order for the test to succeed. + found1 = True + for patterns1 in patterns: + found2 = False + for patterns2 in patterns1: + mo = re_.search(patterns2, target) + if mo is not None and len(mo.group(0)) == len(target): + found2 = True + break + if not found2: + found1 = False + break + return found1 + @classmethod + def gds_parse_time(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + if len(input_data.split('.')) > 1: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt.time() + def gds_str_lower(self, instring): + return instring.lower() + def get_path_(self, node): + path_list = [] + self.get_path_list_(node, path_list) + path_list.reverse() + path = '/'.join(path_list) + return path + Tag_strip_pattern_ = re_.compile(r'\{.*\}') + def get_path_list_(self, node, path_list): + if node is None: + return + tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) + if tag: + path_list.append(tag) + self.get_path_list_(node.getparent(), path_list) + def get_class_obj_(self, node, default_class=None): + class_obj1 = default_class + if 'xsi' in node.nsmap: + classname = node.get('{%s}type' % node.nsmap['xsi']) + if classname is not None: + names = classname.split(':') + if len(names) == 2: + classname = names[1] + class_obj2 = globals().get(classname) + if class_obj2 is not None: + class_obj1 = class_obj2 + return class_obj1 + def gds_build_any(self, node, type_name=None): + return None + @classmethod + def gds_reverse_node_mapping(cls, mapping): + return dict(((v, k) for k, v in mapping.items())) + @staticmethod + def gds_encode(instring): + if sys.version_info.major == 2: + if ExternalEncoding: + encoding = ExternalEncoding + else: + encoding = 'utf-8' + return instring.encode(encoding) + else: + return instring + @staticmethod + def convert_unicode(instring): + if isinstance(instring, str): + result = quote_xml(instring) + elif sys.version_info.major == 2 and isinstance(instring, unicode): + result = quote_xml(instring).encode('utf8') + else: + result = GeneratedsSuper.gds_encode(str(instring)) + return result + def __eq__(self, other): + if type(self) != type(other): + return False + return self.__dict__ == other.__dict__ + def __ne__(self, other): + return not self.__eq__(other) + + def getSubclassFromModule_(module, class_): + '''Get the subclass of a class from a specific module.''' + name = class_.__name__ + 'Sub' + if hasattr(module, name): + return getattr(module, name) + else: + return None + + +# +# If you have installed IPython you can uncomment and use the following. +# IPython is available from http://ipython.scipy.org/. +# + +## from IPython.Shell import IPShellEmbed +## args = '' +## ipshell = IPShellEmbed(args, +## banner = 'Dropping into IPython', +## exit_msg = 'Leaving Interpreter, back to program.') + +# Then use the following line where and when you want to drop into the +# IPython shell: +# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit') + +# +# Globals +# + +ExternalEncoding = '' +Tag_pattern_ = re_.compile(r'({.*})?(.*)') +String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") +Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') +CDATA_pattern_ = re_.compile(r"<!\[CDATA\[.*?\]\]>", re_.DOTALL) + +# Change this to redirect the generated superclass module to use a +# specific subclass module. +CurrentSubclassModule_ = None + +# +# Support/utility functions. +# + + +def showIndent(outfile, level, pretty_print=True): + if pretty_print: + for idx in range(level): + outfile.write(' ') + + +def quote_xml(inStr): + "Escape markup chars, but do not modify CDATA sections." + if not inStr: + return '' + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s2 = '' + pos = 0 + matchobjects = CDATA_pattern_.finditer(s1) + for mo in matchobjects: + s3 = s1[pos:mo.start()] + s2 += quote_xml_aux(s3) + s2 += s1[mo.start():mo.end()] + pos = mo.end() + s3 = s1[pos:] + s2 += quote_xml_aux(s3) + return s2 + + +def quote_xml_aux(inStr): + s1 = inStr.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + return s1 + + +def quote_attrib(inStr): + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + if '"' in s1: + if "'" in s1: + s1 = '"%s"' % s1.replace('"', """) + else: + s1 = "'%s'" % s1 + else: + s1 = '"%s"' % s1 + return s1 + + +def quote_python(inStr): + s1 = inStr + if s1.find("'") == -1: + if s1.find('\n') == -1: + return "'%s'" % s1 + else: + return "'''%s'''" % s1 + else: + if s1.find('"') != -1: + s1 = s1.replace('"', '\\"') + if s1.find('\n') == -1: + return '"%s"' % s1 + else: + return '"""%s"""' % s1 + + +def get_all_text_(node): + if node.text is not None: + text = node.text + else: + text = '' + for child in node: + if child.tail is not None: + text += child.tail + return text + + +def find_attr_value_(attr_name, node): + attrs = node.attrib + attr_parts = attr_name.split(':') + value = None + if len(attr_parts) == 1: + value = attrs.get(attr_name) + elif len(attr_parts) == 2: + prefix, name = attr_parts + namespace = node.nsmap.get(prefix) + if namespace is not None: + value = attrs.get('{%s}%s' % (namespace, name, )) + return value + + +class GDSParseError(Exception): + pass + + +def raise_parse_error(node, msg): + msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline, ) + raise GDSParseError(msg) + + +class MixedContainer: + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + TypeBase64 = 8 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name, namespace, + pretty_print=True): + if self.category == MixedContainer.CategoryText: + # Prevent exporting empty content as empty lines. + if self.value.strip(): + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export( + outfile, level, namespace, name_=name, + pretty_print=pretty_print) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write('<%s>%s</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write('<%s>%d</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write('<%s>%f</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write('<%s>%g</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeBase64: + outfile.write('<%s>%s</%s>' % ( + self.name, + base64.b64encode(self.value), + self.name)) + def to_etree(self, element): + if self.category == MixedContainer.CategoryText: + # Prevent exporting empty content as empty lines. + if self.value.strip(): + if len(element) > 0: + if element[-1].tail is None: + element[-1].tail = self.value + else: + element[-1].tail += self.value + else: + if element.text is None: + element.text = self.value + else: + element.text += self.value + elif self.category == MixedContainer.CategorySimple: + subelement = etree_.SubElement( + element, '%s' % self.name) + subelement.text = self.to_etree_simple() + else: # category == MixedContainer.CategoryComplex + self.value.to_etree(element) + def to_etree_simple(self): + if self.content_type == MixedContainer.TypeString: + text = self.value + elif (self.content_type == MixedContainer.TypeInteger or + self.content_type == MixedContainer.TypeBoolean): + text = '%d' % self.value + elif (self.content_type == MixedContainer.TypeFloat or + self.content_type == MixedContainer.TypeDecimal): + text = '%f' % self.value + elif self.content_type == MixedContainer.TypeDouble: + text = '%g' % self.value + elif self.content_type == MixedContainer.TypeBase64: + text = '%s' % base64.b64encode(self.value) + return text + def exportLiteral(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( + self.category, self.content_type, + self.name, self.value)) + elif self.category == MixedContainer.CategorySimple: + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( + self.category, self.content_type, + self.name, self.value)) + else: # category == MixedContainer.CategoryComplex + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s",\n' % ( + self.category, self.content_type, self.name,)) + self.value.exportLiteral(outfile, level + 1) + showIndent(outfile, level) + outfile.write(')\n') + + +class MemberSpec_(object): + def __init__(self, name='', data_type='', container=0, + optional=0, child_attrs=None, choice=None): + self.name = name + self.data_type = data_type + self.container = container + self.child_attrs = child_attrs + self.choice = choice + self.optional = optional + def set_name(self, name): self.name = name + def get_name(self): return self.name + def set_data_type(self, data_type): self.data_type = data_type + def get_data_type_chain(self): return self.data_type + def get_data_type(self): + if isinstance(self.data_type, list): + if len(self.data_type) > 0: + return self.data_type[-1] + else: + return 'xs:string' + else: + return self.data_type + def set_container(self, container): self.container = container + def get_container(self): return self.container + def set_child_attrs(self, child_attrs): self.child_attrs = child_attrs + def get_child_attrs(self): return self.child_attrs + def set_choice(self, choice): self.choice = choice + def get_choice(self): return self.choice + def set_optional(self, optional): self.optional = optional + def get_optional(self): return self.optional + + +def _cast(typ, value): + if typ is None or value is None: + return value + return typ(value) + +# +# Data representation classes. +# + + +class BomFile(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, parts=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.parts = parts + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, BomFile) + if subclass is not None: + return subclass(*args_, **kwargs_) + if BomFile.subclass: + return BomFile.subclass(*args_, **kwargs_) + else: + return BomFile(*args_, **kwargs_) + factory = staticmethod(factory) + def get_parts(self): + return self.parts + def set_parts(self, parts): + self.parts = parts + partsProp = property(get_parts, set_parts) + def hasContent_(self): + if ( + self.parts is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='BomFile', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('BomFile') + 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_='BomFile') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='BomFile', 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_='BomFile'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='BomFile', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.parts is not None: + self.parts.export(outfile, level, namespaceprefix_, namespacedef_='', name_='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_ == 'parts': + obj_ = PartList.factory(parent_object_=self) + obj_.build(child_) + self.parts = obj_ + obj_.original_tagname_ = 'parts' +# end class BomFile + + +class Part(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, id=None, schema_reference=None, part_type=None, part_numbers=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.id = _cast(None, id) + self.schema_reference = schema_reference + self.part_type = part_type + self.part_numbers = part_numbers + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, Part) + if subclass is not None: + return subclass(*args_, **kwargs_) + if Part.subclass: + return Part.subclass(*args_, **kwargs_) + else: + return Part(*args_, **kwargs_) + factory = staticmethod(factory) + def get_schema_reference(self): + return self.schema_reference + def set_schema_reference(self, schema_reference): + self.schema_reference = schema_reference + schema_referenceProp = property(get_schema_reference, set_schema_reference) + def get_part_type(self): + return self.part_type + def set_part_type(self, part_type): + self.part_type = part_type + part_typeProp = property(get_part_type, set_part_type) + def get_part_numbers(self): + return self.part_numbers + def set_part_numbers(self, part_numbers): + self.part_numbers = part_numbers + part_numbersProp = property(get_part_numbers, set_part_numbers) + def get_id(self): + return self.id + def set_id(self, id): + self.id = id + idProp = property(get_id, set_id) + def hasContent_(self): + if ( + self.schema_reference is not None or + self.part_type is not None or + self.part_numbers is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Part', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('Part') + 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_='Part') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='Part', 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_='Part'): + if self.id is not None and 'id' not in already_processed: + already_processed.add('id') + outfile.write(' id=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.id), input_name='id')), )) + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Part', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.schema_reference is not None: + showIndent(outfile, level, pretty_print) + outfile.write('<%sschema-reference>%s</%sschema-reference>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.schema_reference), input_name='schema-reference')), 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_)) + if self.part_numbers is not None: + self.part_numbers.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-numbers', 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): + value = find_attr_value_('id', node) + if value is not None and 'id' not in already_processed: + already_processed.add('id') + self.id = value + def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): + if nodeName_ == 'schema-reference': + schema_reference_ = child_.text + schema_reference_ = self.gds_validate_string(schema_reference_, node, 'schema_reference') + self.schema_reference = schema_reference_ + elif nodeName_ == 'part-type': + part_type_ = child_.text + part_type_ = self.gds_validate_string(part_type_, node, 'part_type') + self.part_type = part_type_ + elif nodeName_ == 'part-numbers': + obj_ = PartNumberList.factory(parent_object_=self) + obj_.build(child_) + self.part_numbers = obj_ + obj_.original_tagname_ = 'part-numbers' +# end class Part + + +class PartList(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, part=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + if part is None: + self.part = [] + else: + self.part = part + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, PartList) + if subclass is not None: + return subclass(*args_, **kwargs_) + if PartList.subclass: + return PartList.subclass(*args_, **kwargs_) + else: + return PartList(*args_, **kwargs_) + factory = staticmethod(factory) + def get_part(self): + return self.part + def set_part(self, part): + self.part = part + def add_part(self, value): + self.part.append(value) + def add_part(self, value): + self.part.append(value) + def insert_part_at(self, index, value): + self.part.insert(index, value) + def replace_part_at(self, index, value): + self.part[index] = value + partProp = property(get_part, set_part) + def hasContent_(self): + if ( + self.part + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartList', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('PartList') + 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_='PartList') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='PartList', 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_='PartList'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartList', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for part_ in self.part: + part_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='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_ == 'part': + obj_ = Part.factory(parent_object_=self) + obj_.build(child_) + self.part.append(obj_) + obj_.original_tagname_ = 'part' +# end class PartList + + +class PartNumber(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, value=None, distributor=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.value = value + self.distributor = distributor + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, PartNumber) + if subclass is not None: + return subclass(*args_, **kwargs_) + if PartNumber.subclass: + return PartNumber.subclass(*args_, **kwargs_) + else: + return PartNumber(*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_distributor(self): + return self.distributor + def set_distributor(self, distributor): + self.distributor = distributor + distributorProp = property(get_distributor, set_distributor) + def hasContent_(self): + if ( + self.value is not None or + self.distributor is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartNumber', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('PartNumber') + 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_='PartNumber') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='PartNumber', 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_='PartNumber'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartNumber', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + 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.distributor is not None: + showIndent(outfile, level, pretty_print) + outfile.write('<%sdistributor>%s</%sdistributor>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.distributor), input_name='distributor')), namespaceprefix_ , eol_)) + 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_ == 'value': + value_ = child_.text + value_ = self.gds_validate_string(value_, node, 'value') + self.value = value_ + elif nodeName_ == 'distributor': + distributor_ = child_.text + distributor_ = self.gds_validate_string(distributor_, node, 'distributor') + self.distributor = distributor_ +# end class PartNumber + + +class PartNumberList(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, part_number=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + if part_number is None: + self.part_number = [] + else: + self.part_number = part_number + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, PartNumberList) + if subclass is not None: + return subclass(*args_, **kwargs_) + if PartNumberList.subclass: + return PartNumberList.subclass(*args_, **kwargs_) + else: + return PartNumberList(*args_, **kwargs_) + factory = staticmethod(factory) + def get_part_number(self): + return self.part_number + def set_part_number(self, part_number): + self.part_number = part_number + def add_part_number(self, value): + self.part_number.append(value) + def add_part_number(self, value): + self.part_number.append(value) + def insert_part_number_at(self, index, value): + self.part_number.insert(index, value) + def replace_part_number_at(self, index, value): + self.part_number[index] = value + part_numberProp = property(get_part_number, set_part_number) + def hasContent_(self): + if ( + self.part_number + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartNumberList', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('PartNumberList') + 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_='PartNumberList') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='PartNumberList', 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_='PartNumberList'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='PartNumberList', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for part_number_ in self.part_number: + part_number_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='part-number', 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_ == 'part-number': + obj_ = PartNumber.factory(parent_object_=self) + obj_.build(child_) + self.part_number.append(obj_) + obj_.original_tagname_ = 'part-number' +# end class PartNumberList + + +GDSClassesMapping = { + 'bom-file': BomFile, +} + + +USAGE_TEXT = """ +Usage: python <Parser>.py [ -s ] <in_xml_file> +""" + + +def usage(): + print(USAGE_TEXT) + sys.exit(1) + + +def get_root_tag(node): + tag = Tag_pattern_.match(node.tag).groups()[-1] + rootClass = GDSClassesMapping.get(tag) + if rootClass is None: + rootClass = globals().get(tag) + return tag, rootClass + + +def parse(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'BomFile' + rootClass = BomFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + if not silence: + sys.stdout.write('<?xml version="1.0" ?>\n') + rootObj.export( + sys.stdout, 0, name_=rootTag, + namespacedef_='', + pretty_print=True) + return rootObj + + +def parseEtree(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'BomFile' + rootClass = BomFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + mapping = {} + rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) + reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) + if not silence: + content = etree_.tostring( + rootElement, pretty_print=True, + xml_declaration=True, encoding="utf-8") + sys.stdout.write(content) + sys.stdout.write('\n') + return rootObj, rootElement, mapping, reverse_mapping + + +def parseString(inString, silence=False): + '''Parse a string, create the object tree, and export it. + + Arguments: + - inString -- A string. This XML fragment should not start + with an XML declaration containing an encoding. + - silence -- A boolean. If False, export the object. + Returns -- The root object in the tree. + ''' + parser = None + rootNode= parsexmlstring_(inString, parser) + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'BomFile' + rootClass = BomFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + if not silence: + sys.stdout.write('<?xml version="1.0" ?>\n') + rootObj.export( + sys.stdout, 0, name_=rootTag, + namespacedef_='') + return rootObj + + +def parseLiteral(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'BomFile' + rootClass = BomFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + if not silence: + sys.stdout.write('#from bomFile import *\n\n') + sys.stdout.write('import bomFile as model_\n\n') + sys.stdout.write('rootObj = model_.rootClass(\n') + rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) + sys.stdout.write(')\n') + return rootObj + + +def main(): + args = sys.argv[1:] + if len(args) == 1: + parse(args[0]) + else: + usage() + + +if __name__ == '__main__': + #import pdb; pdb.set_trace() + main() + + +__all__ = [ + "BomFile", + "Part", + "PartList", + "PartNumber", + "PartNumberList" +] diff --git a/src/ee/xml/catalogFile.py b/src/ee/xml/catalogFile.py new file mode 100644 index 0000000..61085e7 --- /dev/null +++ b/src/ee/xml/catalogFile.py @@ -0,0 +1,1103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Generated Tue Feb 19 12:27:27 2019 by generateDS.py version 2.30.11. +# Python 3.7.2+ (default, Feb 2 2019, 14:31:48) [GCC 8.2.0] +# +# Command line options: +# ('-f', '') +# ('--one-file-per-xsd', '') +# ('--output-directory', 'src/ee/xml') +# ('-m', '') +# +# Command line arguments: +# xsd/ee-catalog.xsd +# +# Command line: +# env/bin/generateDS.py -f --one-file-per-xsd --output-directory="src/ee/xml" -m xsd/ee-catalog.xsd +# +# Current working directory (os.getcwd()): +# ee-python +# + +import sys +import re as re_ +import base64 +import datetime as datetime_ +import warnings as warnings_ +try: + from lxml import etree as etree_ +except ImportError: + from xml.etree import ElementTree as etree_ + + +Validate_simpletypes_ = True +if sys.version_info.major == 2: + BaseStrType_ = basestring +else: + BaseStrType_ = str + + +def parsexml_(infile, parser=None, **kwargs): + if parser is None: + # Use the lxml ElementTree compatible parser so that, e.g., + # we ignore comments. + try: + parser = etree_.ETCompatXMLParser() + except AttributeError: + # fallback to xml.etree + parser = etree_.XMLParser() + doc = etree_.parse(infile, parser=parser, **kwargs) + return doc + +def parsexmlstring_(instring, parser=None, **kwargs): + if parser is None: + # Use the lxml ElementTree compatible parser so that, e.g., + # we ignore comments. + try: + parser = etree_.ETCompatXMLParser() + except AttributeError: + # fallback to xml.etree + parser = etree_.XMLParser() + element = etree_.fromstring(instring, parser=parser, **kwargs) + return element + +# +# Namespace prefix definition table (and other attributes, too) +# +# The module generatedsnamespaces, if it is importable, must contain +# a dictionary named GeneratedsNamespaceDefs. This Python dictionary +# should map element type names (strings) to XML schema namespace prefix +# definitions. The export method for any class for which there is +# a namespace prefix definition, will export that definition in the +# XML representation of that element. See the export method of +# any generated element type class for a example of the use of this +# table. +# A sample table is: +# +# # File: generatedsnamespaces.py +# +# GenerateDSNamespaceDefs = { +# "ElementtypeA": "http://www.xxx.com/namespaceA", +# "ElementtypeB": "http://www.xxx.com/namespaceB", +# } +# + +try: + from generatedsnamespaces import GenerateDSNamespaceDefs as GenerateDSNamespaceDefs_ +except ImportError: + GenerateDSNamespaceDefs_ = {} + +# +# The root super-class for element type classes +# +# Calls to the methods in these classes are generated by generateDS.py. +# You can replace these methods by re-implementing the following class +# in a module named generatedssuper.py. + +try: + from generatedssuper import GeneratedsSuper +except ImportError as exp: + + class GeneratedsSuper(object): + tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') + class _FixedOffsetTZ(datetime_.tzinfo): + def __init__(self, offset, name): + self.__offset = datetime_.timedelta(minutes=offset) + self.__name = name + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return None + def gds_format_string(self, input_data, input_name=''): + return input_data + def gds_validate_string(self, input_data, node=None, input_name=''): + if not input_data: + return '' + else: + return input_data + def gds_format_base64(self, input_data, input_name=''): + return base64.b64encode(input_data) + def gds_validate_base64(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer(self, input_data, input_name=''): + return '%d' % input_data + def gds_validate_integer(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_integer_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + int(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of integers') + return values + def gds_format_float(self, input_data, input_name=''): + return ('%.15f' % input_data).rstrip('0') + def gds_validate_float(self, input_data, node=None, input_name=''): + return input_data + def gds_format_float_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_float_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of floats') + return values + def gds_format_double(self, input_data, input_name=''): + return '%e' % input_data + def gds_validate_double(self, input_data, node=None, input_name=''): + return input_data + def gds_format_double_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_double_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of doubles') + return values + def gds_format_boolean(self, input_data, input_name=''): + return ('%s' % input_data).lower() + def gds_validate_boolean(self, input_data, node=None, input_name=''): + return input_data + def gds_format_boolean_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_boolean_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + if value not in ('true', '1', 'false', '0', ): + raise_parse_error( + node, + 'Requires sequence of booleans ' + '("true", "1", "false", "0")') + return values + def gds_validate_datetime(self, input_data, node=None, input_name=''): + return input_data + def gds_format_datetime(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + @classmethod + def gds_parse_datetime(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + time_parts = input_data.split('.') + if len(time_parts) > 1: + micro_seconds = int(float('0.' + time_parts[1]) * 1000000) + input_data = '%s.%s' % ( + time_parts[0], "{}".format(micro_seconds).rjust(6, "0"), ) + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt + def gds_validate_date(self, input_data, node=None, input_name=''): + return input_data + def gds_format_date(self, input_data, input_name=''): + _svalue = '%04d-%02d-%02d' % ( + input_data.year, + input_data.month, + input_data.day, + ) + try: + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format( + hours, minutes) + except AttributeError: + pass + return _svalue + @classmethod + def gds_parse_date(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') + dt = dt.replace(tzinfo=tz) + return dt.date() + def gds_validate_time(self, input_data, node=None, input_name=''): + return input_data + def gds_format_time(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%02d:%02d:%02d' % ( + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%02d:%02d:%02d.%s' % ( + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + def gds_validate_simple_patterns(self, patterns, target): + # pat is a list of lists of strings/patterns. + # The target value must match at least one of the patterns + # in order for the test to succeed. + found1 = True + for patterns1 in patterns: + found2 = False + for patterns2 in patterns1: + mo = re_.search(patterns2, target) + if mo is not None and len(mo.group(0)) == len(target): + found2 = True + break + if not found2: + found1 = False + break + return found1 + @classmethod + def gds_parse_time(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + if len(input_data.split('.')) > 1: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt.time() + def gds_str_lower(self, instring): + return instring.lower() + def get_path_(self, node): + path_list = [] + self.get_path_list_(node, path_list) + path_list.reverse() + path = '/'.join(path_list) + return path + Tag_strip_pattern_ = re_.compile(r'\{.*\}') + def get_path_list_(self, node, path_list): + if node is None: + return + tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) + if tag: + path_list.append(tag) + self.get_path_list_(node.getparent(), path_list) + def get_class_obj_(self, node, default_class=None): + class_obj1 = default_class + if 'xsi' in node.nsmap: + classname = node.get('{%s}type' % node.nsmap['xsi']) + if classname is not None: + names = classname.split(':') + if len(names) == 2: + classname = names[1] + class_obj2 = globals().get(classname) + if class_obj2 is not None: + class_obj1 = class_obj2 + return class_obj1 + def gds_build_any(self, node, type_name=None): + return None + @classmethod + def gds_reverse_node_mapping(cls, mapping): + return dict(((v, k) for k, v in mapping.items())) + @staticmethod + def gds_encode(instring): + if sys.version_info.major == 2: + if ExternalEncoding: + encoding = ExternalEncoding + else: + encoding = 'utf-8' + return instring.encode(encoding) + else: + return instring + @staticmethod + def convert_unicode(instring): + if isinstance(instring, str): + result = quote_xml(instring) + elif sys.version_info.major == 2 and isinstance(instring, unicode): + result = quote_xml(instring).encode('utf8') + else: + result = GeneratedsSuper.gds_encode(str(instring)) + return result + def __eq__(self, other): + if type(self) != type(other): + return False + return self.__dict__ == other.__dict__ + def __ne__(self, other): + return not self.__eq__(other) + + def getSubclassFromModule_(module, class_): + '''Get the subclass of a class from a specific module.''' + name = class_.__name__ + 'Sub' + if hasattr(module, name): + return getattr(module, name) + else: + return None + + +# +# If you have installed IPython you can uncomment and use the following. +# IPython is available from http://ipython.scipy.org/. +# + +## from IPython.Shell import IPShellEmbed +## args = '' +## ipshell = IPShellEmbed(args, +## banner = 'Dropping into IPython', +## exit_msg = 'Leaving Interpreter, back to program.') + +# Then use the following line where and when you want to drop into the +# IPython shell: +# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit') + +# +# Globals +# + +ExternalEncoding = '' +Tag_pattern_ = re_.compile(r'({.*})?(.*)') +String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") +Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') +CDATA_pattern_ = re_.compile(r"<!\[CDATA\[.*?\]\]>", re_.DOTALL) + +# Change this to redirect the generated superclass module to use a +# specific subclass module. +CurrentSubclassModule_ = None + +# +# Support/utility functions. +# + + +def showIndent(outfile, level, pretty_print=True): + if pretty_print: + for idx in range(level): + outfile.write(' ') + + +def quote_xml(inStr): + "Escape markup chars, but do not modify CDATA sections." + if not inStr: + return '' + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s2 = '' + pos = 0 + matchobjects = CDATA_pattern_.finditer(s1) + for mo in matchobjects: + s3 = s1[pos:mo.start()] + s2 += quote_xml_aux(s3) + s2 += s1[mo.start():mo.end()] + pos = mo.end() + s3 = s1[pos:] + s2 += quote_xml_aux(s3) + return s2 + + +def quote_xml_aux(inStr): + s1 = inStr.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + return s1 + + +def quote_attrib(inStr): + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + if '"' in s1: + if "'" in s1: + s1 = '"%s"' % s1.replace('"', """) + else: + s1 = "'%s'" % s1 + else: + s1 = '"%s"' % s1 + return s1 + + +def quote_python(inStr): + s1 = inStr + if s1.find("'") == -1: + if s1.find('\n') == -1: + return "'%s'" % s1 + else: + return "'''%s'''" % s1 + else: + if s1.find('"') != -1: + s1 = s1.replace('"', '\\"') + if s1.find('\n') == -1: + return '"%s"' % s1 + else: + return '"""%s"""' % s1 + + +def get_all_text_(node): + if node.text is not None: + text = node.text + else: + text = '' + for child in node: + if child.tail is not None: + text += child.tail + return text + + +def find_attr_value_(attr_name, node): + attrs = node.attrib + attr_parts = attr_name.split(':') + value = None + if len(attr_parts) == 1: + value = attrs.get(attr_name) + elif len(attr_parts) == 2: + prefix, name = attr_parts + namespace = node.nsmap.get(prefix) + if namespace is not None: + value = attrs.get('{%s}%s' % (namespace, name, )) + return value + + +class GDSParseError(Exception): + pass + + +def raise_parse_error(node, msg): + msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline, ) + raise GDSParseError(msg) + + +class MixedContainer: + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + TypeBase64 = 8 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name + def export(self, outfile, level, name, namespace, + pretty_print=True): + if self.category == MixedContainer.CategoryText: + # Prevent exporting empty content as empty lines. + if self.value.strip(): + outfile.write(self.value) + elif self.category == MixedContainer.CategorySimple: + self.exportSimple(outfile, level, name) + else: # category == MixedContainer.CategoryComplex + self.value.export( + outfile, level, namespace, name_=name, + pretty_print=pretty_print) + def exportSimple(self, outfile, level, name): + if self.content_type == MixedContainer.TypeString: + outfile.write('<%s>%s</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeInteger or \ + self.content_type == MixedContainer.TypeBoolean: + outfile.write('<%s>%d</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeFloat or \ + self.content_type == MixedContainer.TypeDecimal: + outfile.write('<%s>%f</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeDouble: + outfile.write('<%s>%g</%s>' % ( + self.name, self.value, self.name)) + elif self.content_type == MixedContainer.TypeBase64: + outfile.write('<%s>%s</%s>' % ( + self.name, + base64.b64encode(self.value), + self.name)) + def to_etree(self, element): + if self.category == MixedContainer.CategoryText: + # Prevent exporting empty content as empty lines. + if self.value.strip(): + if len(element) > 0: + if element[-1].tail is None: + element[-1].tail = self.value + else: + element[-1].tail += self.value + else: + if element.text is None: + element.text = self.value + else: + element.text += self.value + elif self.category == MixedContainer.CategorySimple: + subelement = etree_.SubElement( + element, '%s' % self.name) + subelement.text = self.to_etree_simple() + else: # category == MixedContainer.CategoryComplex + self.value.to_etree(element) + def to_etree_simple(self): + if self.content_type == MixedContainer.TypeString: + text = self.value + elif (self.content_type == MixedContainer.TypeInteger or + self.content_type == MixedContainer.TypeBoolean): + text = '%d' % self.value + elif (self.content_type == MixedContainer.TypeFloat or + self.content_type == MixedContainer.TypeDecimal): + text = '%f' % self.value + elif self.content_type == MixedContainer.TypeDouble: + text = '%g' % self.value + elif self.content_type == MixedContainer.TypeBase64: + text = '%s' % base64.b64encode(self.value) + return text + def exportLiteral(self, outfile, level, name): + if self.category == MixedContainer.CategoryText: + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( + self.category, self.content_type, + self.name, self.value)) + elif self.category == MixedContainer.CategorySimple: + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( + self.category, self.content_type, + self.name, self.value)) + else: # category == MixedContainer.CategoryComplex + showIndent(outfile, level) + outfile.write( + 'model_.MixedContainer(%d, %d, "%s",\n' % ( + self.category, self.content_type, self.name,)) + self.value.exportLiteral(outfile, level + 1) + showIndent(outfile, level) + outfile.write(')\n') + + +class MemberSpec_(object): + def __init__(self, name='', data_type='', container=0, + optional=0, child_attrs=None, choice=None): + self.name = name + self.data_type = data_type + self.container = container + self.child_attrs = child_attrs + self.choice = choice + self.optional = optional + def set_name(self, name): self.name = name + def get_name(self): return self.name + def set_data_type(self, data_type): self.data_type = data_type + def get_data_type_chain(self): return self.data_type + def get_data_type(self): + if isinstance(self.data_type, list): + if len(self.data_type) > 0: + return self.data_type[-1] + else: + return 'xs:string' + else: + return self.data_type + def set_container(self, container): self.container = container + def get_container(self): return self.container + def set_child_attrs(self, child_attrs): self.child_attrs = child_attrs + def get_child_attrs(self): return self.child_attrs + def set_choice(self, choice): self.choice = choice + def get_choice(self): return self.choice + def set_optional(self, optional): self.optional = optional + def get_optional(self): return self.optional + + +def _cast(typ, value): + if typ is None or value is None: + return value + return typ(value) + +# +# Data representation classes. +# + + +class CatalogFile(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, products=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.products = products + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, CatalogFile) + if subclass is not None: + return subclass(*args_, **kwargs_) + if CatalogFile.subclass: + return CatalogFile.subclass(*args_, **kwargs_) + else: + return CatalogFile(*args_, **kwargs_) + factory = staticmethod(factory) + def get_products(self): + return self.products + def set_products(self, products): + self.products = products + productsProp = property(get_products, set_products) + def hasContent_(self): + if ( + self.products is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='CatalogFile', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('CatalogFile') + 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_='CatalogFile') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='CatalogFile', 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_='CatalogFile'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='CatalogFile', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.products is not None: + self.products.export(outfile, level, namespaceprefix_, namespacedef_='', name_='products', 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_ == 'products': + obj_ = ProductList.factory(parent_object_=self) + obj_.build(child_) + self.products = obj_ + obj_.original_tagname_ = 'products' +# end class CatalogFile + + +class Product(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, ref=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + self.ref = ref + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, Product) + if subclass is not None: + return subclass(*args_, **kwargs_) + if Product.subclass: + return Product.subclass(*args_, **kwargs_) + else: + return Product(*args_, **kwargs_) + factory = staticmethod(factory) + def get_ref(self): + return self.ref + def set_ref(self, ref): + self.ref = ref + refProp = property(get_ref, set_ref) + def hasContent_(self): + if ( + self.ref is not None + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Product', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('Product') + 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_='Product') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='Product', 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_='Product'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='Product', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + if self.ref is not None: + showIndent(outfile, level, pretty_print) + outfile.write('<%sref>%s</%sref>%s' % (namespaceprefix_ , self.gds_encode(self.gds_format_string(quote_xml(self.ref), input_name='ref')), namespaceprefix_ , eol_)) + 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_ == 'ref': + ref_ = child_.text + ref_ = self.gds_validate_string(ref_, node, 'ref') + self.ref = ref_ +# end class Product + + +class ProductList(GeneratedsSuper): + subclass = None + superclass = None + def __init__(self, product=None, **kwargs_): + self.original_tagname_ = None + self.parent_object_ = kwargs_.get('parent_object_') + if product is None: + self.product = [] + else: + self.product = product + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, ProductList) + if subclass is not None: + return subclass(*args_, **kwargs_) + if ProductList.subclass: + return ProductList.subclass(*args_, **kwargs_) + else: + return ProductList(*args_, **kwargs_) + factory = staticmethod(factory) + def get_product(self): + return self.product + def set_product(self, product): + self.product = product + def add_product(self, value): + self.product.append(value) + def add_product(self, value): + self.product.append(value) + def insert_product_at(self, index, value): + self.product.insert(index, value) + def replace_product_at(self, index, value): + self.product[index] = value + productProp = property(get_product, set_product) + def hasContent_(self): + if ( + self.product + ): + return True + else: + return False + def export(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ProductList', pretty_print=True): + imported_ns_def_ = GenerateDSNamespaceDefs_.get('ProductList') + 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_='ProductList') + if self.hasContent_(): + outfile.write('>%s' % (eol_, )) + self.exportChildren(outfile, level + 1, namespaceprefix_, namespacedef_, name_='ProductList', 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_='ProductList'): + pass + def exportChildren(self, outfile, level, namespaceprefix_='', namespacedef_='', name_='ProductList', fromsubclass_=False, pretty_print=True): + if pretty_print: + eol_ = '\n' + else: + eol_ = '' + for product_ in self.product: + product_.export(outfile, level, namespaceprefix_, namespacedef_='', name_='product', 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_ == 'product': + obj_ = Product.factory(parent_object_=self) + obj_.build(child_) + self.product.append(obj_) + obj_.original_tagname_ = 'product' +# end class ProductList + + +GDSClassesMapping = { +} + + +USAGE_TEXT = """ +Usage: python <Parser>.py [ -s ] <in_xml_file> +""" + + +def usage(): + print(USAGE_TEXT) + sys.exit(1) + + +def get_root_tag(node): + tag = Tag_pattern_.match(node.tag).groups()[-1] + rootClass = GDSClassesMapping.get(tag) + if rootClass is None: + rootClass = globals().get(tag) + return tag, rootClass + + +def parse(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'CatalogFile' + rootClass = CatalogFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + if not silence: + sys.stdout.write('<?xml version="1.0" ?>\n') + rootObj.export( + sys.stdout, 0, name_=rootTag, + namespacedef_='', + pretty_print=True) + return rootObj + + +def parseEtree(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'CatalogFile' + rootClass = CatalogFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + mapping = {} + rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) + reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) + if not silence: + content = etree_.tostring( + rootElement, pretty_print=True, + xml_declaration=True, encoding="utf-8") + sys.stdout.write(content) + sys.stdout.write('\n') + return rootObj, rootElement, mapping, reverse_mapping + + +def parseString(inString, silence=False): + '''Parse a string, create the object tree, and export it. + + Arguments: + - inString -- A string. This XML fragment should not start + with an XML declaration containing an encoding. + - silence -- A boolean. If False, export the object. + Returns -- The root object in the tree. + ''' + parser = None + rootNode= parsexmlstring_(inString, parser) + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'CatalogFile' + rootClass = CatalogFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + if not silence: + sys.stdout.write('<?xml version="1.0" ?>\n') + rootObj.export( + sys.stdout, 0, name_=rootTag, + namespacedef_='') + return rootObj + + +def parseLiteral(inFileName, silence=False): + parser = None + doc = parsexml_(inFileName, parser) + rootNode = doc.getroot() + rootTag, rootClass = get_root_tag(rootNode) + if rootClass is None: + rootTag = 'CatalogFile' + rootClass = CatalogFile + rootObj = rootClass.factory() + rootObj.build(rootNode) + # Enable Python to collect the space used by the DOM. + doc = None + if not silence: + sys.stdout.write('#from catalogFile import *\n\n') + sys.stdout.write('import catalogFile as model_\n\n') + sys.stdout.write('rootObj = model_.rootClass(\n') + rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) + sys.stdout.write(')\n') + return rootObj + + +def main(): + args = sys.argv[1:] + if len(args) == 1: + parse(args[0]) + else: + usage() + + +if __name__ == '__main__': + #import pdb; pdb.set_trace() + main() + + +__all__ = [ + "CatalogFile", + "Product", + "ProductList" +] diff --git a/xsd/ee-bom.xsd b/xsd/ee-bom.xsd new file mode 100644 index 0000000..a9a2cc1 --- /dev/null +++ b/xsd/ee-bom.xsd @@ -0,0 +1,63 @@ +<xs:schema + xmlns:xs="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://purl.org/ee/bom-file" + xmlns="http://purl.org/ee/bom-file"> + + <xs:attribute name="id" type="xs:string"/> + + <xs:element name="bom-file" type="BomFile"/> + + <xs:complexType name="BomFile"> + <xs:sequence> + <xs:element name="parts" type="PartList" minOccurs="0" maxOccurs="1"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="Part"> + <xs:sequence> + <xs:element name="schema-reference" type="xs:string"/> + <xs:element name="part-type" type="xs:anyURI"/> + <!-- + <xs:element name="manufacturer-part-number" type="xs:string"/> + <xs:element name="distributor-part-numbers" type="DistributorPartNumberList"/> + --> + <xs:element name="part-numbers" type="PartNumberList"/> + </xs:sequence> + <xs:attribute ref="id" use="required"/> + </xs:complexType> + + <xs:complexType name="PartList"> + <xs:sequence> + <xs:element name="part" type="Part" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + + <!-- + <xs:complexType name="DistributorPartNumber"> + <xs:sequence> + <xs:element name="distributor" type="xs:anyURI"/> + <xs:element name="number" type="xs:string"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="DistributorPartNumberList"> + <xs:sequence> + <xs:element name="distributor-part-number" type="DistributorPartNumber" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + --> + + <xs:complexType name="PartNumber"> + <xs:sequence> + <xs:element name="value" type="xs:string"/> + <xs:element name="distributor" type="xs:anyURI"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="PartNumberList"> + <xs:sequence> + <xs:element name="part-number" type="PartNumber" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + +</xs:schema> diff --git a/xsd/ee-catalog.xsd b/xsd/ee-catalog.xsd new file mode 100644 index 0000000..6da3558 --- /dev/null +++ b/xsd/ee-catalog.xsd @@ -0,0 +1,26 @@ +<xsd:schema + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://purl.org/ee/bom-file" + xmlns="http://purl.org/ee/bom-file"> + + <xsd:element name="catalog-file" type="CatalogFile"/> + + <xsd:complexType name="CatalogFile"> + <xsd:sequence> + <xsd:element name="products" type="ProductList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="Product"> + <xsd:sequence> + <xsd:element name="ref" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ProductList"> + <xsd:sequence> + <xsd:element name="product" type="Product" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + +</xsd:schema> |