# Buggy code
def resolve_inout(input=None, output=None, files=None, overwrite=False):
    """Resolves inputs and outputs from standard args and options.

    :param input: a single input filename, optional.
    :param output: a single output filename, optional.
    :param files: a sequence of filenames in which the last is the
        output filename.
    :param overwrite: whether to force overwriting the output
        file, bool.
    :return: the resolved output filename and input filenames as a
        tuple of length 2.

    If provided, the :param:`output` file may be overwritten. An output
    file extracted from :param:`files` will not be overwritten unless
    :param:`overwrite` is `True`.
    """
    resolved_output = output or (files[-1] if files else None)
    if not overwrite and resolved_output and os.path.exists(resolved_output):
        raise FileOverwriteError(
            "file exists and won't be overwritten without use of the "
            "`--overwrite` option."
        )
    resolved_inputs = (
        [input]
        if input
        else [] + list(files[: -1 if not output else None])
        if files
        else []
    )
    return resolved_output, resolved_inputs


# Traceback (IndexError)
$ rio convert --overwrite 20200829.tif
Traceback (most recent call last):
File "/usr/local/bin/rio", line 8, in <module>
sys.exit(main_group())
File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/rasterio/rio/convert.py", line 55, in convert
inputfile = files[0]
IndexError: list index out of range

# Fixed code
def resolve_inout(
    input=None, output=None, files=None, overwrite=False, num_inputs=None
):
    """Resolves inputs and outputs from standard args and options.

    Parameters
    ----------
    input : str
        A single input filename, optional.
    output : str
        A single output filename, optional.
    files : str
        A sequence of filenames in which the last is the output filename.
    overwrite : bool
        Whether to force overwriting the output file.
    num_inputs : int
        Raise exceptions if the number of resolved input files is higher
        or lower than this number.

    Returns
    -------
    tuple (str, list of str)
        The resolved output filename and input filenames as a tuple of
        length 2.

    If provided, the output file may be overwritten. An output
    file extracted from files will not be overwritten unless
    overwrite is True.

    Raises
    ------
    click.BadParameter

    """
    resolved_output = output or (files[-1] if files else None)

    if not overwrite and resolved_output and os.path.exists(resolved_output):
        raise FileOverwriteError(
            "file exists and won't be overwritten without use of the `--overwrite` option."
        )

    resolved_inputs = (
        [input]
        if input
        else [] + list(files[: -1 if not output else None])
        if files
        else []
    )

    if num_inputs is not None:
        if len(resolved_inputs) < num_inputs:
            raise click.BadParameter("Insufficient inputs")
        elif len(resolved_inputs) > num_inputs:
            raise click.BadParameter("Too many inputs")

    return resolved_output, resolved_inputs