helpers.py (6660B)
1 #!/usr/bin/env python3 2 # -*- coding: utf-8 -*- 3 # vim:fenc=utf-8 4 5 import datetime 6 import json 7 import subprocess 8 import tempfile 9 import time 10 import shutil 11 12 from os import listdir 13 14 from partsdb import exports 15 16 17 def print_parts_list(parts, output="full"): 18 if output == "short": 19 _list_ascii_short(parts) 20 if output == "full": 21 _list_ascii(parts) 22 if output == "json": 23 _list_json(parts) 24 25 26 def _list_ascii(parts): 27 # max takes an iterable and key is a function where iterables are 28 # passed and comparison performed, so we look at the longest desc to 29 # get the lenght of the field. We also check if the header is longer, 30 # the result is whatever is longer 31 l_mpn = len(max(parts, key=lambda k: len(k["mpn"]))["mpn"]) 32 l_cat = len(max(parts, key=lambda k: len(k["cname"]))["cname"]) 33 l_man = len(max(parts, key=lambda k: len(k["manufacturer"]))["manufacturer"]) 34 l_desc = len(max(parts, key=lambda k: len(k["description"]))["description"]) 35 l_cat = l_cat if l_cat > len("Category") else len("Category") 36 l_man = l_man if l_man > len("Manufacturer") else len("Manufacturer") 37 l_desc = l_desc if l_desc > len("Description") else len("Description") 38 39 header = ( 40 f"| {'ID':5} | {'PN':4} | " 41 f"{'MPN':{l_mpn}} | " 42 f"{'Category':{l_cat}} | " 43 f"{'Manufacturer':{l_man}} | " 44 f"{'Description':{l_desc}} | " 45 f"{'Type':4} | " 46 f"{'Footp':6} | " 47 f"{'Qty':4} |" 48 ) 49 for i, p in enumerate(parts): 50 if i % 25 == 0: 51 print("-" * len(header)) 52 print(header) 53 print("-" * len(header)) 54 print( 55 f"| {p['id']:<5} | {p['id']:04X} | " 56 f"{p['mpn']:{l_mpn}} | " 57 f"{p['cname']:{l_cat}} | " 58 f"{_sanitize_value(p['manufacturer']):{l_man}} | " 59 f"{_sanitize_value(p['description']):{l_desc}} | " 60 f"{_sanitize_value(p['part_type'])[0:3]:4} | " 61 f"{_sanitize_value(p['footprint'])[0:5]:6} | " 62 f"{p['quantity']:4} |" 63 ) 64 65 66 def _list_ascii_short(parts): 67 header = ( 68 f"| {'ID':4} | " 69 f"{'Category':8} | " 70 f"{'MPN':10} | " 71 f"{'Manufacturer':16} | " 72 f"{'Description':25} |" 73 ) 74 for i, p in enumerate(parts): 75 if i % 25 == 0: 76 print("-" * 79) 77 print(header) 78 print("-" * 79) 79 print( 80 f"| {p['id']:<4} | " 81 f"{p['cname'][0:7]:8} | " 82 f"{_sanitize_value(p['mpn'])[0:9]:10} | " 83 f"{_sanitize_value(p['manufacturer'])[0:15]:16} | " 84 f"{_sanitize_value(p['description'])[0:24]:25} |" 85 ) 86 87 88 def _list_json(parts): 89 p = [dict(zip(part.keys(), part)) for part in parts] 90 print(json.dumps({"parts": p})) 91 92 93 def print_part(p, history, output="full"): 94 if output == "full": 95 _part_ascii(p, history) 96 if output == "json": 97 _part_json(p, history) 98 99 100 def _part_ascii(p, history): 101 print(f"PN: {p['id']:04X}\tMPN: {p['mpn']}\tManufacturer: {p['manufacturer']}") 102 print( 103 f"Category: {p['cat']}\tType: {p['part_type']}" f"\tFootprint: {p['footprint']}" 104 ) 105 print(f"Storage: {p['storage']}") 106 print(f"Created: {p['insert_date']}" f"\tUpdated: {p['update_date']}\n") 107 print(f"Description:\n{p['description']}\n") 108 print(f"Specs:\n{p['specs']}") 109 110 if p["datasheet"] is not None: 111 print("This part has a datasheet available.") 112 if p["image"] is not None: 113 print("This part has an image available.") 114 115 print(f"\nQuantity: {p['quantity']}") 116 # here should go the historical data. 117 if history: 118 print("History:") 119 for h in history: 120 print(f"{h['insert_date']} | " f"{h['movement']:4} | " f"{h['mcomment']}") 121 122 123 def _part_json(part, history): 124 part = dict(zip(part.keys(), part)) 125 # remove bytes data if present. For now is useless in this output. 126 del part["datasheet"] 127 del part["image"] 128 129 part["history"] = [dict(zip(h.keys(), h)) for h in history] 130 131 print(json.dumps({"part": part})) 132 133 134 def _sanitize_value(value): 135 if value is None: 136 return "-" 137 return value 138 139 140 def open_file(content, extension): 141 with tempfile.NamedTemporaryFile(suffix=extension) as f: 142 f.write(content) 143 subprocess.Popen(["xdg-open", f.name], start_new_session=True) 144 time.sleep(2) 145 146 147 def html_main_index(dest_folder, categories, storages, env): 148 tpl = env.get_template("index.html") 149 with open(f"{dest_folder}/index.html", "w") as f: 150 f.write( 151 tpl.render( 152 cat=categories, 153 sto=storages, 154 time_generated=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 155 ) 156 ) 157 158 159 def html_category_index(dest_folder, category, parts, env): 160 tpl = env.get_template("cat.html") 161 with open(f"{dest_folder}/cat_list_{category['id']}.html", "w") as f: 162 f.write( 163 tpl.render( 164 category=category, 165 parts=parts, 166 time_generated=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 167 ) 168 ) 169 170 171 def html_storage_index(dest_folder, storage, parts, env): 172 tpl = env.get_template("storage.html") 173 with open(f"{dest_folder}/storage_{storage['id']}.html", "w") as f: 174 f.write( 175 tpl.render( 176 storage=storage, 177 parts=parts, 178 time_generated=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 179 ) 180 ) 181 182 183 def html_part(dest_folder, part, part_history, env): 184 tpl = env.get_template("part.html") 185 with open(f"{dest_folder}/part_{part['id']}.html", "w") as f: 186 f.write( 187 tpl.render( 188 part=part, 189 history=part_history, 190 time_generated=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 191 ) 192 ) 193 194 195 def html_css(dest_folder, env): 196 tpl = env.get_template("style.css") 197 with open(f"{dest_folder}/style.css", "w") as f: 198 f.write(tpl.render()) 199 200 201 def html_aux_files(dest_folder): 202 orig_folder = list(exports.__path__)[0] 203 aux_files = listdir(f"{orig_folder}/files") 204 for f in aux_files: 205 shutil.copy2(f"{orig_folder}/files/{f}", dest_folder) 206 207 208 def html_attachments(dest_folder, part_id, datasheet, image): 209 if datasheet["datasheet"] is not None: 210 with open(f"{dest_folder}/part_datasheet_{part_id}.pdf", "wb") as f: 211 f.write(datasheet["datasheet"]) 212 if image["image"] is not None: 213 with open(f"{dest_folder}/part_image_{part_id}.jpg", "wb") as f: 214 f.write(image["image"])