from __future__ import annotations

import errno
import os
import sys

from enum import Enum
from typing import Any


class FileType(Enum):
    """File type."""
    ANY = 0
    FILE = 1
    DIR = 2


class ProgramExit(Exception):
    """Raise to express the will to exit from the program."""
    pass


def raise_exit(message: str | None = None) -> None:
    """Raise a ProgramExit with the specified message."""
    raise ProgramExit(message)


def raise_ioerror(err_no: int, path: str | None = None, message: str | None = None) -> None:
    """Raise an IOError with an auto-generated message based on err_no."""
    if not message:
        message = os.strerror(err_no) + '.'

    if path:
        message += ' Path: ' + path

    e = IOError(message)
    e.errno = err_no

    raise e


def raise_not_found(path: str | None = None, message: str | None = None) -> None:
    """Raise a 'file not found' exception."""
    raise_ioerror(errno.ENOENT, path, message)


def raise_if_none(**kwargs: Any) -> None:
    """Raise exception if any of the args is None."""
    for key in kwargs:
        if kwargs[key] is None:
            raise ValueError('Illegal "None" value for: ' + key)


def raise_if_falsy(**kwargs: Any) -> None:
    """Raise exception if any of the args is falsy."""
    for key in kwargs:
        value = kwargs[key]
        if not value:
            if value is None:
                adj = '"None"'
            elif value == 0:
                adj = 'zero'
            else:
                adj = 'empty'
            raise ValueError(f'Illegal {adj} value for: {key}')


def raise_if_not_found(path: str, file_type: FileType = FileType.ANY) -> None:
    """Raise exception if the specified file does not exist."""
    raise_if_falsy(path=path)

    if file_type == FileType.FILE:
        test_func = os.path.isfile
    elif file_type == FileType.DIR:
        test_func = os.path.isdir
    else:
        test_func = os.path.exists

    if not test_func(path):
        raise_not_found(path)


def raise_if_exists(path: str) -> None:
    """Raise exception if a file already exists at a given path."""
    raise_if_falsy(path=path)
    if os.path.exists(path):
        raise_ioerror(errno.EEXIST, path)


def raise_if_not_root() -> None:
    """Raise exception if the effective user is not root."""
    if os.geteuid() != 0:
        raise_ioerror(errno.EPERM, message='This operation requires root privileges.')


def re_raise_new_message(exception: Exception, message: str) -> None:
    """Re-raise exception with a new message."""
    raise type(exception)(message).with_traceback(sys.exc_info()[2])

from __future__ import annotations

import errno
import os
import sys

from enum import Enum
from typing import Any


class FileType(Enum):
    """File type."""
    ANY = 0
    FILE = 1
    DIR = 2


class ProgramExit(Exception):
    """Raise to express the will to exit from the program."""
    pass


def raise_exit(message: str | None = None) -> None:
    """Raise a ProgramExit with the specified message."""
    raise ProgramExit(message)


def raise_ioerror(err_no: int, path: str | None = None, message: str | None = None) -> None:
    """Raise an IOError with an auto-generated message based on err_no."""
    if not message:
        message = os.strerror(err_no) + '.'

    if path:
        message += ' Path: ' + path

    e = IOError(message)
    e.errno = err_no

    raise e


def raise_not_found(path: str | None = None, message: str | None = None) -> None:
    """Raise a 'file not found' exception."""
    raise_ioerror(errno.ENOENT, path, message)


def raise_if_none(**kwargs: Any) -> None:
    """Raise exception if any of the args is None."""
    for key in kwargs:
        if kwargs[key] is None:
            raise ValueError('Illegal "None" value for: ' + key)


def raise_if_falsy(**kwargs: Any) -> None:
    """Raise exception if any of the args is falsy."""
    for key in kwargs:
        value = kwargs[key]
        if not value:
            if value is None:
                adj = '"None"'
            elif value == 0:
                adj = 'zero'
            else:
                adj = 'empty'
            raise ValueError(f'Illegal {adj} value for: {key}')


def raise_if_not_found(path: str, file_type: FileType = FileType.ANY) -> None:
    """Raise exception if the specified file does not exist."""
    raise_if_falsy(path=path)

    if file_type == FileType.FILE:
        test_func = os.path.isfile
    elif file_type == FileType.DIR:
        test_func = os.path.isdir
    else:
        test_func = os.path.exists

    if not test_func(path):
        raise_not_found(path)


def raise_if_exists(path: str) -> None:
    """Raise exception if a file already exists at a given path."""
    raise_if_falsy(path=path)
    if os.path.exists(path):
        raise_ioerror(errno.EEXIST, path)


def raise_if_not_root() -> None:
    """Raise exception if the effective user is not root."""
    if os.geteuid() != 0:
        raise_ioerror(errno.EPERM, message='This operation requires root privileges.')


def re_raise_new_message(exception: Exception, message: str) -> None:
    """Re-raise exception with a new message."""
    raise type(exception)(message).with_traceback(sys.exc_info()[2])

File type. Raise to express the will to exit from the program. Raise a ProgramExit with the specified message. Raise an IOError with an auto-generated message based on err_no. Raise a 'file not found' exception. Raise exception if any of the args is None. Raise exception if any of the args is falsy. Raise exception if the specified file does not exist. Raise exception if a file already exists at a given path. Raise exception if the effective user is not root. Re-raise exception with a new message.