diff --git a/src/wireviz/wv_bom.py b/src/wireviz/wv_bom.py index 0328661..223de38 100644 --- a/src/wireviz/wv_bom.py +++ b/src/wireviz/wv_bom.py @@ -3,7 +3,7 @@ from collections import Counter from dataclasses import asdict -from typing import List, Tuple, Union +from typing import Any, List, Tuple, Union from wireviz.DataClasses import AdditionalComponent, Connector, Cable from wireviz.wv_gv_html import html_line_breaks @@ -106,8 +106,7 @@ def generate_bom(harness): group_entries = [v for v in bom_entries if bom_types_group(v) == group] designators = [] for group_entry in group_entries: - d = group_entry.get('designators') - designators.extend(d if isinstance(d, List) else [d] if d else []) + designators.extend(make_list(group_entry.get('designators'))) total_qty = sum(entry['qty'] for entry in group_entries) bom.append({**group_entries[0], 'qty': round(total_qty, 3), 'designators': sorted(set(designators))}) @@ -129,19 +128,13 @@ def bom_list(bom): for fieldname in ['pn', 'manufacturer', 'mpn']: # these optional BOM columns will only be included if at least one BOM item actually uses them if any(entry.get(fieldname) for entry in bom): keys.append(fieldname) - bom_list = [] # list of staic bom header names, headers not specified here are generated by capitilising the internal name bom_headings = { "pn": "P/N", "mpn": "MPN" } - bom_list.append([bom_headings.get(k, k.capitalize()) for k in keys]) # create header row with keys - for item in bom: - item_list = [item.get(key, '') for key in keys] # fill missing values with blanks - item_list = [', '.join(subitem) if isinstance(subitem, List) else subitem for subitem in item_list] # convert any lists into comma separated strings - item_list = ['' if subitem is None else subitem for subitem in item_list] # if a field is missing for some (but not all) BOM items - bom_list.append(item_list) - return bom_list + return ([[bom_headings.get(k, k.capitalize()) for k in keys]] + # Create header row with key names + [[make_str(entry.get(k)) for k in keys] for entry in bom]) # Create string list for each entry row def component_table_entry(type, qty, unit=None, pn=None, manufacturer=None, mpn=None): output = f'{qty}' @@ -174,3 +167,11 @@ def manufacturer_info_field(manufacturer, mpn): # Return the value indexed if it is a list, or simply the value otherwise. def index_if_list(value, index): return value[index] if isinstance(value, list) else value + +def make_list(value: Any) -> list: + """Return value if a list, empty list if None, or single element list otherwise.""" + return value if isinstance(value, list) else [] if value is None else [value] + +def make_str(value: Any) -> str: + """Return comma separated elements if a list, empty string if None, or value as a string otherwise.""" + return ', '.join(str(element) for element in make_list(value))