def METHOD_NAME(element_metric):
    """
    Return a batchwise metric function from an elementwise metric function
    """
    @functools.wraps(element_metric)
    def wrapper(x_batch, x_adv_batch, **kwargs):
        x_batch = list(x_batch)
        x_adv_batch = list(x_adv_batch)
        if len(x_batch) != len(x_adv_batch):
            raise ValueError(
                f"len(a_batch) {len(x_batch)} != len(b_batch) {len(x_adv_batch)}"
            )
        y = []
        for x, x_adv in zip(x_batch, x_adv_batch):
            y.append(element_metric(x, x_adv, **kwargs))
        try:
            y = np.array(y)
        except ValueError:
            # Handle ragged arrays
            y = np.array(y, dtype=object)
        return y
    if wrapper.__doc__ is None:
        log.warning(f"{element_metric.__name__} has no doc string")
        wrapper.__doc__ = ""
    wrapper.__doc__ = "Batch version of:\n" + wrapper.__doc__
    wrapper.__name__ = "batch_" + wrapper.__name__
    # note: repr(wrapper) defaults to the element_metric, not __name__
    # See: https://stackoverflow.com/questions/10875442/possible-to-change-a-functions-repr-in-python
    return wrapper