diff --git a/TODO.txt b/TODO.txt
index b2e5ee911e..485f7b8890 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -19,6 +19,11 @@ Common
* Push file open semantics down to one of the base frame classes ( likely candidate is
WinEDA_BasicFrame ) so that file open behavior is consistent across all applications.
+* Look over Brian's python BOM generation scripts, which are now in
+ scripts/python/ky and sort them out, and get something into the installation as well.
+ Code came from Brian in this posting's attachment, which is ky2.zip:
+ https://lists.launchpad.net/kicad-developers/msg06763.html
+ but is now in scripts/python/ky temporarily.
CvPCB
@@ -48,6 +53,4 @@ E6) Start initial work for changing component library file format to use Dick's
PCBNew
------
-Dick:
-* Use BOARD_ITEM::MenuIcon() in the onrightclick.cpp
diff --git a/scripts/bom-in-python/ky/bom_example1.py b/scripts/bom-in-python/ky/bom_example1.py
new file mode 100644
index 0000000000..e1508baaaf
--- /dev/null
+++ b/scripts/bom-in-python/ky/bom_example1.py
@@ -0,0 +1,38 @@
+#
+# Example python script to generate a BOM from a KiCad generic netlist
+#
+# Example: Tab delimited list (The same as std output) Ungrouped
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import csv
+import sys
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+# Create a new csv writer object to use as the output formatter, although we
+# are created a tab delimited list instead!
+out = csv.writer(f, delimiter='\t', quoting=csv.QUOTE_NONE)
+
+# Output a field delimited header line
+out.writerow(['Source:', net.getSource()])
+out.writerow(['Date:', net.getDate()])
+out.writerow(['Tool:', net.getTool()])
+out.writerow(['Component Count:', len(net.components)])
+out.writerow(['Ref', 'Value', 'Part', 'Documentation', 'Description', 'Vendor'])
+
+# Output all of the component information
+for c in net.components:
+ out.writerow([c.getRef(), c.getValue(), c.getLib() + "/" + c.getPart(),
+ c.getDatasheet(), c.getDescription(), c.getField("Vendor")])
diff --git a/scripts/bom-in-python/ky/bom_example2.py b/scripts/bom-in-python/ky/bom_example2.py
new file mode 100644
index 0000000000..23fb870f52
--- /dev/null
+++ b/scripts/bom-in-python/ky/bom_example2.py
@@ -0,0 +1,38 @@
+#
+# Example python script to generate a BOM from a KiCad generic netlist
+#
+# Example: Ungrouped (One component per row) CSV output
+#
+
+# Import the KiCad python helper module
+import ky
+import csv
+import sys
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+# Create a new csv writer object to use as the output formatter
+out = csv.writer(f, delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL)
+
+# Output a field delimited header line
+out.writerow(['Source:', net.getSource()])
+out.writerow(['Date:', net.getDate()])
+out.writerow(['Tool:', net.getTool()])
+out.writerow(['Component Count:', len(net.components)])
+out.writerow(['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor'])
+
+# Output all of the component information (One component per row)
+for c in net.components:
+ out.writerow([c.getRef(), c.getValue(), c.getFootprint(), c.getDatasheet(),
+ c.getField("Manufacturer"), c.getField("Vendor")])
+
diff --git a/scripts/bom-in-python/ky/bom_example3.py b/scripts/bom-in-python/ky/bom_example3.py
new file mode 100644
index 0000000000..c5581fa6b7
--- /dev/null
+++ b/scripts/bom-in-python/ky/bom_example3.py
@@ -0,0 +1,51 @@
+#
+# Example python script to generate a BOM from a KiCad generic netlist
+#
+# Example: Sorted and Grouped CSV BOM
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import csv
+import sys
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+# Create a new csv writer object to use as the output formatter
+out = csv.writer(f, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
+
+# Output a set of rows for a header providing general information
+out.writerow(['Source:', net.getSource()])
+out.writerow(['Date:', net.getDate()])
+out.writerow(['Tool:', net.getTool()])
+out.writerow(['Component Count:', len(net.components)])
+out.writerow(['Ref', 'Qnty', 'Value', 'Part', 'Datasheet', 'Description', 'Vendor'])
+
+# Get all of the components in groups of matching parts + values (see ky.py)
+grouped = net.groupComponents()
+
+# Output all of the component information
+for group in grouped:
+ refs = ""
+
+ # Add the reference of every component in the group and keep a reference
+ # to the component so that the other data can be filled in once per group
+ for component in group:
+ refs += component.getRef() + ", "
+ c = component
+
+ # Fill in the component groups common data
+ out.writerow([refs, len(group), c.getValue(), c.getLib() + "/" + c.getPart(), c.getDatasheet(),
+ c.getDescription(), c.getField("Vendor")])
+
+
diff --git a/scripts/bom-in-python/ky/bom_example4.py b/scripts/bom-in-python/ky/bom_example4.py
new file mode 100644
index 0000000000..b438e73a7d
--- /dev/null
+++ b/scripts/bom-in-python/ky/bom_example4.py
@@ -0,0 +1,78 @@
+#
+# Example python script to generate a BOM from a KiCad generic netlist
+#
+# Example: Sorted and Grouped HTML BOM
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import sys
+
+# Start with a basic html template
+html = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+# Output a set of rows for a header providing general information
+html = html.replace('', net.getSource())
+html = html.replace('', net.getDate())
+html = html.replace('', net.getTool())
+html = html.replace('', "Component Count:" + \
+ str(len(net.components)))
+
+row = "Ref | " + "Qnty | "
+row += "Value | " + "Part | " + "Datasheet | "
+row += "Description | " + "Vendor |
"
+
+html = html.replace('', row + "")
+
+# Get all of the components in groups of matching parts + values (see ky.py)
+grouped = net.groupComponents()
+
+# Output all of the component information
+for group in grouped:
+ refs = ""
+
+ # Add the reference of every component in the group and keep a reference
+ # to the component so that the other data can be filled in once per group
+ for component in group:
+ refs += component.getRef() + ", "
+ c = component
+
+ row = "" + refs +" | " + str(len(group))
+ row += " | " + c.getValue() + " | " + c.getLib() + "/"
+ row += c.getPart() + " | " + c.getDatasheet() + " | "
+ row += c.getDescription() + " | " + c.getField("Vendor")
+ row += " |
"
+
+ html = html.replace('', row + "")
+
+# Print the formatted html to the file
+print >> f, html
diff --git a/scripts/bom-in-python/ky/bom_example5.py b/scripts/bom-in-python/ky/bom_example5.py
new file mode 100644
index 0000000000..a4b8ba8e2d
--- /dev/null
+++ b/scripts/bom-in-python/ky/bom_example5.py
@@ -0,0 +1,113 @@
+#
+# Example python script to generate a BOM from a KiCad generic netlist
+#
+# Example: Sorted and Grouped HTML BOM with more advanced grouping
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import sys
+
+# Start with a basic html template
+html = """
+
+
+
+
+ KiCad BOM Example 5
+
+
+
+
+
+
+
+
+
+ """
+
+def myEqu(self, other):
+ """myEqu is a more advanced equivalence function for components which is
+ used by component grouping. Normal operation is to group components based
+ on their Value, Library source, and Library part.
+
+ In this example of a more advanced equivalency operator we also compare the
+ custom fields Voltage, Tolerance and Manufacturer as well as the assigned
+ footprint. If these fields are not used in some parts they will simply be
+ ignored (they will match as both will be empty strings).
+
+ """
+ result = True
+ if self.getValue() != other.getValue():
+ result = False
+ elif self.getLib() != other.getLib():
+ result = False
+ elif self.getPart() != other.getPart():
+ result = False
+ elif self.getFootprint() != other.getFootprint():
+ result = False
+ elif self.getField("Tolerance") != other.getField("Tolerance"):
+ result = False
+ elif self.getField("Manufacturer") != other.getField("Manufacturer"):
+ result = False
+ elif self.getField("Voltage") != other.getField("Voltage"):
+ result = False
+
+ return result
+
+# Override the component equivalence operator - it is important to do this
+# before loading the netlist, otherwise all components will have the original
+# equivalency operator.
+ky.component.__equ__ = myEqu
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# video.tmp. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write too, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+# Output a set of rows for a header providing general information
+html = html.replace('', net.getSource())
+html = html.replace('', net.getDate())
+html = html.replace('', net.getTool())
+html = html.replace('', "Component Count:" + \
+ str(len(net.components)))
+
+row = "Ref | " + "Qnty | "
+row += "Value | " + "Part | " + "Datasheet | "
+row += "Description | " + "Vendor |
"
+
+html = html.replace('', row + "")
+
+# Get all of the components in groups of matching parts + values (see ky.py)
+grouped = net.groupComponents()
+
+# Output all of the component information
+for group in grouped:
+ refs = ""
+
+ # Add the reference of every component in the group and keep a reference
+ # to the component so that the other data can be filled in once per group
+ for component in group:
+ refs += component.getRef() + ", "
+ c = component
+
+ row = "" + refs +" | " + str(len(group))
+ row += " | " + c.getValue() + " | " + c.getLib() + "/"
+ row += c.getPart() + " | " + c.getDatasheet() + " | "
+ row += c.getDescription() + " | " + c.getField("Vendor")
+ row += " |
"
+
+ html = html.replace('', row + "")
+
+# Print the formatted html to output file
+print >> f, html
diff --git a/scripts/bom-in-python/ky/ky.py b/scripts/bom-in-python/ky/ky.py
new file mode 100644
index 0000000000..ad809a8919
--- /dev/null
+++ b/scripts/bom-in-python/ky/ky.py
@@ -0,0 +1,450 @@
+#
+# KiCad python module for interpreting generic netlists which can be used
+# to generate Bills of materials, etc.
+#
+# No string formatting is used on purpose as the only string formatting that
+# is current compatible with python 2.4+ to 3.0+ is the '%' method, and that
+# is due to be deprecated in 3.0+ soon
+#
+
+import sys
+import xml.sax as sax
+
+
+class component():
+ """Class for a set of component information"""
+ def __init__(self, element):
+ self.element = element
+ self.libpart = None
+
+ # Set to true when this component is included in a component group
+ self.grouped = False
+
+ def __eq__(self, other):
+ """Equlivalency operator, remember this can be easily overloaded"""
+ result = False
+ if self.getValue() == other.getValue():
+ if self.getLib() == other.getLib():
+ if self.getPart() == other.getPart():
+ result = True
+ return result
+
+ def setPart(self, part):
+ self.libpart = part
+
+ def setValue(self, value):
+ """Set the value of this component"""
+ v = self.element.getChild("value")
+ if v:
+ v.setChars(value)
+
+ def getValue(self):
+ return self.element.get("value")
+
+ def getRef(self):
+ return self.element.get("comp", "ref")
+
+ def getFootprint(self):
+ return self.element.get("footprint")
+
+ def getDatasheet(self):
+ return self.element.get("datasheet")
+
+ def getLib(self):
+ return self.element.get("libsource", "lib")
+
+ def getPart(self):
+ return self.element.get("libsource", "part")
+
+ def getTimestamp(self):
+ return self.element.get("tstamp")
+
+ def getDescription(self):
+ # When attempting to access the part, we must take care in case the part
+ # cannot be found in the netlist
+ try:
+ d = self.libpart.getDescription()
+ except AttributeError:
+ d = ""
+ return d
+
+ def getDatasheet(self):
+ # When attempting to access the part, we must take care in case the part
+ # cannot be found in the netlist
+ try:
+ d = self.libpart.getDatasheet()
+ except AttributeError:
+ d = ""
+ return d
+
+ def getField(self, name):
+ """Return the value of a field named name. The component is first
+ checked for the field, and then the components library part is checked
+ for the field. If the field doesn't exist in either, an empty string is
+ returned
+
+ Keywords:
+ name -- The name of the field to return the value for
+
+ """
+ field = self.element.get("field", "name", name)
+ if field == "":
+ try:
+ field = self.libpart.getField(name)
+ except AttributeError:
+ field = ""
+ return field
+
+
+class netlistElement():
+ """Generic netlist element. All elements for a netlist tree which can be
+ used to easily generate various output formats by propogating format
+ requests to all children
+ """
+ def __init__(self, name, parent=None):
+ self.name = name
+ self.attributes = {}
+ self.parent = parent
+ self.chars = ""
+ self.children = []
+ self.indent = ""
+
+ def __str__(self):
+ """String representation of this netlist element
+
+ """
+ return (self.name + "[" + self.chars + "]" + " attr:" +
+ str(len(self.attributes[a])))
+
+ def formatXML(self, amChild=False):
+ """Return this element formatted as XML
+
+ Keywords:
+ amChild -- If set to True, the start of document is not returned
+
+ """
+ s = ""
+
+ if not amChild:
+ s = "\n"
+
+ s += self.indent + "<" + self.name
+ for a in self.attributes:
+ s += " " + a + "=\"" + self.attributes[a] + "\""
+
+ if (len(self.chars) == 0) and (len(self.children) == 0):
+ s += "/>"
+ else:
+ s += ">" + self.chars
+
+ for c in self.children:
+ c.indent += self.indent + " "
+ s += "\n"
+ s += c.formatXML(True)
+
+ if (len(self.children) > 0):
+ s += "\n" + self.indent
+
+ if (len(self.children) > 0) or (len(self.chars) > 0):
+ s += "" + self.name + ">"
+
+ return s
+
+ def formatHTML(self, amChild=False):
+ """Return this element formatted as HTML
+
+ Keywords:
+ amChild -- If set to True, the start of document is not returned
+
+ """
+ s = ""
+
+ if not amChild:
+ s = """
+
+
+
+
+
+
+
+ """
+
+ s += "" + self.name + " " + self.chars + " | "
+ for a in self.attributes:
+ s += "- " + a + " = " + self.attributes[a] + "
"
+
+ s += " |
\n"
+
+ for c in self.children:
+ s += c.formatHTML(True)
+
+ if not amChild:
+ s += """
+
+ """
+
+ return s
+
+ def addAttribute(self, attr, value):
+ """Add an attribute to this element"""
+ self.attributes[attr] = value
+
+ def setChars(self, chars):
+ """Set the characters for this element"""
+ self.chars = chars
+
+ def addChars(self, chars):
+ """Add characters (textual value) to this element"""
+ self.chars += chars
+
+ def addChild(self, child):
+ """Add a child element to this element"""
+ self.children.append(child)
+ return self.children[len(self.children) - 1]
+
+ def getParent(self):
+ """Get the parent of this element (Could be None)"""
+ return self.parent
+
+ def setAttribute(self, attr, value):
+ """Set an attributes value - in fact does the same thing as add
+ attribute
+
+ """
+ self.attributes[attr] = value
+
+ def getChild(self, name):
+ """Returns a child element of name
+
+ Keywords:
+ name -- The name of the child element to return"""
+ for child in self.children:
+ if child.name == name:
+ return child
+
+ return None
+
+ def get(self, element, attribute="", attrmatch=""):
+ """Return the data for either an attribute, or else an element"""
+ if (self.name == element):
+ if attribute != "":
+ if attrmatch != "":
+ if self.attributes[attribute] == attrmatch:
+ return self.chars
+ else:
+ return self.attributes[attribute]
+ else:
+ return self.chars
+
+ for child in self.children:
+ if child.get(element, attribute, attrmatch) != "":
+ return child.get(element, attribute, attrmatch)
+
+ return ""
+
+
+class netlist():
+ """ Kicad generic netlist class. Generally loaded from a kicad generic
+ netlist file. Includes several helper functions to ease BOM creating
+ scripts
+
+ """
+ def __init__(self, fname=""):
+ """Initialiser for the genericNetlist class
+
+ Keywords:
+ fname -- The name of the generic netlist file to open (Optional)
+
+ """
+ self.design = None
+ self.components = []
+ self.libparts = []
+ self.libraries = []
+ self.nets = []
+
+ # The entire tree is loaded into self.tree
+ self.tree = []
+
+ self._curr_element = None
+
+ if fname != "":
+ self.load(fname)
+
+ def addChars(self, content):
+ """Add characters to the current element"""
+ self._curr_element.addChars(content)
+
+ def addElement(self, name):
+ """Add a new kicad generic element to the list"""
+ if self._curr_element == None:
+ self.tree = netlistElement(name)
+ self._curr_element = self.tree
+ else:
+ self._curr_element = self._curr_element.addChild(
+ netlistElement(name, self._curr_element))
+
+ # If this element is a component, add it to the components list
+ if self._curr_element.name == "comp":
+ self.components.append(component(self._curr_element))
+
+ # Assign the design element
+ if self._curr_element.name == "design":
+ self.design = self._curr_element
+
+ # If this element is a library part, add it to the parts list
+ if self._curr_element.name == "libpart":
+ self.libparts.append(part(self._curr_element))
+
+ # If this element is a net, add it to the nets list
+ if self._curr_element.name = "net"
+ self.nets.append(self._curr_element)
+
+ # If this element is a library, add it to the libraries list
+ if self._curr_element.name = "library"
+ self.libraries.append(self._curr_element)
+
+ return self._curr_element
+
+ def endDocument(self):
+ """Called when the netlist document has been fully parsed"""
+ # When the document is complete, the library parts must be linked to
+ # the components as they are seperate in the tree so as not to
+ # duplicate library part information for every component
+ for c in self.components:
+ for p in self.libparts:
+ if p.getPart() == c.getPart() and p.getLib() == c.getLib():
+ c.setPart(p)
+
+ def endElement(self):
+ """End the current element and switch to its parent"""
+ self._curr_element = self._curr_element.getParent()
+
+ def getDate(self):
+ """Return the date + time string generated by the tree creation tool"""
+ return self.design.get("date")
+
+ def getSource(self):
+ """Return the source string for the design"""
+ return self.design.get("source")
+
+ def getTool(self):
+ """Return the tool string which was used to create the netlist tree"""
+ return self.design.get("tool")
+
+ def groupComponents(self):
+ """Return a list of component lists. Components are grouped together
+ when the value, library and part identifiers match
+
+ """
+ groups = []
+
+ # Make sure to start off will all components ungrouped to begin with
+ for c in self.components:
+ c.grouped = False
+
+ # Group components based on the value, library and part identifiers
+ for c in self.components:
+ if c.grouped == False:
+ c.grouped = True
+ newgroup = []
+ newgroup.append(c)
+
+ # Check every other ungrouped component against this component
+ # and add to the group as necessary
+ for ci in self.components:
+ if ci.grouped == False and ci == c:
+ newgroup.append(ci)
+ ci.grouped = True
+
+ # Add the new component group to the groups list
+ groups.append(newgroup)
+
+ # Each group is a list of components, we need to sort each list first
+ # to get them in order as this makes for easier to read BOM's
+ for g in groups:
+ g = sorted(g, key=lambda g: g.getRef())
+
+ # Finally, sort the groups to order the references alphabetically
+ groups = sorted(groups, key=lambda group: group[0].getRef())
+
+ return groups
+
+ def formatXML(self):
+ """Return the whole netlist formatted in XML"""
+ return self.tree.formatXML()
+
+ def formatHTML(self):
+ """Return the whole netlist formatted in HTML"""
+ return self.tree.formatHTML()
+
+ def load(self, fname):
+ """Load a kicad generic netlist
+
+ Keywords:
+ fname -- The name of the generic netlist file to open
+
+ """
+ try:
+ self._reader = sax.make_parser()
+ self._reader.setContentHandler(_gNetReader(self))
+ self._reader.parse(fname)
+ except IOError as e:
+ print >> sys.stderr, __file__, ":", e
+ sys.exit(-1)
+
+
+class part():
+ """Class for a library part"""
+ def __init__(self, part):
+ # The part is a reference to a libpart generic netlist element
+ self.element = part
+
+ def __str__(self):
+ # simply print the generic netlist element associated with this part
+ return str(self.element)
+
+ def getDatasheet(self):
+ return self.element.get("docs")
+
+ def getLib(self):
+ return self.element.get("libpart", "lib")
+
+ def getPart(self):
+ return self.element.get("libpart", "part")
+
+ def getDescription(self):
+ return self.element.get("description")
+
+ def getField(self, name):
+ return self.element.get("field", "name", name)
+
+
+class _gNetReader(sax.handler.ContentHandler):
+ """SAX kicad generic netlist content handler - passes most of the work back
+ to the gNetlist class which builds a complete tree in RAM for the design
+
+ """
+ def __init__(self, aParent):
+ self.parent = aParent
+
+ def startElement(self, name, attrs):
+ """Start of a new XML element event"""
+ element = self.parent.addElement(name)
+
+ for name in attrs.getNames():
+ element.addAttribute(name, attrs.getValue(name))
+
+ def endElement(self, name):
+ self.parent.endElement()
+
+ def characters(self, content):
+ # Ignore erroneous white space - ignoreableWhitespace does not get rid
+ # of the need for this!
+ if not content.isspace():
+ self.parent.addChars(content)
+
+ def endDocument(self):
+ """End of the XML document event"""
+ self.parent.endDocument()
diff --git a/scripts/bom-in-python/ky/round_robin.py b/scripts/bom-in-python/ky/round_robin.py
new file mode 100644
index 0000000000..9abfe41f7a
--- /dev/null
+++ b/scripts/bom-in-python/ky/round_robin.py
@@ -0,0 +1,23 @@
+#
+# Example python script to generate an equivalent XML document from XML input
+#
+# Example: Round robin, XML to XML conversion
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import sys
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+print >> f, net.formatXML()
diff --git a/scripts/bom-in-python/ky/round_value_robin.py b/scripts/bom-in-python/ky/round_value_robin.py
new file mode 100644
index 0000000000..6099441b6f
--- /dev/null
+++ b/scripts/bom-in-python/ky/round_value_robin.py
@@ -0,0 +1,71 @@
+#
+# Example python script to generate an equivalent XML document from XML input
+#
+# Example: Round value robin, XML to XML conversion with partial value monging
+#
+
+# Import the KiCad python helper module and the csv formatter
+import ky
+import sys
+
+def checkvalue(self):
+ """Check values, and replace with preferred/consistent values"""
+ ref = self.getRef()
+ r = ref.split("R")
+ c = ref.split("C")
+ v = self.getValue()
+
+ # Common to all values - convert decimation if necessary
+ dec = v.split(",")
+ if (len(dec) == 2):
+ newval = dec[0] + "." + dec[1]
+ self.setValue(newval)
+ v = self.getValue()
+
+ if len(r) == 2 and r[1].isdigit():
+ # This is a resistor - make values consistent
+ # If the value is a pure value, add R to the end of the value
+ if v.isdigit():
+ i = int(v)
+ if (i > 1000000):
+ i = i / 100000
+ v = str(i) + "M"
+ if (i > 1000):
+ i = i / 1000
+ v = str(i) + "K"
+ else:
+ v = str(i) + "R"
+
+ self.setValue(v)
+ else:
+ # Get the multiplier character
+ multiplier = v[len(v) - 1]
+ v = v.strip(multiplier)
+ v = v.split(".")
+ if (len(v) == 2):
+ newval = v[0] + multiplier + v[1]
+ self.setValue(newval)
+ v = self.getValue()
+
+
+
+# Give components a new method for checking the values (this could easily be a
+# Company Part Number generator method instead)
+ky.component.checkvalue = checkvalue
+
+# Generate an instance of a generic netlist, and load the netlist tree from
+# the command line option. If the file doesn't exist, execution will stop
+net = ky.netlist(sys.argv[1])
+
+# Open a file to write to, if the file cannot be opened output to stdout
+# instead
+try:
+ f = open(sys.argv[2], 'w')
+except IOError:
+ print >> sys.stderr, __file__, ":", e
+ f = stdout
+
+for c in net.components:
+ c.checkvalue()
+
+print >> f, net.formatXML()