Skip to content

Commit bf3ff18

Browse files
-- Added prettytable module dependency to:
-- `solid.utils.bill_of_materials()` now returns a justified table using prettytable
1 parent 0ff2431 commit bf3ff18

File tree

5 files changed

+66
-64
lines changed

5 files changed

+66
-64
lines changed

Diff for: TODO_SolidPython.txt

+6-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131
}
3232
}
3333
}
34-
-- Once you've declared something a hole(), you *can't put anything in
35-
it*. This kind of defeats the purpose of most holes in mechanical design.
36-
This feature may need some rethinking.
37-
-- bill_of_materials() entries should be left-justified in their columns.
3834

3935
-- Applescript or other inter-app communication that will recompile in OpenSCAD
4036
whenever requested via your Python code
@@ -77,4 +73,10 @@ Completed:
7773
-- Add to PyPI so SolidPython can be installed with pip install solidpython
7874
-- Update README with PyEuclid information and PyPI-aware install info
7975
-- Comprehensive docs
76+
-- Once you've declared something a hole(), you *can't put anything in
77+
it*. This kind of defeats the purpose of most holes in mechanical design.
78+
This feature may need some rethinking. (Resolved via the part() class)
79+
-- bill_of_materials() entries should be left-justified in their columns. (BOM
80+
now created via prettytable module)
81+
8082

Diff for: setup.cfg

+3
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
source-dir = Doc
33
build-dir = Doc/_build
44
all_files = 1
5+
6+
[metadata]
7+
description-file = README.rst

Diff for: setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
"Topic :: Scientific/Engineering :: Mathematics",
2222
],
2323
packages=find_packages(),
24-
install_requires=['euclid3', 'PyPNG'],
24+
install_requires=['euclid3', 'PyPNG', 'prettytable'],
2525
)

Diff for: solid/examples/bom_scad.py

+5
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,9 @@ def assemble():
114114
print("%(__file__)s: SCAD file written to: \n%(file_out)s" % vars())
115115
print(bom)
116116

117+
print("Or, Spreadsheet-ready TSV:\n\n")
118+
bom = bill_of_materials(csv=True)
119+
print(bom)
120+
121+
117122
scad_render_to_file(a, file_out)

Diff for: solid/utils.py

+51-59
Original file line numberDiff line numberDiff line change
@@ -543,85 +543,77 @@ def wrapped_f(*wargs):
543543

544544
return wrap
545545

546-
547546
def bill_of_materials(csv=False):
548-
res = ''
549-
res += "%8s\t%8s\t%8s\t%8s" % ("Desc.", "Count", "Unit Price", "Total Price")
550-
for x in g_bom_headers:
551-
res += '\t' + x
552-
res += '\n'
553-
547+
field_names = ["Description", "Count", "Unit Price", "Total Price"]
548+
field_names += g_bom_headers
549+
550+
rows = []
551+
554552
all_costs = {}
555553
for desc, elements in g_parts_dict.items():
556554
count = elements['Count']
557555
currency = elements['currency']
558-
if not csv:
559-
currency += ' '
560556
price = elements['Unit Price']
561557

562558
if count > 0:
563559
if price:
564560
total = price * count
565-
try:
566-
all_costs[currency] += total
567-
except:
568-
all_costs[currency] = total
569-
570-
res += ("%8s\t%8d\t%s%8f\t%s%8.2f"
571-
% (desc, count, currency, price, currency, total))
561+
if currency not in all_costs:
562+
all_costs[currency] = 0
563+
564+
all_costs[currency] += total
565+
unit_price = _currency_str(price, currency)
566+
total_price = _currency_str(total, currency)
572567
else:
573-
res += "%8s\t%8d\t\t" % (desc, count)
568+
unit_price = total_price = ""
569+
row = [desc, count, unit_price, total_price]
574570

575571
for key in g_bom_headers:
576572
value = elements[key]
577-
# String formatting just converts everything via str() anyways.
578-
res += "\t%s" % value
579-
580-
res += '\n'
573+
row.append(value)
574+
rows.append(row)
581575

576+
# Add total costs if we have values to add
582577
if len(all_costs) > 0:
583-
if not csv:
584-
res += "_" * 60 + '\n'
585-
else:
586-
res += '\n'
578+
empty_row = [""] * len(field_names)
579+
rows.append(empty_row)
580+
for currency, cost in all_costs.items():
581+
row = empty_row[:]
582+
row[0] = "Total Cost, {currency:>4}".format(**vars())
583+
row[3] = "{currency:>4} {cost:.2f}".format(**vars())
584+
585+
rows.append(row)
587586

588-
res += "Total Cost:\n"
587+
res = _table_string(field_names, rows, csv)
589588

590-
for currency in all_costs.keys():
591-
if not csv:
592-
res += "\t\t%s %.2f\n" % (currency, all_costs[currency])
593-
else:
594-
res += "%s\t%.2f\n" % (currency, all_costs[currency])
595-
596-
res += '\n'
597589
return res
598590

599-
600-
# FIXME: finish this.
601-
def bill_of_materials_justified():
602-
res = ''
603-
columns = [s.rjust(8)
604-
for s in ("Desc.", "Count", "Unit Price", "Total Price")]
605-
all_costs = {}
606-
for desc, (count, currency, price) in g_parts_dict.items():
607-
if count > 0:
608-
if price:
609-
total = price * count
610-
try:
611-
all_costs[currency] += total
612-
except:
613-
all_costs[currency] = total
614-
615-
res += "%(desc)s %(count)s %(currency)s %(price)s %(currency)s %(total)s \n" % vars()
616-
else:
617-
res += "%(desc)s %(count)s " % vars()
618-
if all_costs > 0:
619-
res += "_" * 60 + '\n'
620-
res += "Total Cost:\n"
621-
for currency in all_costs.keys():
622-
res += "\t\t%s %.2f\n" % (currency, all_costs[currency])
623-
res += "\n"
624-
return res
591+
def _currency_str(value, currency="$"):
592+
return "{currency:>4} {value:.2f}".format(**vars())
593+
594+
def _table_string(field_names, rows, csv=False):
595+
# Output a justified table string using the prettytable module.
596+
# Fall back to Excel-ready tab-separated values if prettytable's not found
597+
# or CSV is requested
598+
if not csv:
599+
try:
600+
import prettytable
601+
table = prettytable.PrettyTable(field_names=field_names)
602+
for row in rows:
603+
table.add_row(row)
604+
res = table.get_string()
605+
except ImportError as e:
606+
print("Unable to import prettytable module. Outputting in TSV format")
607+
csv = True
608+
if csv:
609+
lines = ["\t".join(field_names)]
610+
for row in rows:
611+
line = "\t".join([str(f) for f in row])
612+
lines.append(line)
613+
614+
res = "\n".join(lines)
615+
616+
return res + "\n"
625617

626618
# ================
627619
# = Bounding Box =

0 commit comments

Comments
 (0)