import csv import config from utils import normalize, find_csv_path def read_manifest(project_name): """Reads the manifest CSV for a specific project into a list of dictionaries.""" csv_filepath = find_csv_path(project_name) if not csv_filepath: return None print(f"[{project_name}] Reading manifest: {csv_filepath}") manifest_items = [] # Only require Alias and Panel now for basic grouping required_cols = {config.CSV_ALIAS_COL, config.CSV_PANEL_COL} optional_cols = {config.CSV_EQ_TYPE_COL, config.CSV_CONV_TYPE_COL} try: # Revert back to 'utf-8-sig' to handle potential BOM from Excel with open(csv_filepath, mode='r', newline='', encoding='utf-8-sig') as infile: reader = csv.DictReader(infile) # Strip whitespace from headers for reliable matching headers = set(h.strip() for h in reader.fieldnames if h) # Added 'if h' to handle potential empty headers # Check for required columns missing_required = required_cols - headers if missing_required: print(f"Error: Missing required columns in CSV '{csv_filepath}': {', '.join(missing_required)}") print(f"Available columns: {', '.join(headers)}") return None for row in reader: # Strip whitespace from values as well alias = row.get(config.CSV_ALIAS_COL, "").strip() panel = row.get(config.CSV_PANEL_COL, "").strip() # Add if Alias and Control Panel are present (Panel needed for grouping results later) if alias and panel: item = { "alias": alias, "normalized_alias": normalize(alias), "control_panel": panel, # Add optional data if columns exist and have values "equipment_type": row.get(config.CSV_EQ_TYPE_COL, "").strip() if config.CSV_EQ_TYPE_COL in headers else "N/A", "conveyor_type": row.get(config.CSV_CONV_TYPE_COL, "").strip() if config.CSV_CONV_TYPE_COL in headers else "N/A", # Status fields to be filled later "found_scada": False, "found_drawing": False } manifest_items.append(item) elif alias and not panel: print(f"Warning: Alias '{alias}' found in CSV but is missing its '{config.CSV_PANEL_COL}'. Skipping.") # Add other specific warnings if needed except FileNotFoundError: print(f"Error: Manifest file not found at {csv_filepath}") return None except Exception as e: print(f"Error reading CSV file {csv_filepath}: {e}") return None print(f"Read {len(manifest_items)} valid items from manifest.") return manifest_items