<gh_stars>0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Documentation for the whole module.
We can place tests even here.

>>> echo(10)
10
"""


def echo(value):
    """
    Returns the given argument.
    :param value: argument to be returned
    :return: the given argument

    >>> echo(0)
    0

    >>> [echo(x) for x in range(3)]
    [0, 1, 2]
    """
    return value


def bad_echo(value):
    """
    Badly implemented echo method.
    :param value:
    :return:

    >>> bad_echo(5)
    5
    """
    return 0


def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()
