Generator of prime numbers using the sieve of Eratosthenes.

    Args:
        p_min (int): prime numbers lower than p_min will not be in the resulting primes
        p_max (int): the generator will stop when this value is reached, it means that there
            will be no prime bigger than this number in the resulting primes. If p_max
            is None, there will not be any upper limit

    Returns:
        A generator of all the consecutive primes between p_min and p_max

    Raises:
        TypeError: if p_min or p_max is not an integer

def prime_generator(p_min=2, p_max=None):

    """ Generator of prime numbers using the sieve of Eratosthenes.

    Args:
        p_min (int): prime numbers lower than p_min will not be in the resulting primes
        p_max (int): the generator will stop when this value is reached, it means that there
            will be no prime bigger than this number in the resulting primes. If p_max
            is None, there will not be any upper limit

    Returns:
        A generator of all the consecutive primes between p_min and p_max

    Raises:
        TypeError: if p_min or p_max is not an integer

    """

    if not isinstance(p_min, int):
        raise TypeError("Expecting an integer")
    if p_max is not None and not isinstance(p_max, int):
        raise TypeError("Expecting an integer")

    q = max(p_min, 3)
    if q % 2 == 0:
        q += 1
    if p_min <= 2 and (p_max is None or p_max >= 2):
        yield 2  # outside the while block to make the double increment optimization work

    while p_max is None or q <= p_max:
        if is_prime(q):
            yield q
        q += 2