Convert a tuple into a range but pass ranges through silently.

    This is useful to ensure that input is a range so that attributes may
    be accessed with `.start`, `.stop` or so that containment checks are
    constant time.

    Parameters
    ----------
    tup_or_range : tuple or range
        A tuple to pass to from_tuple or a range to return.

    Returns
    -------
    range : range
        The input to convert to a range.

    Raises
    ------
    ValueError
        Raised when the input is not a tuple or a range. ValueError is also
        raised if the input is a tuple whose length is not 2 or 3.

def maybe_from_tuple(tup_or_range):
    """Convert a tuple into a range but pass ranges through silently.

    This is useful to ensure that input is a range so that attributes may
    be accessed with `.start`, `.stop` or so that containment checks are
    constant time.

    Parameters
    ----------
    tup_or_range : tuple or range
        A tuple to pass to from_tuple or a range to return.

    Returns
    -------
    range : range
        The input to convert to a range.

    Raises
    ------
    ValueError
        Raised when the input is not a tuple or a range. ValueError is also
        raised if the input is a tuple whose length is not 2 or 3.
    """
    if isinstance(tup_or_range, tuple):
        return from_tuple(tup_or_range)
    elif isinstance(tup_or_range, range):
        return tup_or_range

    raise ValueError(
        'maybe_from_tuple expects a tuple or range, got %r: %r' % (
            type(tup_or_range).__name__,
            tup_or_range,
        ),
    )