Use descriptive names for generated resistor symbols (R0402_4.7K_1%)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user