import itertools


def is_valid_luhn(s):
    """Check whether a string is valid according to the Luhn algorithm.

    The `Luhn algorithm
    <https://en.wikipedia.org/wiki/Luhn_algorithm>`_ is used to validate
    a variety of identification numbers, e.g. credit card numbers.

    The string must not contain any separators; only the characters ``0-9``
    are allowed.

    :param str s: the string
    :return: ``True`` if the string is valid
    :rtype: bool
    :raise ValueError: if a character is not allowed
    """
    if not s.isdecimal():
        raise ValueError('only characters 0-9 are allowed')
    return sum(sum(divmod(int(c) * w, 10))
               for c, w in zip(s[::-1], itertools.cycle((1, 2)))) % 10 == 0