testmod_literate

The module docstring should give a concise description of the working, details are in the literate source so the docstrings are not bloated:

"""
This is the "testmod_literate" module.

It supplies one function, `factorial()`.  For example,

>>> factorial(5)
120

"""

__docformat__ = 'restructuredtext'

Beware: as the docstring is not parsed as separate unit but as part of the file, there must be a blank line also after the last doctest block. Otherwise doctest expects """ to be part of the output.

factorial

The functions docstring can be kept concise and additional discussion referred to the text part of the literate source:

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

    Factorials of floats are OK, but the float must be an exact integer:

    >>> factorial(30.0)
    265252859812191058636308480000000

    """

    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

Discussion and test

factorial() accepts input as int, long or float:

>>> factorial(30)
265252859812191058636308480000000
>>> factorial(30.0)
265252859812191058636308480000000

However, the float must be an exact integer and it must also not be ridiculously large:

>>> factorial(30.1)
Traceback (most recent call last):
    ...
ValueError: n must be exact integer
>>> factorial(1e100)
Traceback (most recent call last):
    ...
OverflowError: n too large

The factorial of negative values is not defined:

>>> factorial(-1)
Traceback (most recent call last):
    ...
ValueError: n must be >= 0

The type of the return value depends on the size of the result.

If the result is small enough to fit in an int, return an int. Else return a long:

>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000

Self Test

The traditional test function parses the docstrings of all objects in this module. It misses doctests in comments:

def _test():
    import doctest
    doctest.testmod()

Test all doctest blocks (both in docstrings and in text parts (well formatted comments) if the module is called as __main__ (i.e. from the command line):

def _test_all_doctests():
    import pylit, sys
    pylit.run_doctest(infile=sys.argv[0], txt2code=False,
                      globs=sys.modules.get('__main__').__dict__)

(Future versions of pylit might contain a convenience function for a simpler invocation of this test.)

Doctests can still be disabled or commented - make sure they are not recognised as text block (no double colon here):

# a silly doctest # >>> False # True

or (with non-canonical comments):

# a silly doctest
#>>> False
#True

Doctests in doc-strings can be skipped with the strip option:

def _test_text_doctests():
    import pylit, sys
    pylit.run_doctest(infile=sys.argv[0], txt2code=False, strip=True,
                      globs=sys.modules.get('__main__').__dict__)

Do a self test:

if __name__ == "__main__":
    #_test()
    _test_all_doctests()