From: Keith Packard Date: Tue, 11 Feb 2025 01:13:17 +0000 (-0800) Subject: bin: Add argument handling to fillparts programs X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=dba4cffde22332b0e93fd194a9c94bced20ac5b1;p=hw%2Faltusmetrum bin: Add argument handling to fillparts programs This creating output files inside the applications so that errors don't end up leaving output files lying around after make finishes. Signed-off-by: Keith Packard --- diff --git a/bin/fillpartscsv.py b/bin/fillpartscsv.py index 4f2d24f..675bb30 100755 --- a/bin/fillpartscsv.py +++ b/bin/fillpartscsv.py @@ -17,14 +17,31 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # -import parts; -import csv; -import sys; +import argparse +import parts +import sys def main(): - preferred = parts.Parts(ods='default') - my_parts = parts.Parts(csv_file=sys.stdin) + parser = argparse.ArgumentParser(); + parser.add_argument("input", help="CSV format input file") + parser.add_argument("-o", "--output", help="CSV format output file") + parser.add_argument("-p", "--preferred", help="Preferred parts database") + args = parser.parse_args() + + if args.preferred: + preferred_name = args.preferred + else: + preferred_name = 'default' + preferred = parts.Parts(ods=preferred_name) + if args.input: + with open(args.input) as input: + my_parts = parts.Parts(csv_file=input) + else: + my_parts = parts.Parts(csv_file=sys.stdin) my_parts.fill_values(preferred) - my_parts.export_csv_file(sys.stdout) + if args.output: + my_parts.export_csv(args.output) + else: + my_parts.export_csv_file(sys.stdout) main() diff --git a/bin/fillpartslist.py b/bin/fillpartslist.py index 00324db..afc5149 100755 --- a/bin/fillpartslist.py +++ b/bin/fillpartslist.py @@ -17,13 +17,31 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # -import parts; -import sys; +import argparse +import parts +import sys def main(): - preferred = parts.Parts(ods='default') - my_parts = parts.Parts(tab_file=sys.stdin) + parser = argparse.ArgumentParser(); + parser.add_argument("input", help="Tab-delimited input file") + parser.add_argument("-o", "--output", help="Tab-delimited output file") + parser.add_argument("-p", "--preferred", help="Preferred parts database") + args = parser.parse_args() + + if args.preferred: + preferred_name = args.preferred + else: + preferred_name = 'default' + preferred = parts.Parts(ods=preferred_name) + if args.input: + with open(args.input) as input: + my_parts = parts.Parts(tab_file=input) + else: + my_parts = parts.Parts(tab_file=sys.stdin) my_parts.fill_values(preferred) - my_parts.export_tab_file(sys.stdout) + if args.output: + my_parts.export_tab(args.output) + else: + my_parts.export_tab_file(sys.stdout) main() diff --git a/bin/parts.py b/bin/parts.py index aca296e..3b6321a 100644 --- a/bin/parts.py +++ b/bin/parts.py @@ -20,14 +20,14 @@ AltusMetrum collection of classes """ -import csv; -import tempfile; -import subprocess; +import csv +import tempfile +import subprocess import os import sys import functools -from pathlib import Path; -import re; +from pathlib import Path +import re # These attributes form the 'key' used to uniquely identify the part key_attrs = ('device', 'value', 'footprint') @@ -38,64 +38,6 @@ pref_order = ('device', 'value', 'footprint', 'loadstatus', 'provided', 'mfg', value_pattern=r'([0-9]+)(\.[0-9]*)?([kmMupng]?)(F|H|Hz)?' -def numeric_value(a): - m = re.fullmatch(value_pattern, a, flags=re.IGNORECASE) - if m: - n = m.group(1) - if m.group(2): - n += m.group(2) - number = float(n) - scale = m.group(3) - if scale == 'G': - number *= 1000000000 - elif scale == 'M': - number *= 1000000 - elif scale == 'k': - number *= 1000 - elif scale == 'm': - number /= 1000 - elif scale == 'u' or scale == 'µ': - number /= 1000000 - elif scale == 'p': - number /= 1000000000 - return number - return None - -def value_cmp(a, b): - na = numeric_value(a) - nb = numeric_value(b) - if na and nb: - if na < nb: - return -1 - if na > nb: - return 1 - return 0 - if na: - return -1 - if nb: - return 1 - if a < b: - return -1 - if b > a: - return 1 - return 0 - -def str_cmp(a,b): - if a < b: - return -1 - if a > b: - return 1 - return 0 - -def key_cmp(a, b): - c = str_cmp(a[0], b[0]) - if c: - return c - c = value_cmp(a[1], b[1]) - if c: - return c - return str_cmp(a[2], b[2]) - class Part(): """ A single part containing a dictionary with all of the attributes @@ -271,21 +213,58 @@ class Parts(): t = t + (i,) return t - # Export to a CSV file + # Compute a key value suitable for sorting + def cmp_key(self, k): + value = k[1] + m = re.fullmatch(value_pattern, value, flags=re.IGNORECASE) + if m: + number = m.group(1) + if m.group(2): + number += m.group(2) + n = float(number) + scale = m.group(3) + if scale == 'G': + n *= 1000000000 + elif scale == 'M': + n *= 1000000 + elif scale == 'k': + n *= 1000 + elif scale == 'm': + n /= 1000 + elif scale == 'u' or scale == 'µ': + n /= 1000000 + elif scale == 'p': + n /= 1000000000 + value = "" + else: + n = 0 + return (k[0], value, n, k[2]) + + # Export to a CSV file object def export_csv_file(self, outfile): csvwriter = csv.writer(outfile, dialect='excel-nl') attrs = self.attrs_tuple() csvwriter.writerow(attrs) - keys = sorted(list(self.parts), key=functools.cmp_to_key(key_cmp)) + keys = sorted(list(self.parts), key=self.cmp_key) for key in keys: part = self.get(key) csvwriter.writerow(tuple(map(part.get_unknown, attrs))) - # Export to a tab-delimited file + # Export to a CSV file + def export_csv(self, outname): + with open(outname, "w", newline='') as outfile: + self.export_csv_file(outfile) + + # Export to a tab-delimited file object def export_tab_file(self, outfile): attrs = self.attrs_tuple() print("\t".join(attrs), file=outfile) - keys = sorted(list(self.parts), key=functools.cmp_to_key(key_cmp)) + keys = sorted(list(self.parts), key=self.cmp_key) for key in keys: part = self.get(key) print("\t".join(tuple(map(part.get_unknown, attrs))), file=outfile) + + # Export to a tab-delimited file + def export_tab(self, outname): + with open(outname, "w") as outfile: + self.export_tab_file(outfile)