from typing import Union


def astuple(i, argname: Union[str, None]) -> tuple:
    """
    Converts iterables (except strings) into a tuple.

    :param argname:
        If string, it's used in the exception raised when `i` not an iterable.
        If `None`, wraps non-iterables in a single-item tuple, and no exception
        is ever raised.
    """
    if not i:
        return ()

    if isinstance(i, str):
        i = (i,)
    else:
        try:
            i = tuple(i)
        except Exception as ex:
            if argname is None:
                return (i,)
            raise ValueError(
                f"Cannot tuple-ize {argname}({i!r}) due to: {ex}"
            ) from None

    return i