From e574407fe6473d5bb571b975a3ef92c934436036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Miquel?= Date: Sun, 15 Feb 2026 16:50:39 +0100 Subject: [PATCH] Giving names and populating the ods current_eval file --- giving_names.py | 98 ++++++++++++++++++++------------ update_ods.py | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 update_ods.py diff --git a/giving_names.py b/giving_names.py index a10e05e..3cdbf68 100644 --- a/giving_names.py +++ b/giving_names.py @@ -1,23 +1,20 @@ import os import sys import json -import shutil import re from collections import defaultdict def main(): if len(sys.argv) < 2: - print("Usage: python rename_copies.py ") + print("Usage: python giving_names.py ") sys.exit(1) - work_dir = sys.argv[1] - target_subdir = os.path.join(work_dir, "Copies annotées") + work_dir = os.path.abspath(sys.argv[1]) + target_subdir = os.path.join(work_dir, "A Rendre") os.makedirs(target_subdir, exist_ok=True) pattern = re.compile(r"^Copie(\d+)\.json$") - - # Store data: name -> list of (copie_id, source_folder) copies_map = defaultdict(list) # 1. Collect all data @@ -26,40 +23,67 @@ def main(): if match: copie_id = match.group(1) json_path = os.path.join(work_dir, filename) - source_folder = os.path.join(work_dir, f"Anot_Copie{copie_id}") - - if os.path.isdir(source_folder): - try: - with open(json_path, 'r', encoding='utf-8') as f: - data = json.load(f) - name = data.get("name", "Unknown").strip() - copies_map[name].append((copie_id, source_folder)) - except Exception as e: - print(f"Error processing {filename}: {e}") - - # 2. Check constraints and move files - for name, entries in copies_map.items(): - # Alert if name is Unknown - if name == "Unknown": - ids = [e[0] for e in entries] - print(f"ALERT: 'Unknown' name found for IDs: {', '.join(ids)}") - - # Alert if duplicates (same name, multiple IDs) - elif len(entries) > 1: - ids = [e[0] for e in entries] - print(f"ALERT: Name '{name}' assigned to multiple IDs: {', '.join(ids)}") - - # Perform move - safe_name = re.sub(r'[<>:"/\\|?*]', '', name) - for copie_id, source_folder in entries: - new_folder_name = f"{safe_name} ({copie_id})" - dest_path = os.path.join(target_subdir, new_folder_name) try: - print(f"Moving '{source_folder}' -> '{dest_path}'") - shutil.move(source_folder, dest_path) + with open(json_path, 'r', encoding='utf-8') as f: + data = json.load(f) + name = data.get("name", "Unknown").strip() + copies_map[name].append(copie_id) except Exception as e: - print(f"Error moving {source_folder}: {e}") + print(f"Error processing {filename}: {e}") + + # 2. Check constraints and symlink files + for name, ids in copies_map.items(): + if name == "Unknown": + print(f"ALERT: 'Unknown' name found for IDs: {', '.join(ids)}") + elif len(ids) > 1: + print(f"ALERT: Name '{name}' assigned to multiple IDs: {', '.join(ids)}") + + safe_name = re.sub(r'[<>:"/\\|?*]', '', name).strip() + + for copie_id in ids: + path_b = os.path.join(work_dir, f"Bnot/Copie{copie_id}") + path_a = os.path.join(work_dir, f"Anot/Copie{copie_id}") + + # Determine source: must contain both files + source_folder = None + + # Check Bnot first + if (os.path.exists(os.path.join(path_b, "Concat.jpg")) and + os.path.exists(os.path.join(path_b, "score.json"))): + source_folder = path_b + # Fallback to Anot + elif (os.path.exists(os.path.join(path_a, "Concat.jpg")) and + os.path.exists(os.path.join(path_a, "score.json"))): + source_folder = path_a + + if not source_folder: + print(f"Skipping ID {copie_id}: Files missing in both Anot and Bnot.") + continue + + # Create destination directory + dest_folder_name = safe_name if len(ids) == 1 else f"{safe_name} ({copie_id})" + dest_path = os.path.join(target_subdir, dest_folder_name) + os.makedirs(dest_path, exist_ok=True) + + print(f"Linking '{source_folder}' -> '{dest_path}'") + + # Link configuration: (source_filename, dest_filename) + links = [ + ("Concat.jpg", f"{safe_name}.jpg"), + ("score.json", "score.json") + ] + + for src_name, dst_name in links: + src_file = os.path.join(source_folder, src_name) + dst_link = os.path.join(dest_path, dst_name) + + try: + if os.path.lexists(dst_link): + os.remove(dst_link) + os.symlink(src_file, dst_link) + except Exception as e: + print(f"Error linking {src_name} for {dest_folder_name}: {e}") if __name__ == "__main__": main() diff --git a/update_ods.py b/update_ods.py new file mode 100644 index 0000000..866c8a1 --- /dev/null +++ b/update_ods.py @@ -0,0 +1,147 @@ +import os +import sys +import json +import ezodf + +# Configuration +ODS_PATH = "/home/sebastien/Rust/gestion_classe/Staging/current_eval.ods" +TARGET_DIR_NAME = "A Rendre" + +def main(): + if len(sys.argv) < 2: + # Default to current directory if not provided, or raise error + work_dir = os.getcwd() + else: + work_dir = os.path.abspath(sys.argv[1]) + + a_rendre_path = os.path.join(work_dir, TARGET_DIR_NAME) + + if not os.path.isdir(a_rendre_path): + print(f"Error: Directory '{TARGET_DIR_NAME}' not found in {work_dir}") + sys.exit(1) + + if not os.path.exists(ODS_PATH): + print(f"Error: ODS file not found at {ODS_PATH}") + sys.exit(1) + + print(f"Opening ODS file: {ODS_PATH}...") + try: + doc = ezodf.opendoc(ODS_PATH) + except Exception as e: + print(f"Failed to open ODS: {e}") + sys.exit(1) + + # Assuming the data is in the first sheet + sheet = doc.sheets[0] + + # Map Student Names to Column Indices + # User specified: Names are in the second line (index 1) + # User specified: Ignore first 3 columns (0, 1, 2) + name_row_index = 1 + name_to_col = {} + + for col_idx in range(3, sheet.ncols()): + cell = sheet[name_row_index, col_idx] + if cell.value: + # Normalize name: strip spaces + name = str(cell.value).strip() + name_to_col[name] = col_idx + + print(f"Found {len(name_to_col)} students in ODS.") + + # Iterate over folders in "A Rendre" + for item in os.listdir(a_rendre_path): + student_dir = os.path.join(a_rendre_path, item) + + # Check if it is a directory and has a name (ignoring the (ID) suffix if present from previous script) + # The directory name might be "Name" or "Name (ID)". + # The ODS usually contains just "Name". + + if not os.path.isdir(student_dir): + continue + + # Extract strict name for ODS matching (remove potential ID suffix if added by previous tool) + # Assuming the ODS name matches the folder name prefix + # If folder is "Doe John (123)", ODS likely has "Doe John" or "Doe John (123)"? + # Based on previous prompt, ODS has "AMELOT Gautier". + # We try exact match first, then simplified match. + + json_path = os.path.join(student_dir, "score.json") + if not os.path.exists(json_path): + continue + + with open(json_path, 'r', encoding='utf-8') as f: + try: + scores_data = json.load(f) + except json.JSONDecodeError: + print(f"Error decoding JSON for {item}") + continue + + # Determine Column Index + col_idx = name_to_col.get(item) + + # If not found exact match, try stripping ID suffix e.g. "Name (123)" -> "Name" + if col_idx is None and '(' in item: + clean_name = item.rsplit('(', 1)[0].strip() + col_idx = name_to_col.get(clean_name) + + if col_idx is None: + print(f"Skipping '{item}': Name not found in ODS columns.") + continue + + # Sort keys naturally (Ex 2 comes before Ex 10) + # sorted_keys = natsorted(scores_data.keys()) + + # Start filling from Row 2 (index 2), immediately below the name line + start_row = 2 + + for i, key in enumerate(scores_data.keys()): + row_idx = start_row + i + + # Ensure we don't go out of bounds + if row_idx >= sheet.nrows(): + sheet.append_rows(1) + + val_str = str(scores_data[key]) + + # Logic: if "" -> "NT" + new_val = "NT" if val_str == "" else val_str + + cell = sheet[row_idx, col_idx] + current_val = cell.value + + # Conflict Detection + # Normalize current ODS value to string for comparison + # ODS might store 2.0 as float 2.0. JSON has "2.0". + is_different = False + + if current_val is not None and current_val != "": + # specific check to handle float/string mismatch (2.0 vs "2.0") + try: + if float(str(current_val)) != float(str(new_val)): + is_different = True + except ValueError: + # If conversion fails (e.g. comparing "NT" to "2.0"), compare strings + if str(current_val).strip() != str(new_val).strip(): + is_different = True + + if is_different: + print(f"DEBUG: Conflict for {item} at {key} (Row {row_idx}). " + f"Existing: '{current_val}' vs New: '{new_val}'. Overwriting.") + + # Set value + # Try to set as float if it looks like a number, otherwise string + if new_val == "NT": + cell.set_value(new_val) + else: + try: + cell.set_value(float(new_val)) + except ValueError: + cell.set_value(new_val) + + print("Saving ODS file...") + doc.save() + print("Done.") + +if __name__ == "__main__": + main()