Source code for medvision_bm.utils.utils

import json
import os
import tempfile

import torch


[docs] def atomic_write_json(json_path, data, indent=4): """Write ``data`` as JSON to ``json_path`` atomically. Writes to a temp file in the same directory, fsyncs it, then ``os.replace``-es it over the target. If the write fails (e.g. ENOSPC on a full disk), the original file is left untouched instead of being truncated to 0 bytes, which is what opening the target directly with mode ``"w"`` would do. Args: json_path (str): Destination path for the JSON file. data: Any JSON-serializable object to write. indent (int): Indentation passed to ``json.dump``. Defaults to ``4``. Raises: BaseException: Re-raises any error raised while writing or replacing the file, after removing the partial temp file. """ dir_name = os.path.dirname(json_path) or "." os.makedirs(dir_name, exist_ok=True) fd, tmp_path = tempfile.mkstemp(dir=dir_name, suffix=".tmp") try: with os.fdopen(fd, "w") as f: json.dump(data, f, indent=indent) f.flush() os.fsync(f.fileno()) os.replace(tmp_path, json_path) except BaseException: # Don't leave a partial temp file behind on failure. try: os.remove(tmp_path) except OSError: pass raise
[docs] def str2bool(v): """Coerce a string (or bool) to a boolean, for use as an ``argparse`` type. Args: v: A boolean, or a string such as ``"yes"``, ``"true"``, ``"1"``, ``"no"``, ``"false"``, or ``"0"`` (case-insensitive). Returns: bool: ``True`` for truthy tokens and ``False`` for falsy tokens. A value that is already a ``bool`` is returned unchanged. Raises: argparse.ArgumentTypeError: If ``v`` is not a recognized boolean token. """ import argparse if isinstance(v, bool): return v if v.lower() in ("yes", "y", "true", "t", "1"): return True elif v.lower() in ("no", "n", "false", "f", "0"): return False else: raise argparse.ArgumentTypeError("Boolean value expected.")
[docs] def set_cuda_num_processes(): """Determine the number of GPU processes to launch from the CUDA environment. Reads ``CUDA_VISIBLE_DEVICES``. When it is unset, all GPUs reported by ``torch.cuda.device_count()`` are used; otherwise the number of device ids listed in the variable is used (at least 1). Returns: int: The number of processes to run, one per visible GPU. """ cuda_visible = os.getenv("CUDA_VISIBLE_DEVICES", None) if cuda_visible is None: num_processes = torch.cuda.device_count() print( f"No CUDA_VISIBLE_DEVICES found. Using all available GPUs: {num_processes}" ) return num_processes else: num_processes = max(1, len([d for d in cuda_visible.split(",") if d.strip()])) print( f"Using CUDA_VISIBLE_DEVICES={cuda_visible}; num_processes={num_processes}" ) return num_processes
[docs] def update_task_status(json_path, model_name, task_name): """Mark a (model, task) pair as completed in a JSON tracking file. Loads the existing status file (creating the parent directory and treating a missing file as empty), sets ``data[model_name][task_name]`` to ``True``, and writes the file back atomically. Args: json_path (str): Path to the JSON tracking file. model_name (str): Model whose status is updated. task_name (str): Task to mark as completed. Returns: bool: Always ``False``; the return value is unused by callers. """ # Create the folder if it doesn't exist os.makedirs(os.path.dirname(json_path), exist_ok=True) # Update the completion status if os.path.exists(json_path): with open(json_path, "r") as f: data = json.load(f) else: data = {} if model_name not in data: data[model_name] = {} data[model_name][task_name] = True atomic_write_json(json_path, data) return False
[docs] def load_tasks(json_file_path): """Load task names from a JSON file mapping task names to their definitions. Args: json_file_path (str): Path to a JSON file whose top-level keys are task names. Returns: list: The task names (the top-level keys), in file order. """ with open(json_file_path, "r") as f: tasks_dict = json.load(f) tasks = list(tasks_dict.keys()) print(f"\nFound {len(tasks)} tasks to process: {tasks}\n") return tasks
[docs] def load_tasks_status(tasks_status_file, model_name): """Return the completion-status mapping for a single model. Args: tasks_status_file (str): Path to the JSON status file. A missing file is treated as empty. model_name (str): Model whose status entry is returned. Returns: dict: Mapping of task name to completion flag for ``model_name``, or an empty dict if the file or the model entry is absent. Raises: ValueError: If the status file exists but cannot be read or parsed. """ if os.path.exists(tasks_status_file): try: with open(tasks_status_file, "r") as f: completed_all = json.load(f) except Exception as e: raise ValueError( f"Error loading tasks status file: {tasks_status_file}\nError: {e}" ) else: completed_all = {} return completed_all.get(model_name, {})