Skip to content

Utils Reference

This page documents the utils sub-package.


medpipe.utils.logger

Logger functions.

This module provides helper functions for logging.

Functions: - setup_logger: sets up a logger for a script. - exception_handler: Function that logs exceptions. - print_message: Function that prints and logs an info message.

exception_handler(logger, log_path, log_config, script_name)

Handles exceptions and logs them.

Parameters:

Name Type Description Default
logger Logger

Logger object that logs the exception.

required
log_path str

Path to the log file being used.

required
log_config dict

Configuration parameters for the log messages.

required
script_name str

Name of the script in which the error occurred.

required

Returns:

Type Description
None

Nothing is returned.

Source code in src/medpipe/utils/logger.py
def exception_handler(logger, log_path, log_config, script_name):
    """
    Handles exceptions and logs them.

    Parameters
    ----------
    logger : logging.Logger
        Logger object that logs the exception.
    log_path : str
        Path to the log file being used.
    log_config : dict
        Configuration parameters for the log messages.
    script_name : str
        Name of the script in which the error occurred.

    Returns
    -------
    None
        Nothing is returned.

    """
    logger.exception(log_config["log_message"] + f"{script_name}")
    sys.stderr.write(log_config["print_message"] + f"{log_path}/{script_name}.log\n")

print_message(message, logger=None, script_name='')

Wrapper function to print message or log them.

If the logger.level is less than 0, only log message. If the logger.level is greater than 0, log and print. If logger is None, only print.

Parameters:

Name Type Description Default
message str

Message to print or log.

required
logger logging.Logger or None, default:None

Logger to log message. If None message is printed to terminal.

None
script_name str

Script name to know where the message is coming from.

""

Returns:

Type Description
None

Nothing is returned.

Source code in src/medpipe/utils/logger.py
def print_message(message, logger=None, script_name="") -> None:
    """
    Wrapper function to print message or log them.

    If the logger.level is less than 0, only log message.
    If the logger.level is greater than 0, log and print.
    If logger is None, only print.

    Parameters
    ----------
    message : str
        Message to print or log.
    logger : logging.Logger or None, default:None
        Logger to log message. If None message is printed to terminal.
    script_name : str, default: ""
        Script name to know where the message is coming from.

    Returns
    -------
    None
        Nothing is returned.

    """
    if logger:
        if logger.level >= 0:
            # Print to file and screen
            logger.info(f"{message} in {script_name}")
            sys.stdout.write(f"[INFO] {message}\n")
        elif logger.level < 0:
            # Don't print to screen
            logger.info(f"{message} in {script_name}")
    else:
        # Only print to screen
        print(f"[INFO] {message} in {script_name}")

setup_logger(script_name, log_path)

Setups a logger for logging exceptions.

Parameters:

Name Type Description Default
script_name str

Name of the script to log exceptions from.

required
log_path str

Path to the folder to store the log file.

required

Returns:

Name Type Description
logger Logger

Logger object.

Raises
______
TypeError

If script_name or log_path are not a str.

FileNotFoundError

If log_path do not exist.

NotADirectoryError

If log_path is not a directory.

Source code in src/medpipe/utils/logger.py
def setup_logger(script_name: str, log_path: str) -> logging.Logger:
    """
    Setups a logger for logging exceptions.

    Parameters
    ----------
    script_name
        Name of the script to log exceptions from.
    log_path
        Path to the folder to store the log file.

    Returns
    -------
    logger : logging.Logger
        Logger object.

    Raises
    ______
    TypeError
        If script_name or log_path are not a str.
    FileNotFoundError
        If log_path do not exist.
    NotADirectoryError
        If log_path is not a directory.

    """
    if type(script_name) is not str:
        raise TypeError(f"{script_name} should be a string")

    try:
        medpipe.utils.exceptions.path_checks(log_path)

    except (FileNotFoundError, TypeError, NotADirectoryError):
        raise

    # Change the log file destination
    logger_config_dict = LOGGING_CONFIG
    logger_config_dict["handlers"]["file"]["filename"] = str(
        pathlib.Path(log_path) / f"{script_name}.log"
    )

    logging.config.dictConfig(logger_config_dict)  # Configure logger

    return logging.getLogger(script_name)

medpipe.utils.io

I/O utilities module.

This module provides helper functions for reading from and writing to files, handling various common I/O tasks.

Functions: - load_data_from_csv: Loads the data from a .csv file. - read_toml_configuration: Parses the contents of a .TOML file.

load_data_from_csv(data_file)

Reads a .csv file and returns its contents.

Parameters


data_file Path to the .csv file to load.

Returns


data : pd.DataFrame Loaded data.

Raises


TypeError If data_file is not a str. FileNotFoundError If data_file does not exist. IsADirectoryError If data_file is not a file. ValueError If data_file extension is not .csv file.

Source code in src/medpipe/utils/io.py
def load_data_from_csv(data_file: str):
    """
    Reads a .csv file and returns its contents.

    Parameters
    __________
    data_file
        Path to the .csv file to load.

    Returns
    _______
    data : pd.DataFrame
        Loaded data.

    Raises
    ______
    TypeError
        If data_file is not a str.
    FileNotFoundError
        If data_file does not exist.
    IsADirectoryError
        If data_file is not a file.
    ValueError
        If data_file extension is not .csv file.

    """
    try:
        exceptions.file_checks(data_file, ".csv")
    except (FileNotFoundError, IsADirectoryError, TypeError, ValueError):
        raise

    data = pd.read_csv(data_file)
    return data

read_toml_configuration(config_file)

Reads a .TOML configuration file and returns contents.

The function adds the base_dir variable to any dir variable.

Parameters:

Name Type Description Default
config_file str

Path to the configuration file.

required

Returns:

Name Type Description
config dict

Configuration contents as a dictionary.

Raises:

Type Description
TypeError

If config_file is not a str.

FileNotFoundError

If config_file does not exist.

IsADirectoryError

If config_file is not a file.

ValueError

If data_file extension is not .csv file.

TOMLDecodeError

If the file was not read properly.

Source code in src/medpipe/utils/io.py
def read_toml_configuration(config_file: str) -> dict:
    """
    Reads a .TOML configuration file and returns contents.

    The function adds the base_dir variable to any dir variable.

    Parameters
    ----------
    config_file
        Path to the configuration file.

    Returns
    -------
    config : dict
        Configuration contents as a dictionary.

    Raises
    ------
    TypeError
        If config_file is not a str.
    FileNotFoundError
        If config_file does not exist.
    IsADirectoryError
        If config_file is not a file.
    ValueError
        If data_file extension is not .csv file.
    tomllib.TOMLDecodeError
        If the file was not read properly.

    """
    try:
        exceptions.file_checks(config_file, ".toml")
    except (FileNotFoundError, IsADirectoryError, TypeError, ValueError):
        raise

    with open(config_file, "rb") as file:
        config = tomllib.load(file)

    # Add base_dir to dir parameters
    if "base_dir" in config.keys():
        if "log_dir" in config.keys():
            config["log_dir"] = config["base_dir"] + config["log_dir"]

        for key, item in config.items():
            if type(item) is type(dict()) and "dir" in item.keys():
                # In a _parameters dictionary
                config[key]["dir"] = config["base_dir"] + config[key]["dir"]

    return config

medpipe.utils.exceptions

Execption functions module.

This module provides functions for execption handling and raising.

Functions: - file_checks: Checks if the file is correct. - path_checks: Checks if the path is correct. - array_check: Checks for an array-like. - array_dim_check: Checks that the dimension of two arrays agree.

array_check(arr)

Checks that the input is an array-like.

Parameters:

Name Type Description Default
arr array - like

Array to check.

required

Returns:

Type Description
None

Nothing is returned.

Raises:

Type Description
TypeError

If arr is not an array-like.

Source code in src/medpipe/utils/exceptions.py
def array_check(arr) -> None:
    """
    Checks that the input is an array-like.

    Parameters
    ----------
    arr : array-like
        Array to check.

    Returns
    -------
    None
        Nothing is returned.

    Raises
    ------
    TypeError
        If arr is not an array-like.

    """
    if not is_list_like(arr):
        raise TypeError(f"arr should be an array-like but instead got {type(arr)}")

array_dim_check(arr1, arr2, dim=None)

Checks that the dimensions of the arrays match.

Parameters:

Name Type Description Default
arr1 array - like

First array.

required
arr2 array - like

Second array.

required
dim int or None

Dimension to compare. If None shape is used.

None

Returns:

Type Description
None

Nothing is returned.

Raises:

Type Description
TypeError

If dim is not an integer.

ValueError

If the arrays do not have the same dimensions.

Source code in src/medpipe/utils/exceptions.py
def array_dim_check(arr1, arr2, dim=None) -> None:
    """
    Checks that the dimensions of the arrays match.

    Parameters
    ----------
    arr1 : array-like
        First array.
    arr2 : array-like
        Second array.
    dim : int or None, default: None
        Dimension to compare. If None shape is used.

    Returns
    -------
    None
        Nothing is returned.

    Raises
    ------
    TypeError
        If dim is not an integer.
    ValueError
        If the arrays do not have the same dimensions.

    """
    # Check arrays
    array_check(arr1)
    array_check(arr2)

    if dim is None:
        if arr1.shape != arr2.shape:
            raise ValueError("The dimensions do not agree")
    else:
        if type(dim) is not int:
            raise TypeError("dim should be an integer")
        if arr1.shape[dim] != arr2.shape[dim]:
            raise ValueError(f"The {dim} axis does not agree")

file_checks(file, extension, exists=True)

Performs checks to ensure that a file and extension are correct.

Parameters:

Name Type Description Default
file str

File to check.

required
extension str

Extension of the file to check.

required
exists default: True

Flag to indicate if the file should exists.

True

Returns:

Type Description
None

Nothing is returned.

Raises:

Type Description
TypeError

If file is not a str.

FileNotFoundError

If file does not exist.

IsADirectoryError

If file is a directory.

ValueError

If file extension is not .extension file.

Source code in src/medpipe/utils/exceptions.py
def file_checks(file: str, extension: str, exists: bool = True) -> None:
    """
    Performs checks to ensure that a file and extension are correct.

    Parameters
    ----------
    file
        File to check.
    extension
        Extension of the file to check.
    exists : default: True
        Flag to indicate if the file should exists.

    Returns
    -------
    None
        Nothing is returned.

    Raises
    ------
    TypeError
        If file is not a str.
    FileNotFoundError
        If file does not exist.
    IsADirectoryError
        If file is a directory.
    ValueError
        If file extension is not .extension file.

    """
    if type(file) is not str:
        raise TypeError(f"{file} should be a string")

    path_object = pathlib.Path(file)  # Create a Path object

    path_checks(str(path_object.parent))

    if not path_object.exists() and exists:
        raise FileNotFoundError(f"{file} does not exist")

    if not path_object.is_file() and exists:
        raise IsADirectoryError(f"{file} should be a file")

    if path_object.suffix != extension:
        raise ValueError(f"{file} should be a {extension} file")

path_checks(path)

Performs checks to ensure that a path is correct and creates it if it does not exist.

Parameters:

Name Type Description Default
path str

Path to check.

required

Returns:

Type Description
None

Nothing is returned.

Raises:

Type Description
TypeError

If path is not a str.

FileNotFoundError

If path does not exist.

NotADirectoryError

If path is not a directory.

Source code in src/medpipe/utils/exceptions.py
def path_checks(path: str) -> None:
    """
    Performs checks to ensure that a path is correct and creates it
    if it does not exist.

    Parameters
    ----------
    path
        Path to check.

    Returns
    -------
    None
        Nothing is returned.

    Raises
    ------
    TypeError
        If path is not a str.
    FileNotFoundError
        If path does not exist.
    NotADirectoryError
        If path is not a directory.

    """
    if type(path) is not str:
        raise TypeError(f"{path} should be a string")

    path_object = pathlib.Path(path)  # Create a Path object
    path_suffix = path_object.suffix
    dir = False

    if path_suffix != "":
        try:
            # If suffix ends with a digit because of version number
            int(path_suffix[1:])
            dir = True
        except ValueError:
            pass
    else:
        # If there is no suffix
        dir = True

    if not path_object.exists() and dir:
        path_object.mkdir(parents=True)

    if not path_object.exists():
        raise FileNotFoundError(f"{path} does not exist")

    if not path_object.is_dir():
        raise NotADirectoryError(f"{path} should be a directory")

medpipe.utils.config

Configuration utilities module.

This module provides helper functions for reading configuration files.

Functions: - get_file_path: Gets a file path from a configuration dictionary. - get_configuration: Gets the configuration by chaining .toml configurations. - parse_version_number: Function that parses a version number. - split_version_number: Splits a version number into the data and model version numbers.

get_configuration(parameters, v_number)

Gets the configuration by chaining .toml configurations.

Parameters:

Name Type Description Default
parameters dict

Parameters for the configuration chaining.

required
v_number str

Version number of the data to recuperate.

required

Returns:

Name Type Description
config_dict dict

Configuration parameters dictionary.

Raises:

Type Description
TypeError

If parameters is not a dict.

Source code in src/medpipe/utils/config.py
def get_configuration(parameters: dict, v_number: str) -> dict:
    """
    Gets the configuration by chaining .toml configurations.

    Parameters
    ----------
    parameters
        Parameters for the configuration chaining.
    v_number
        Version number of the data to recuperate.

    Returns
    -------
    config_dict : dict
        Configuration parameters dictionary.

    Raises
    ------
    TypeError
        If parameters is not a dict.

    """
    if type(parameters) is not type(dict()):
        raise TypeError(f"parameters should be a dict, but got f{type(parameters)}")

    config_dict = {}  # Create empty configuration dictionary
    path = parameters["dir"]
    v_list = parse_version_number(v_number)

    for i, folder in enumerate(parameters["subfolders"]):
        if folder[-1] != "/":
            folder += "/"
        file_path = (
            path
            + folder
            + parameters["name"]
            + folder[:-1]
            + f"-v{v_list[i]}"
            + parameters["extension"]
        )
        config_dict.update(read_toml_configuration(file_path))

    return config_dict

get_file_path(config_dict, v_number='', path_type='io', exists=True)

Gets the path to a file from a configuration dictionary.

If the path_type is "fig", the extension is removed.

Parameters:

Name Type Description Default
config_dict dict

Dictionary from a loaded .TOML file.

required
v_number default: ""

Version number.

''
path_type (io, db, data, fig)

Path type in the configuration file.

"io"
exists default: True

Flag to indicate if the file should exists.

True

Returns:

Name Type Description
file_path str

Path to the file.

Source code in src/medpipe/utils/config.py
def get_file_path(
    config_dict: dict, v_number: str = "", path_type: str = "io", exists: bool = True
) -> str:
    """
    Gets the path to a file from a configuration dictionary.

    If the path_type is "fig", the extension is removed.

    Parameters
    ----------
    config_dict
        Dictionary from a loaded .TOML file.
    v_number : default: ""
        Version number.
    path_type : {"io", "db", "data", "fig"}, default: "io"
        Path type in the configuration file.
    exists : default: True
        Flag to indicate if the file should exists.

    Returns
    -------
    file_path : str
        Path to the file.

    """
    if type(config_dict) is not type(dict()):
        raise TypeError(
            f"config_dict should be a dictionary, but got {type(config_dict)}"
        )
    if type(path_type) is not type(""):
        raise TypeError(f"path_type should be a str, but got {type(path_type)}")

    if path_type not in ["io", "db", "data", "fig"]:
        raise ValueError(f"path_type should be io, db, or data, but got {path_type}")

    key = path_type + "_parameters"
    if key not in config_dict.keys():
        raise KeyError(f"config_dict should have a {key} key")

    parameters = config_dict[key]

    if path_type == "fig":
        # Create a fig folder for each version number
        file_path = (
            parameters["dir"]
            + f"{v_number}/"
            + parameters["name"]
            + v_number
            + parameters["extension"]
        )
    else:
        file_path = (
            parameters["dir"] + parameters["name"] + v_number + parameters["extension"]
        )

    # Run file checks before returning
    file_checks(file_path, parameters["extension"], exists=exists)

    if path_type == "fig":  # If figure remove extension
        return file_path[: -len(parameters["extension"])]

    return file_path

parse_version_number(v_number)

Parses a version number.

Expecting a version number in the format vX.Y.Z.

Parameters:

Name Type Description Default
v_number str

Version number to parse.

required

Returns:

Name Type Description
v_list list[str]

List containing [source, extraction, preprocessing] numbers.

Raises:

Type Description
TypeError

If v_number is not a string.

Source code in src/medpipe/utils/config.py
def parse_version_number(v_number: str) -> list[str]:
    """
    Parses a version number.

    Expecting a version number in the format vX.Y.Z.

    Parameters
    ----------
    v_number
        Version number to parse.

    Returns
    -------
    v_list : list[str]
        List containing [source, extraction, preprocessing] numbers.

    Raises
    ------
    TypeError
        If v_number is not a string.

    """
    if type(v_number) is not type(""):
        raise TypeError(f"v_number should be a string, but got {type(v_number)}")

    if v_number[0] == "v":
        # Remove v prefix if present
        v_number = v_number[1:]

    return v_number.split(".")

split_version_number(v_number)

Splits a version number into the data and model version numbers.

Expecting a version number in the format vX.Y.Z-nN, where X.Y.Z is the data version number and nN is the model version number.

Parameters:

Name Type Description Default
v_number str

Data version number to split.

required

Returns:

Name Type Description
data_v_number str

Data version number in the format vX.Y.Z.

model_v_number str

Model version number in the format vnN.

Raises:

Type Description
TypeError

If v_number is not a string.

ValueError

If v_number format is incorrect.

Source code in src/medpipe/utils/config.py
def split_version_number(v_number: str):
    """
    Splits a version number into the data and model version numbers.

    Expecting a version number in the format vX.Y.Z-nN, where X.Y.Z is the
    data version number and nN is the model version number.

    Parameters
    ----------
    v_number
        Data version number to split.

    Returns
    -------
    data_v_number : str
        Data version number in the format vX.Y.Z.
    model_v_number : str
        Model version number in the format vnN.

    Raises
    ------
    TypeError
        If v_number is not a string.
    ValueError
        If v_number format is incorrect.

    """
    if type(v_number) is not type(""):
        raise TypeError(f"v_number should be a string, but got {type(v_number)}")

    if "-" not in v_number:
        raise ValueError(
            f"Incorrect version number format, expecting vX.Y.Z-nN but got {v_number}"
        )

    data_v_number, model_v_number = v_number.split("-")  # Split at the - sign

    if data_v_number[0] != "v":
        # Add v in case version number does not have one
        data_v_number = "v" + data_v_number

    return data_v_number, "v" + model_v_number