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.
|
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
|
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")
|
Value ← Value1 (e.g. "10k", "4.7k", "100")
|
||||||
Description ← Description column
|
Description ← Description column
|
||||||
UMPN ← GLE P/N
|
UMPN ← GLE P/N (internal part number of first approved vendor)
|
||||||
MFG ← Mfg.1
|
MFG ← Mfg.1
|
||||||
MPN ← Mfg.1 P/N
|
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.
|
All geometry and pin definitions are copied verbatim from R_temp.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@@ -34,6 +42,24 @@ def kicad_str(value: str) -> str:
|
|||||||
return str(value).replace('\\', '\\\\').replace('"', '\\"')
|
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,
|
def make_symbol(name: str, value: str, description: str,
|
||||||
umpn: str, mfg: str, mpn: str,
|
umpn: str, mfg: str, mpn: str,
|
||||||
geometry_body: str) -> str:
|
geometry_body: str) -> str:
|
||||||
@@ -206,6 +232,7 @@ def main(xlsx_path: Path, sym_path: Path):
|
|||||||
# ---- Build new symbols ----
|
# ---- Build new symbols ----
|
||||||
new_symbols = []
|
new_symbols = []
|
||||||
skipped = []
|
skipped = []
|
||||||
|
seen_names: dict[str, str] = {} # sym_name → GLE P/N of first occurrence
|
||||||
|
|
||||||
for _, row in resistors.iterrows():
|
for _, row in resistors.iterrows():
|
||||||
gle_pn = str(row['GLE P/N']).strip()
|
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))
|
skipped.append(('(no GLE P/N)', value))
|
||||||
continue
|
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.
|
# Substitute R_temp → this symbol's name in the geometry block.
|
||||||
# Also re-indent so sub-symbol opening parens align with the template.
|
# 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') \
|
geom = raw_geom.replace('R_temp_0_1', f'{sym_name}_0_1') \
|
||||||
.replace('R_temp_1_1', f'{gle_pn}_1_1')
|
.replace('R_temp_1_1', f'{sym_name}_1_1')
|
||||||
# Each sub-symbol block starts at column 0 after extract; add two tabs.
|
# 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
|
geom = '\n'.join('\t\t' + line if line.startswith('(symbol ') else line
|
||||||
for line in geom.splitlines())
|
for line in geom.splitlines())
|
||||||
|
|
||||||
sym = make_symbol(
|
sym = make_symbol(
|
||||||
name=gle_pn,
|
name=sym_name,
|
||||||
value=value,
|
value=value,
|
||||||
description=description,
|
description=description,
|
||||||
umpn=gle_pn,
|
umpn=gle_pn,
|
||||||
@@ -237,7 +273,14 @@ def main(xlsx_path: Path, sym_path: Path):
|
|||||||
)
|
)
|
||||||
new_symbols.append(sym)
|
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) ----
|
# ---- Rebuild file from scratch (idempotent) ----
|
||||||
# Extract the library header lines (everything before the first symbol)
|
# Extract the library header lines (everything before the first symbol)
|
||||||
|
|||||||
Reference in New Issue
Block a user