Source code for labnirs2snirf.args

"""
Module for handling command-line arguments.
"""

import argparse
from pathlib import Path
from typing import Self

from .error import Labnirs2SnirfError


[docs] class ArgumentError(Labnirs2SnirfError): """Error indicating invalid command-line arguments."""
def _file_must_exist(path_str: str) -> Path: """ Validate that a file path exists. This function is used as an argparse type validator to ensure that a provided path points to an existing file. Parameters ---------- path_str : str String representation of the file path to validate. Returns ------- Path Validated Path object if the file exists. Raises ------ ArgumentError If the path is empty, does not exist, or is not a file. """ if not path_str: raise ArgumentError("Path must not be empty.") path = Path(path_str) if not path.exists() or not path.is_file(): raise ArgumentError(f"File '{path_str}' does not exist.") return path def _file_must_not_exist(path_str: str) -> Path: """ Validate that a file path does not already exist. This function is used as an argparse type validator to ensure that a provided path does not point to an existing file, preventing accidental overwrites. Parameters ---------- path_str : str String representation of the file path to validate. Returns ------- Path Validated Path object if the path does not exist. Raises ------ ArgumentError If the path is empty or already exists. """ if not path_str: raise ArgumentError("Path must not be empty.") path = Path(path_str) if path.exists(): raise ArgumentError(f"Path '{path_str}' already exists.") return path def _validate_drop_value(value: str) -> str: """ Validate a single drop value for the --drop argument. Parameters ---------- value : str Drop value to validate. Can be 'HbT', 'HbO', 'HbR' (case insensitive), or a positive integer indicating wavelength. Returns ------- str Validated and normalized (lowercase) drop value. Raises ------ ArgumentError If the value is not a valid drop type. """ value = value.lower().strip() if value.isdecimal() and int(value) > 0: return value if value in {"hbt", "hbo", "hbr"}: return value raise ArgumentError( f"Invalid drop type '{value}'. Must be 'HbT', 'HbO', 'HbR' " f"(case insensitive) or a positive non-zero integer indicating wavelength.", ) # class _NotImplementedAction(argparse.Action): # def __call__(self, parser, namespace, values, option_string=None): # raise ArgumentError(f"'{option_string}' option is not implemented yet.")
[docs] class Arguments: """ Class to handle configuration and parsing of command-line arguments. Parameters ---------- progname : str or None, default=__package__ Program name to display in help message. If None, defaults to package name. """ parser: argparse.ArgumentParser source_file: Path target_file: Path type: str log: bool verbosity: int locations: Path | None drop: set[str] | None
[docs] def __init__(self, progname: str | None = __package__): """ Initialize the Arguments parser. Parameters ---------- progname : str or None, default=__package__ Program name to display in help message. If None, defaults to package name. """ parser = argparse.ArgumentParser( description="Convert LabNIRS data to SNIRF format.", allow_abbrev=False, prog=progname if progname else "labnirs2snirf", ) parser.add_argument( "source_file", help="path to LabNIRS data file (*.txt)", type=_file_must_exist, ) parser.add_argument( "target_file", help="path to output file (*.snirf); if not specified, output is written to the current directory as <out.snirf>", nargs="?", default="out.snirf", type=_file_must_not_exist, ) parser.add_argument( "--locations", help="Path to file holding probe location data. " "Location files are expected to follow the .sfp format, i.e. " "tab-separated text file with columns: optode name, x, y, and z, " "where x, y, an z are the 3D coordinates of the optode. " "Conflicts with -g.", type=_file_must_exist, ) parser.add_argument( "--type", help="Include specific data category only. " "'Raw' includes raw voltage, 'Hb' includes heamoglobin' data, 'all' (default) includes both.", choices=["hb", "raw", "all"], type=str.lower, default="all", ) parser.add_argument( "--drop", help="Drop specific data types. " "Possible values: HbT, HbO, HbR, or wavelength integers (e.g. 780). Can be used multiple times.", action="append", type=_validate_drop_value, ) parser.add_argument( "-v", "--verbose", action="count", help="Increase verbosity of output, can be used multiple times. One -v for ERROR/WARNING level, " "-vv for INFO level, -vvv for DEBUG level. Combine with --log to redirect log output to file.", default=0, dest="verbosity", ) parser.add_argument( "--log", action="store_true", help="Redirects logging to file labnirs2snirf.log in the current directory. " "Logging level is controlled by -v/--verbose. Specifying --log implies -v." "Log messages written to file contain additional information about where messages occurred.", ) # parser.add_argument( # "-csv", # "--tasks", # help="(NOT IMPLEMENTED) path to .csv file containing task timings", # type=Path, # action=NotImplementedAction, # # action=FileMustExistAction, # ) # parser.add_argument( # "-pat", # "--patient", # help="(NOT IMPLEMENTED) path to .pat file containing patient and study metadata", # type=Path, # action=NotImplementedAction, # # action=FileMustExistAction, # ) self.parser = parser
[docs] def parse(self, args: list[str]) -> Self: """ Parse command-line arguments and populate the Arguments object. Parameters ---------- args : list[str] List of command-line arguments to parse. If empty, shows help. Returns ------- Self Self with parsed argument values set as attributes. Notes ----- If --log is specified, verbosity is automatically set to at least 1. Drop values are converted to a set to avoid duplicates. """ parser = self.parser del self.parser parser.parse_args(args=args or ["-h"], namespace=self) # If --log is specified, ensure verbosity is at least 1 if self.log: self.verbosity = max(self.verbosity, 1) # Convert drop list to set to avoid duplicates if self.drop is not None: self.drop = set(self.drop) return self
[docs] def __str__(self) -> str: """ Return a string representation of the Arguments object. Returns ------- str String showing arguments stored. """ return f"Arguments({str(self.__dict__)})"
[docs] def __repr__(self) -> str: """ Return a detailed string representation of the Arguments object. Returns ------- str String showing arguments stored. """ return f"Arguments({repr(self.__dict__)})"