From 278b2db158088e35a94456f9fb98307de95e2978 Mon Sep 17 00:00:00 2001 From: Brent Perteet Date: Fri, 20 Feb 2026 15:40:44 +0000 Subject: [PATCH] Use descriptive names for generated resistor symbols (R0402_4.7K_1%) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symbols are now named by value+tolerance instead of internal GLE P/N, e.g. R0402_4.7K_1%, R0402_100_5%, R0402_10.0K_0.1%. - Add make_symbol_name() to normalise value suffix (k→K) and extract tolerance via regex from the Description column - Deduplicate by sym_name: where two GLE P/Ns share the same value+tolerance (alternate approved vendors), keep the first row and report the 10 skipped duplicates at runtime - UMPN field still carries the GLE P/N of the primary vendor Co-Authored-By: Claude Sonnet 4.6 --- scripts/gen_resistors_0402.py | 55 +++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/scripts/gen_resistors_0402.py b/scripts/gen_resistors_0402.py index 5e07a37..aa3a1f1 100644 --- a/scripts/gen_resistors_0402.py +++ b/scripts/gen_resistors_0402.py @@ -6,13 +6,21 @@ Reads the approved parts list spreadsheet and generates KiCad 9 symbols for every 0402 resistor into kicad-lib/symbols/Res_0402.kicad_sym. The existing R_temp template symbol is kept in the file. One new symbol -is added per row, named by the internal part number (GLE P/N), with: +is added per unique value+tolerance combination, named descriptively, e.g.: + R0402_4.7K_1% + R0402_100_5% + R0402_10.0K_0.1% + +Symbol fields: Value ← Value1 (e.g. "10k", "4.7k", "100") Description ← Description column - UMPN ← GLE P/N + UMPN ← GLE P/N (internal part number of first approved vendor) MFG ← Mfg.1 MPN ← Mfg.1 P/N +Where multiple approved vendors share the same value+tolerance, only the +first row is used (the duplicate rows are reported and skipped). + All geometry and pin definitions are copied verbatim from R_temp. Usage: @@ -34,6 +42,24 @@ def kicad_str(value: str) -> str: return str(value).replace('\\', '\\\\').replace('"', '\\"') +def make_symbol_name(value: str, description: str) -> str: + """ + Build a descriptive KiCad symbol name, e.g. 'R0402_4.7K_1%'. + + value – the Value1 column (e.g. '4.7k', '100', '10.0k') + description – the Description column (e.g. 'Resistor, 0402, 1%, 4.7k') + + The value suffix (k, m, g) is uppercased. Tolerance is extracted + with a regex that matches patterns like '1%', '0.1%', '5%'. + """ + # Uppercase trailing unit letter(s): 4.7k → 4.7K, 10.0k → 10.0K + value_norm = re.sub(r'([a-zA-Z]+)$', lambda m: m.group(1).upper(), value.strip()) + # Extract tolerance from description + tol_match = re.search(r'(\d+(?:\.\d+)?%)', description) + tolerance = tol_match.group(1) if tol_match else 'X' + return f'R0402_{value_norm}_{tolerance}' + + def make_symbol(name: str, value: str, description: str, umpn: str, mfg: str, mpn: str, geometry_body: str) -> str: @@ -206,6 +232,7 @@ def main(xlsx_path: Path, sym_path: Path): # ---- Build new symbols ---- new_symbols = [] skipped = [] + seen_names: dict[str, str] = {} # sym_name → GLE P/N of first occurrence for _, row in resistors.iterrows(): gle_pn = str(row['GLE P/N']).strip() @@ -218,16 +245,25 @@ def main(xlsx_path: Path, sym_path: Path): skipped.append(('(no GLE P/N)', value)) continue + # Build descriptive symbol name, e.g. "R0402_4.7K_1%" + sym_name = make_symbol_name(value, description) + + # Skip duplicate value+tolerance combinations (alternate approved vendors) + if sym_name in seen_names: + skipped.append((sym_name, f'dup of GLE {seen_names[sym_name]} (this: {gle_pn})')) + continue + seen_names[sym_name] = gle_pn + # Substitute R_temp → this symbol's name in the geometry block. # Also re-indent so sub-symbol opening parens align with the template. - geom = raw_geom.replace('R_temp_0_1', f'{gle_pn}_0_1') \ - .replace('R_temp_1_1', f'{gle_pn}_1_1') + geom = raw_geom.replace('R_temp_0_1', f'{sym_name}_0_1') \ + .replace('R_temp_1_1', f'{sym_name}_1_1') # Each sub-symbol block starts at column 0 after extract; add two tabs. geom = '\n'.join('\t\t' + line if line.startswith('(symbol ') else line for line in geom.splitlines()) sym = make_symbol( - name=gle_pn, + name=sym_name, value=value, description=description, umpn=gle_pn, @@ -237,7 +273,14 @@ def main(xlsx_path: Path, sym_path: Path): ) new_symbols.append(sym) - print(f"Generated {len(new_symbols)} symbols ({len(skipped)} skipped)") + dups = [(n, r) for n, r in skipped if n != '(no GLE P/N)'] + no_pn = [(n, r) for n, r in skipped if n == '(no GLE P/N)'] + print(f"Generated {len(new_symbols)} symbols " + f"({len(dups)} duplicate value/tol skipped, {len(no_pn)} missing GLE P/N)") + if dups: + print(" Skipped duplicates:") + for name, reason in dups: + print(f" {name}: {reason}") # ---- Rebuild file from scratch (idempotent) ---- # Extract the library header lines (everything before the first symbol)