import random


def next_unused_name_in_group(grp, length):
    """ Gives a name that isn't used in a Group.

    Generates a name of the desired length that is not a Dataset or
    Group in the given group. Note, if length is not large enough and
    `grp` is full enough, there may be no available names meaning that
    this function will hang.

    Parameters
    ----------
    grp : h5py.Group or h5py.File
        The HDF5 Group (or File if at '/') to generate an unused name
        in.
    length : int
        Number of characters the name should be.

    Returns
    -------
    name : str
        A name that isn't already an existing Dataset or Group in
        `grp`.

    """
    # While
    #
    # ltrs = string.ascii_letters + string.digits
    # name = ''.join([random.choice(ltrs) for i in range(length)])
    #
    # seems intuitive, its performance is abysmal compared to
    #
    # '%0{0}x'.format(length) % random.getrandbits(length * 4)
    #
    # The difference is a factor of 20. Idea from
    #
    # https://stackoverflow.com/questions/2782229/most-lightweight-way-
    #   to-create-a-random-string-and-a-random-hexadecimal-number/
    #   35161595#35161595
    fmt = '%0{0}x'.format(length)
    name = fmt % random.getrandbits(length * 4)
    while name in grp:
        name = fmt % random.getrandbits(length * 4)
    return name