Coverage for laskea/api/excel.py: 98.78%
45 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-10 22:19:18 +00:00
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-10 22:19:18 +00:00
1import hashlib
2import pathlib
3from typing import no_type_check
5from openpyxl import load_workbook # type: ignore
7from laskea import BASE_LF_ONLY
9CHUNK_SIZE = 2 << 15
12def hash_file(path: pathlib.Path) -> str:
13 """Return the SHA512 hex digest of the data from file."""
14 hash = hashlib.sha512()
15 with open(path, 'rb') as handle:
16 while chunk := handle.read(CHUNK_SIZE):
17 hash.update(chunk)
18 return hash.hexdigest()
21@no_type_check
22def mbom_table(filename: str):
23 """Import MBOM per convention from office table file."""
24 wb = load_workbook(filename=filename, data_only=True, read_only=True)
25 ws = wb.worksheets[0]
27 table_headers = [ws[address].value for address in ('A1', 'B1', 'C1', 'D1')]
29 table_caption_data = [ws[address].value for address in ('A2', 'B2', 'C2', 'D2')]
31 max_row = 1000
32 table_rows = []
33 for row in range(3, max_row):
34 data = [ws[address].value for address in (f'A{row}', f'B{row}', f'C{row}', f'D{row}')]
35 if [x for x in data if x]:
36 table_rows.append(data)
38 # print(table_headers)
39 # ['Level', 'P/N', 'Item Name', 'SW Version']
41 # print(table_caption_data)
42 # [0, '123', 'SW, PRODUCT, CUST', None]
44 # for row in table_rows:
45 # print(row)
47 # [1, '124', 'THAT, DEF, LINUX', 'v1.2']
48 # [1, '125', 'THAT, EFG, ABA8000, LINUX', 'Rev.24']
49 # [1, '126', 'THAT, ABC, CUST', 'v7_R2427']
50 # [2, '127', 'THAT, MNMNM, LINUX', 'v6.204.70']
51 # [2, '128', 'THAT, WHAT, XXXX4, LINUX', 'v4.2']
52 # [3, '129', 'SIMULATION, ABC v7.0', 'v7.0']
53 # [4, '130', 'ORGA v7.0 IJK', 'v7.0']
54 # [3, '222', 'ABC Config XML - CUST', 'v7.0']
55 # [3, '223', 'ABC Default Trip XML', 'v7.0']
56 # [3, '224', 'ABC Default Patching XML - LD Smoke', 'v7.0']
57 # [3, '227', 'ABC Default EFK Config Files - MNO12', 'v6.204.70']
58 # [2, '132', 'LIBRARY, FUNNY HEART, 1.0', 'v1.0']
59 # [2, '131', 'XYZ RUNTIME, LINUX', 'v3.3.0']
60 # [1, '141', 'THAT, UVW', 'Core 2.0.1, Adapter 2.0.4']
62 header_widths = [len(label) for label in table_headers] # noqa
63 widths = header_widths[:]
64 selection = table_rows[:]
65 for record in selection:
66 for i, s in enumerate(record):
67 if s is not None: 67 ↛ 66line 67 didn't jump to line 66, because the condition on line 67 was never false
68 widths[i] = max(widths[i], len(str(s)))
70 header_cells = [table_headers[key].ljust(widths[key]) for key in range(len(table_headers))] # noqa # noqa
71 header = f'| {" | ".join(header_cells)} |'
73 separator_cells = ['-' * (widths[key] + 1) for key in range(len(table_headers))] # noqa
74 separator = [f':{v}' for v in separator_cells]
75 separator_display = f'|{"|".join(separator)}|'
77 dows = []
78 for dow in selection:
79 dows.append([str(v).ljust(widths[k]) for k, v in enumerate(dow)])
81 rows_display = [f'| {" | ".join(v for v in row)} |' for row in dows]
83 semantics = f'<!-- anchor: {tuple(str(e) if e is not None else "" for e in table_caption_data)}-->'
84 source = f'<!-- source: {pathlib.Path(filename)}-->'
85 checksum = f'<!-- s-hash: sha512:{hash_file(pathlib.Path(filename))}-->'
86 the_table = '\n'.join([semantics] + [header] + [separator_display] + rows_display + [source] + [checksum])
88 return the_table.replace('\r', '') if BASE_LF_ONLY else the_table