From 705e270004e4333b1642d4eb1af6be6ca23e65c3 Mon Sep 17 00:00:00 2001 From: dat972 Date: Thu, 9 Jul 2026 21:52:19 -0500 Subject: [PATCH] updated how we are doing manifests so they are more clean and easier to check file formats --- __pycache__/fccs_verify.cpython-313.pyc | Bin 0 -> 6307 bytes fccs_export.py | 70 +++++++++++++++++++----- fccs_verify.py | 23 +++++--- 3 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 __pycache__/fccs_verify.cpython-313.pyc diff --git a/__pycache__/fccs_verify.cpython-313.pyc b/__pycache__/fccs_verify.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..684a9efb605ae403828e6d5138ec206d757cbfb2 GIT binary patch literal 6307 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 JR`GQ}{vS*KS^59~ literal 0 HcmV?d00001 diff --git a/fccs_export.py b/fccs_export.py index 93e3f22..6f0784c 100755 --- a/fccs_export.py +++ b/fccs_export.py @@ -168,21 +168,63 @@ def open_send_to_file(main, app, ctrl, timeouts): return dlg -def read_manifest(dlg, log): - """Read the list of selected documents from the right-side ListView.""" +def read_manifest(dlg, drawer_id, log): + """Read the selected documents from the ListView into clean rows. + + The ListView (`List1`) has columns Drawer ID, Page Title (the document + name) and Application. `texts()` returns a flat, row-major dump led by the + control's own name ('List1'), which is why the raw capture looked messy. + + This parses it into one row per document and drops the redundant Drawer ID + column (always equal to drawer_id) and any empty columns, leaving the + document name (and Application) per line. Returns a list of rows (each a + list of cell strings), [] if empty, or None if it couldn't be read. + """ try: lv = dlg.child_window(title="List1", class_name="SysListView32") - count = lv.item_count() - if count == 0: - log(" WARNING: ListView is empty after Select") - return [] - items = lv.texts() - log(f" Manifest captured: {count} documents selected") - return items + n_rows = lv.item_count() except Exception as e: - log(f" WARNING: could not read manifest from ListView: {e}") + log(f" WARNING: could not read manifest list: {e}") return None + if n_rows == 0: + log(" WARNING: ListView is empty after Select") + return [] + + try: + n_cols = lv.column_count() + except Exception: + n_cols = 0 + if not n_cols or n_cols < 1: + n_cols = 3 # observed columns: Drawer ID, Page Title, Application + + # Read every cell. Primary: get_item(row, col). Fallback: reshape texts(). + try: + grid = [[lv.get_item(r, c).text() for c in range(n_cols)] + for r in range(n_rows)] + except Exception as e: + log(f" NOTE: get_item failed ({e}); falling back to texts().") + raw = lv.texts() + if raw and raw[0] == lv.window_text(): + raw = raw[1:] # drop the control's own name ('List1') + grid = [raw[i:i + n_cols] for i in range(0, len(raw), n_cols)] + grid = [row for row in grid if len(row) == n_cols] + + # Keep only columns that carry real, non-redundant info. + keep_cols = [] + for c in range(n_cols): + vals = [(row[c].strip() if c < len(row) else "") for row in grid] + if all(v == drawer_id for v in vals): + continue # redundant Drawer ID column + if all(v == "" for v in vals): + continue # empty column + keep_cols.append(c) + + rows = [[(row[c] if c < len(row) else "") for c in keep_cols] + for row in grid] + log(f" Manifest captured: {len(rows)} documents selected") + return rows + def save_manifest(drawer_id, items, manifest_dir, log): """Save the list of expected export items to a manifest file.""" @@ -197,8 +239,8 @@ def save_manifest(drawer_id, items, manifest_dir, log): log(f" Manifest saved: {path}") -def perform_export(dlg, ctrl, timeouts, log): - """Click Select -> then OK to start the export. Returns manifest list.""" +def perform_export(dlg, drawer_id, ctrl, timeouts, log): + """Click Select -> then OK to start the export. Returns manifest rows.""" select_btn = dlg.child_window(title=ctrl["select_btn_title"], class_name="Button") select_btn.wait("visible ready enabled", timeout=timeouts["dialog"]) select_btn.click() @@ -206,7 +248,7 @@ def perform_export(dlg, ctrl, timeouts, log): ok_btn = dlg.child_window(title=ctrl["ok_btn_title"], class_name="Button") ok_btn.wait("visible ready enabled", timeout=timeouts["select"]) - manifest = read_manifest(dlg, log) + manifest = read_manifest(dlg, drawer_id, log) ok_btn.click() return manifest @@ -319,7 +361,7 @@ def export_drawer(app, main, search_box, drawer_id, ctrl, timeouts, # 3 & 4. Select -> and OK (captures manifest before clicking OK) try: - manifest = perform_export(dlg, ctrl, timeouts, log) + manifest = perform_export(dlg, drawer_id, ctrl, timeouts, log) if manifest is not None: save_manifest(drawer_id, manifest, manifest_dir, log) except Exception as e: diff --git a/fccs_verify.py b/fccs_verify.py index 93c9009..aa633df 100644 --- a/fccs_verify.py +++ b/fccs_verify.py @@ -13,14 +13,23 @@ from fccs_config import parse_args, load_config, make_logger def load_manifest(path): - """Load a manifest file and return the list of document rows.""" - items = [] + """Load a manifest file and return one row per document. + + Handles both formats: + - New: one document per line (tab-separated columns). + - Old: a raw ListView dump led by 'List1', then row-major cells with + 3 columns per document (Drawer ID, Page Title, Application). We + reshape it so the document count is correct. + """ with open(path, "r", encoding="utf-8") as f: - for line in f: - line = line.rstrip("\n") - if line: - items.append(line.split("\t")) - return items + lines = [line.rstrip("\n") for line in f if line.strip()] + + if lines and lines[0].strip() == "List1": + cells = lines[1:] + rows = [cells[i:i + 3] for i in range(0, len(cells), 3)] + return [r for r in rows if len(r) == 3] + + return [line.split("\t") for line in lines] def main():