From 1ec9ca4f81c32b6f7c4381cb3019c6d4dfaceae3 Mon Sep 17 00:00:00 2001 From: Tyler Ward Date: Wed, 1 Jul 2020 23:17:20 +0100 Subject: [PATCH] Improved part number support Added internal part number and manufacturer fields Added support for wire part numbers in a bundle Moved part number information to seperate row in table --- src/wireviz/wireviz.py | 113 ++++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/src/wireviz/wireviz.py b/src/wireviz/wireviz.py index 3317c00..be62636 100755 --- a/src/wireviz/wireviz.py +++ b/src/wireviz/wireviz.py @@ -89,8 +89,12 @@ class Harness: colorbar=''.format(wv_colors.translate_color(n.color, 'HEX')) if n.color else '')) else: # not a ferrule + # id = identification + id = [n.manufacturer, + 'MPN:{}'.format(n.manufacturer_part_number) if n.manufacturer_part_number else '', + 'IPN:{}'.format(n.internal_part_number) if n.internal_part_number else ''] # a = attributes - a = [n.part_number, n.type, + a = [n.type, n.subtype, '{}-pin'.format(n.pincount) if n.show_pincount else ''] # p = pinout @@ -104,7 +108,7 @@ class Harness: if n.ports_right: p[2].append('{portno}'.format(portno=pinnumber)) # l = label - l = [n.name if n.show_name else '', a, p, n.notes] + l = [n.name if n.show_name else '', id, a, p, n.notes] dot.node(k, label=nested(l)) if len(n.loops) > 0: @@ -122,9 +126,13 @@ class Harness: '{name}:p{port_to}{loop_side}:{loop_dir}'.format(name=n.name, port_from=loop[0], port_to=loop[1], loop_side=loop_side, loop_dir=loop_dir)) for k, c in self.cables.items(): + # id = identification + id = [c.manufacturer if not isinstance(c.manufacturer, list) else '', + 'MPN:{}'.format(c.manufacturer_part_number) if (c.manufacturer_part_number and not isinstance(c.manufacturer_part_number, list)) else '', + 'IPN:{}'.format(c.internal_part_number) if (c.internal_part_number and not isinstance(c.internal_part_number, list)) else ''] + id = list(filter(None, id)) # a = attributes - a = [c.part_number, - '{}x'.format(len(c.colors)) if c.show_wirecount else '', + a = ['{}x'.format(len(c.colors)) if c.show_wirecount else '', '{} {}{}'.format(c.gauge, c.gauge_unit, ' ({} AWG)'.format(awg_equiv(c.gauge)) if c.gauge_unit == 'mm\u00B2' and c.show_equiv else '') if c.gauge else '', # TODO: show equiv '+ S' if c.shield else '', '{} m'.format(c.length) if c.length > 0 else ''] @@ -135,6 +143,11 @@ class Harness: html = html + '' # name+attributes table if c.show_name: html = html + ''.format(colspan=len(a), name=c.name) + if(len(id) > 0): # print an identification row if values specified + html = html + '' # end identification row html = html + '' # attribute row for attrib in a: html = html + ''.format(attrib=attrib) @@ -156,6 +169,21 @@ class Harness: html = html + '' bgcolor = wv_colors.translate_color(x, 'hex') html = html + ''.format(colspan=len(p), bgcolor=bgcolor if bgcolor != '' else '#ffffff', port='w{}'.format(i)) + if(c.category == 'bundle'): # for bundles individual wires can have part information + # create a list of wire parameters + wireid = [] + if isinstance(c.manufacturer, list): + wireid.append(c.manufacturer[i - 1]) + if isinstance(c.manufacturer_part_number, list): + wireid.append('MPN:{}'.format(c.manufacturer_part_number[i - 1])) + if isinstance(c.internal_part_number, list): + wireid.append('IPN:{}'.format(c.internal_part_number[i - 1])) + # print parameters into a table row under the wire + if(len(wireid) > 0): + html = html + '' if c.shield: p = ['', 'Shield', ''] @@ -248,39 +276,53 @@ class Harness: bom_connectors = [] bom_cables = [] # connectors - types = Counter([(v.type, v.subtype, v.pincount) for v in self.connectors.values()]) + types = Counter([(v.type, v.subtype, v.pincount, v.manufacturer, v.manufacturer_part_number, v.internal_part_number) for v in self.connectors.values()]) for type in types: - items = {k: v for k, v in self.connectors.items() if (v.type, v.subtype, v.pincount) == type} + items = {k: v for k, v in self.connectors.items() if (v.type, v.subtype, v.pincount, v.manufacturer, v.manufacturer_part_number, v.internal_part_number) == type} shared = next(iter(items.values())) designators = list(items.keys()) designators.sort() - part_number = shared.part_number name = 'Connector{type}{subtype}{pincount}{color}'.format(type = ', {}'.format(shared.type) if shared.type else '', subtype = ', {}'.format(shared.subtype) if shared.subtype else '', pincount = ', {} pins'.format(shared.pincount) if shared.category != 'ferrule' else '', color = ', {}'.format(shared.color) if shared.color else '') item = {'item': name, 'qty': len(designators), 'unit': '', 'designators': designators if shared.category != 'ferrule' else ''} - if part_number is not None: # set part number only if it exists - item['part number'] = part_number + if shared.manufacturer is not None: # set manufacturer only if it exists + item['manufacturer'] = shared.manufacturer + if shared.manufacturer_part_number is not None: # set part number only if it exists + item['manufacturer part number'] = shared.manufacturer_part_number + if shared.internal_part_number is not None: # set part number only if it exists + item['internal part number'] = shared.internal_part_number bom_connectors.append(item) bom_connectors = sorted(bom_connectors, key=lambda k: k['item']) # https://stackoverflow.com/a/73050 bom.extend(bom_connectors) # cables - types = Counter([(v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield) for v in self.cables.values()]) + types = Counter([(v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield, + v.manufacturer if not isinstance(v.manufacturer, list) else None, + v.manufacturer_part_number if not isinstance(v.manufacturer_part_number, list) else None, + v.internal_part_number if not isinstance(v.manufacturer_part_number, list) else None + ) for v in self.cables.values()]) for type in types: - items = {k: v for k, v in self.cables.items() if (v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield) == type} + items = {k: v for k, v in self.cables.items() if (v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield, + v.manufacturer if not isinstance(v.manufacturer, list) else None, + v.manufacturer_part_number if not isinstance(v.manufacturer_part_number, list) else None, + v.internal_part_number if not isinstance(v.manufacturer_part_number, list) else None + ) == type} shared = next(iter(items.values())) if shared.category != 'bundle': designators = list(items.keys()) designators.sort() - part_number = shared.part_number total_length = sum(i.length for i in items.values()) name = 'Cable, {wirecount}{gauge}{shield}'.format(wirecount = shared.wirecount, gauge = ' x {} {}'.format(shared.gauge, shared.gauge_unit) if shared.gauge else ' wires', shield = ' shielded' if shared.shield else '') item = {'item': name, 'qty': round(total_length, 3), 'unit': 'm', 'designators': designators} - if part_number is not None: # set part number only if it exists - item['part number'] = part_number + if shared.manufacturer is not None: # set manufacturer only if it exists + item['manufacturer'] = shared.manufacturer + if shared.manufacturer_part_number is not None: # set part number only if it exists + item['manufacturer part number'] = shared.manufacturer_part_number + if shared.internal_part_number is not None: # set part number only if it exists + item['internal part number'] = shared.internal_part_number bom_cables.append(item) # bundles (ignores wirecount) wirelist = [] @@ -293,12 +335,16 @@ class Harness: if shared.category == 'bundle': for bundle in items.values(): # add each wire from each bundle to the wirelist - for color in bundle.colors: - wirelist.append({'gauge': shared.gauge, 'gauge_unit': shared.gauge_unit, 'length': shared.length, 'color': color, 'designator': bundle.name}) + for index, color in enumerate(bundle.colors, 0): + wireinfo = {'gauge': shared.gauge, 'gauge_unit': shared.gauge_unit, 'length': shared.length, 'color': color, 'designator': bundle.name} + wireinfo['manufacturer'] = bundle.manufacturer[index] if isinstance(bundle.manufacturer, list) else None + wireinfo['manufacturer part number'] = bundle.manufacturer_part_number[index] if isinstance(bundle.manufacturer_part_number, list) else None + wireinfo['internal part number'] = bundle.internal_part_number[index] if isinstance(bundle.internal_part_number, list) else None + wirelist.append(wireinfo) # join similar wires from all the bundles to a single BOM item - types = Counter([(v['gauge'], v['gauge_unit'], v['color']) for v in wirelist]) + types = Counter([(v['gauge'], v['gauge_unit'], v['color'], v['manufacturer'], v['manufacturer part number'], v['internal part number']) for v in wirelist]) for type in types: - items = [v for v in wirelist if (v['gauge'], v['gauge_unit'], v['color']) == type] + items = [v for v in wirelist if (v['gauge'], v['gauge_unit'], v['color'], v['manufacturer'], v['manufacturer part number'], v['internal part number']) == type] shared = items[0] designators = [i['designator'] for i in items] # remove duplicates @@ -308,6 +354,12 @@ class Harness: name = 'Wire{gauge}{color}'.format(gauge=', {} {}'.format(shared['gauge'], shared['gauge_unit']) if shared['gauge'] else '', color=', {}'.format(shared['color']) if shared['color'] != '' else '') item = {'item': name, 'qty': round(total_length, 3), 'unit': 'm', 'designators': designators} + if shared['manufacturer'] is not None: # set manufacturer only if it exists + item['manufacturer'] = shared['manufacturer'] + if shared['manufacturer part number'] is not None: # set part number only if it exists + item['manufacturer part number'] = shared['manufacturer part number'] + if shared['internal part number'] is not None: # set part number only if it exists + item['internal part number'] = shared['internal part number'] bom_cables.append(item) bom_cables = sorted(bom_cables, key=lambda k: k['item']) # https://stackoverflow.com/a/73050 bom.extend(bom_cables) @@ -316,9 +368,10 @@ class Harness: def bom_list(self): bom = self.bom() keys = ['item', 'qty', 'unit', 'designators'] - # check if any part numbers are set - if any("part number" in x for x in bom): - keys.append("part number") + # check if any optional fields are set and add to keys if they are + for fieldname in ["manufacturer", "manufacturer part number", "internal part number"]: + if any(fieldname in x for x in bom): + keys.append(fieldname) bom_list = [] bom_list.append([k.capitalize() for k in keys]) # create header row with keys for item in bom: @@ -332,7 +385,9 @@ class Harness: @dataclass class Connector: name: str - part_number: str = None + manufacturer: str = None + manufacturer_part_number: str = None + internal_part_number: str = None category: str = None type: str = None subtype: str = None @@ -383,7 +438,9 @@ class Connector: @dataclass class Cable: name: str - part_number: str = None + manufacturer: str = None + manufacturer_part_number: str = None + internal_part_number: str = None category : str = None type: str = None gauge: float = None @@ -437,6 +494,16 @@ class Cable: raise Exception('Unknown number of wires. Must specify wirecount or colors (implicit length)') self.wirecount = len(self.colors) + # if lists of part numbers are provided check this is a bundle and that it matches the wirecount. + for idfield in [self.manufacturer, self.manufacturer_part_number, self.internal_part_number]: + if isinstance(idfield, list): + if self.category == "bundle": + # check the length + if len(idfield) != self.wirecount: + raise Exception('lists of part data must match wirecount') + else: + raise Exception('lists of part data are only supported for bundles') + # for BOM generation self.wirecount_and_shield = (self.wirecount, self.shield)
{name}
'.format(colspan=len(a)) + for attrib in id: + html = html + ''.format(attrib=attrib) + html = html + '
{attrib}
{attrib}
'.format(colspan=len(a)) + for attrib in wireid: + html = html + ''.format(attrib=attrib) + html = html + '
{attrib}