..  #!/usr/bin/env python
  # -*- coding: iso-8859-1 -*-

:Date:      $Date$
:Version:   SVN-Revision $Revision$
:URL:       $URL:  $
:Copyright: 2006 Guenter Milde.
            Released without any warranty under the terms of the
            GNU General Public License (v. 2 or later)

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)
      265252859812191058636308480000000L

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

      >>> factorial(30.0)
      265252859812191058636308480000000L

      """

      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)
      265252859812191058636308480000000L
      >>> factorial(30L)
      265252859812191058636308480000000L
      >>> factorial(30.0)
      265252859812191058636308480000000L

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(long(n)) for n in range(6)]
      [1, 1, 2, 6, 24, 120]
      >>> factorial(30)
      265252859812191058636308480000000L
      >>> factorial(30L)
      265252859812191058636308480000000L


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()
