diff --git a/README.md b/README.md
index e973b63..b445ae2 100644
--- a/README.md
+++ b/README.md
@@ -100,10 +100,11 @@ $ wireviz ~/path/to/file/mywire.yml
This will output the following files
```
-mywire.gv GraphViz output
+mywire.gv Raw GraphViz DOT file output of wiring diagram
mywire.svg Wiring diagram as vector image
mywire.png Wiring diagram as raster image
mywire.bom.tsv BOM (bill of materials) as tab-separated text file
+mywire.bom.csv BOM (bill of materials) as comma-separated, excel-format text file
mywire.html HTML page with wiring diagram and BOM embedded
```
diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py
index a3aa0ce..c2ce5de 100644
--- a/src/wireviz/Harness.py
+++ b/src/wireviz/Harness.py
@@ -3,9 +3,9 @@
from wireviz.DataClasses import Connector, Cable
from graphviz import Graph
-from wireviz import wv_colors, wv_helper
+from wireviz import wv_colors, wv_helper, bom_helper
from wireviz.wv_colors import get_color_hex
-from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, \
+from wireviz.wv_helper import awg_equiv, mm2_equiv, \
nested_html_table, flatten2d, index_if_list, html_line_breaks, \
graphviz_line_breaks, remove_line_breaks, open_file_read, open_file_write
from collections import Counter
@@ -67,7 +67,7 @@ class Harness:
font = 'arial'
dot.attr('graph', rankdir='LR',
ranksep='2',
- bgcolor='white',
+ bgcolor=wv_colors.COLOR_BACKGROUND,
nodesep='0.33',
fontname=font)
dot.attr('node', shape='record',
@@ -297,12 +297,12 @@ class Harness:
graph.save(filename=f'{filename}.gv')
# bom output
bom_list = self.bom_list()
- with open_file_write(f'{filename}.bom.tsv') as file:
- file.write(tuplelist2tsv(bom_list))
+ # todo: support user choices of BOM format (probably also graphviz outputs, html outputs)
+ bom_helper.generate_bom_outputs(filename,bom_list, [bom_helper.WIREVIZ_TSV, bom_helper.EXCEL_CSV])
# HTML output
with open_file_write(f'{filename}.html') as file:
file.write('\n')
- file.write('
')
+ file.write(f'')
file.write('Diagram
')
with open_file_read(f'{filename}.svg') as svg:
diff --git a/src/wireviz/bom_helper.py b/src/wireviz/bom_helper.py
new file mode 100644
index 0000000..218b413
--- /dev/null
+++ b/src/wireviz/bom_helper.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import csv
+from wireviz import wv_helper
+from wireviz.wv_helper import open_file_write
+
+EXCEL_CSV = csv.excel
+EXCEL_TSV = csv.excel_tab
+UNIX_CSV = csv.unix_dialect
+WIREVIZ_TSV = type('Wireviz BOM', (csv.Dialect, object), dict(
+ delimiter='\t',
+ doublequote=True,
+ escapechar=None,
+ lineterminator='\n',
+ quoting=0,
+ skipinitialspace=False,
+ strict=False,
+ quotechar='"'
+))
+csv.register_dialect('Wireviz BOM', WIREVIZ_TSV)
+
+_csv_formats = { EXCEL_CSV, UNIX_CSV }
+_tsv_formats = { EXCEL_TSV, WIREVIZ_TSV }
+
+_csv_ext = '.bom.csv'
+_tsv_ext = '.bom.tsv'
+
+def generate_bom_outputs(base_filename, bomdata, formats=None):
+ if formats is None:
+ formats = [EXCEL_CSV, WIREVIZ_TSV]
+ elif isinstance(formats, csv.Dialect):
+ formats = [formats]
+ elif not isinstance(formats, list):
+ raise TypeError
+ expanded_csv_names = len(_csv_formats.intersection(set(formats))) > 1
+ expanded_tsv_names = len(_tsv_formats.intersection(set(formats))) > 1
+
+ for fmt in formats:
+ if fmt in _csv_formats:
+ file = csv.writer(open_file_write(base_filename + ("_" + fmt.__name__ if expanded_csv_names else "") + _csv_ext, fmt.lineterminator), fmt)
+
+ elif fmt in _tsv_formats:
+ file = csv.writer(open_file_write(base_filename + ("_"+fmt.__name__ if expanded_tsv_names else "") + _tsv_ext, fmt.lineterminator), fmt)
+ else:
+ raise KeyError("Unknown BOM Format Specified")
+ file.writerows(wv_helper.flatten2d(bomdata))
+
+# TODO: Possibly refactor other BOM output operations, such as HTML, into here?
\ No newline at end of file
diff --git a/src/wireviz/build_examples.py b/src/wireviz/build_examples.py
index ee59ded..9238e7d 100755
--- a/src/wireviz/build_examples.py
+++ b/src/wireviz/build_examples.py
@@ -74,10 +74,11 @@ def build_tutorials():
file.write(f'\n\n')
- file.write(f'[Bill of Materials](tutorial{outfile_name}.bom.tsv)\n\n\n')
+ file.write(f'[Bill of Materials - TSV](tutorial{outfile_name}.bom.tsv)\n\n')
+ file.write(f'[Bill of Materials - CSV](tutorial{outfile_name}.bom.csv)\n\n\n')
def clean_examples():
- generated_extensions = ['.gv', '.png', '.svg', '.html', '.bom.tsv']
+ generated_extensions = ['.gv', '.png', '.svg', '.html', '.bom.tsv', '.bom.csv']
for filepath in [examples_path, demos_path, tutorials_path]:
print(filepath)
diff --git a/src/wireviz/wv_colors.py b/src/wireviz/wv_colors.py
index 4157543..c34e7fe 100644
--- a/src/wireviz/wv_colors.py
+++ b/src/wireviz/wv_colors.py
@@ -98,12 +98,13 @@ _color_ger = {
}
-color_default = '#ffffff'
+COLOR_DEFAULT = '#ffffff'
+COLOR_BACKGROUND = '#ffffff'
def get_color_hex(input, pad=False):
if input is None or input == '':
- return [color_default]
+ return [COLOR_DEFAULT]
if len(input) == 4: # give wires with EXACTLY 2 colors that striped/banded look
input = input + input[:2]
# hacky style fix: give single color wires a triple-up so that wires are the same size
@@ -113,7 +114,7 @@ def get_color_hex(input, pad=False):
output = [_color_hex[input[i:i + 2]] for i in range(0, len(input), 2)]
except KeyError:
print("Unknown color specified")
- output = [color_default]
+ output = [COLOR_DEFAULT]
return output
diff --git a/src/wireviz/wv_helper.py b/src/wireviz/wv_helper.py
index 024c3ef..703eb8c 100644
--- a/src/wireviz/wv_helper.py
+++ b/src/wireviz/wv_helper.py
@@ -113,8 +113,7 @@ def remove_line_breaks(inp):
return inp.replace('\n', ' ').rstrip() if isinstance(inp, str) else inp
def open_file_read(filename):
- # TODO: Intelligently determine encoding
return open(filename, 'r', encoding='UTF-8')
-def open_file_write(filename):
- return open(filename, 'w', encoding='UTF-8')
\ No newline at end of file
+def open_file_write(filename, newline='\n'):
+ return open(filename, 'w', encoding='UTF-8', newline=newline)