from typing import Union


def smallest_prime_divisor(num: int, bound: Union[int, None] = None) -> int:
    """
    Returns the smallest prime divisor of the input `num` if that divisor is
    at most `bound`. If none are found, this returns `num`.

    Input:
        num: a positive integer
        bound: an optional bound on the size of the primes to check. If not
               given, then it defaults to `num`.

    Output:
        The smallest prime divisor of `num`, or `num` itself if that divisor is
        at least as large as `bound`.

    Raises:
        ValueError: if num < 1.

    Examples:
    >>> smallest_prime_divisor(15)
    3
    >>> smallest_prime_divisor(1001)
    7
    """
    if num < 1:
        raise ValueError("A positive integer is expected.")
    if num == 1:
        return num
    for prime in [2, 3, 5]:
        if num % prime == 0:
            return prime
    if bound is None:
        bound = num
    # Possible prime locations mod 2*3*5=30
    diffs = [6, 4, 2, 4, 2, 4, 6, 2]
    cand = 7
    i = 1
    while cand <= bound and cand*cand <= num:
        if num % cand == 0:
            return cand
        cand += diffs[i]
        i = (i + 1) % 8
    return num