]> git.gag.com Git - hw/altusmetrum/commitdiff
Make tab and csv part import 'the same'.
authorKeith Packard <keithp@keithp.com>
Sun, 22 Jun 2025 21:37:30 +0000 (14:37 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 22 Jun 2025 21:42:09 +0000 (14:42 -0700)
.tab files have one line per refdes, .csv files have one line per component.
When importing a .tab file, merge matching components by sorting-in
another refdes. When importing a .csv file, sort the refdes
numerically.

When dumping a .tab file, iterate over the refdes and emit duplicate lines.

Signed-off-by: Keith Packard <keithp@keithp.com>
bin/parts.py

index 5d3ce8c134dc86e4373dd88a3f930b6b1cfff52a..d7402a2d081b0f8fa23caa3e2a725d2ef3e6a9e4 100644 (file)
@@ -34,14 +34,21 @@ key_attrs = ('device', 'value', 'footprint')
 
 # This is the preferred order when writing a CSV file
 pref_order_csv = ('device', 'value', 'footprint', 'loadstatus', 'provided', 'mfg',
-              'mfg_part_number', 'vendor', 'vendor_part_number', 'quantity', 'refdes')
+                  'mfg_part_number', 'vendor', 'vendor_part_number', 'quantity', 'refdes', 'pnpformat')
 
 pref_order_tab = ('refdes', 'device', 'value', 'footprint', 'loadstatus', 'provided', 'mfg',
-              'mfg_part_number', 'vendor', 'vendor_part_number', 'quantity')
+                  'mfg_part_number', 'vendor', 'vendor_part_number', 'quantity', 'pnpformat')
 
 value_pattern=r'([0-9]+)(\.[0-9]*)?([kmMupng]?)(F|H|Hz|V|screws)?([ _][0-9]+(\.[0-9]*))?'
 refdes_pattern=r'([a-zA-Z]+)([0-9]+)'
 
+def refdes_number(refdes):
+    mr = re.fullmatch(refdes_pattern, refdes)
+    if mr:
+        return int(mr.group(2)) + ord(mr.group(1))
+    raise ValueError('Invalid refdes %s' % (refdes,))
+
+
 class Part():
     """
     A single part containing a dictionary with all of the attributes
@@ -58,6 +65,14 @@ class Part():
             for i in range(len(values)):
                 if values[i]:
                     self.attrs[keys[i]] = values[i]
+            if not self.get('quantity'):
+                self.set('quantity', '1')
+            refdes = self.get_refdes()
+            if refdes:
+                self.set('refdes', " ".join(sorted(refdes, key=refdes_number)))
+
+    def __str__(self):
+        return self.attrs.__str__()
 
     # Get an attribute value, returning None for
     # missing attributes
@@ -66,6 +81,28 @@ class Part():
             return self.attrs[attr]
         return None
 
+    # Get the list of refdes for a part
+    def get_refdes(self):
+        refdes = self.get('refdes')
+        if not refdes:
+            return ()
+        return refdes.split()
+
+    # Add a refdes to a part. Refdes is a space-separated string
+    def add_refdes(self, refdes):
+        if not refdes:
+            return
+        my_refdes = self.get('refdes')
+        quantity = self.get('quantity')
+        if quantity:
+            quantity = str(int(quantity) + 1)
+        else:
+            quantity = str(1)
+        if my_refdes:
+            refdes = my_refdes + " " + refdes
+        self.set('refdes', " ".join(sorted(refdes.split(), key=refdes_number)))
+        self.set('quantity', quantity)
+            
     # Get an attribute value in lower case
     def get_lower(self, attr):
         if attr in self.attrs:
@@ -157,7 +194,10 @@ class Parts():
     # Add/replace a part, computing the key
     def set(self, part):
         key = part.key()
-        self.parts[key] = part
+        if key in self.parts:
+            self.parts[key].add_refdes(part.get('refdes'))
+        else:
+            self.parts[key] = part
 
     # Import from a CSV file object
     def import_csv_file(self, infile):
@@ -273,7 +313,10 @@ class Parts():
         refdes = 'unknown'
         if part is not None:
             refdes = part.get_unknown('refdes')
-
+        try:
+            refdes = refdes[0]
+        except:
+            pass
         mr = re.fullmatch(refdes_pattern, refdes)
         if mr:
             category = mr.group(1)
@@ -329,7 +372,11 @@ class Parts():
         keys = sorted(list(self.parts), key=self.cmp_tab_key)
         for key in keys:
             part = self.get(key)
-            print("\t".join(tuple(map(part.get_unknown, attrs))), file=outfile)
+            orig_refdes = part.get('refdes')
+            for refdes in part.get_refdes():
+                part.set('refdes', refdes)
+                print("\t".join(tuple(map(part.get_unknown, attrs))), file=outfile)
+            part.set('refdes', orig_refdes)
 
     # Export to a tab-delimited file
     def export_tab(self, outname):