From 05b05febad116b36df515825cf0646f41fdb6280 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Sun, 26 Sep 2004 05:09:59 +0000 Subject: [PATCH] Added a lot of new stuff to the debugging section. --- Doc/lib/libdoctest.tex | 188 ++++++++++++++++++++++++++++++++++------- 1 file changed, 159 insertions(+), 29 deletions(-) diff --git a/Doc/lib/libdoctest.tex b/Doc/lib/libdoctest.tex index 6ea4345d930..f9d6ba0057b 100644 --- a/Doc/lib/libdoctest.tex +++ b/Doc/lib/libdoctest.tex @@ -1547,34 +1547,174 @@ initialized by the constructor, and should not be modified directly. \subsection{Debugging\label{doctest-debugging}} -Doctest provides three mechanisms for debugging doctest examples: +Doctest provides several mechanisms for debugging doctest examples: -\begin{enumerate} -\item The \function{debug()} function converts a specified doctest - to a Python script, and executes that script using \module{pdb}. +\begin{itemize} +\item Several functions convert doctests to executable Python + programs, which can be run under the Python debugger, \refmodule{pdb}. \item The \class{DebugRunner} class is a subclass of \class{DocTestRunner} that raises an exception for the first failing example, containing information about that example. This information can be used to perform post-mortem debugging on the example. -\item The unittest cases generated by \function{DocTestSuite()} - support the \method{debug} method defined by +\item The \module{unittest} cases generated by \function{DocTestSuite()} + support the \method{debug()} method defined by \class{unittest.TestCase}. -\end{enumerate} +\item You can add a call to \function{pdb.set_trace()} in a doctest + example, and you'll drop into the Python debugger when that + line is executed. Then you can inspect current values of variables, + and so on. For example, suppose \file{a.py} contains just this + module docstring: -\begin{funcdesc}{debug}{module, name} - Debug a single doctest docstring. +\begin{verbatim} +""" +>>> def f(x): +... g(x*2) +>>> def g(x): +... print x+3 +... import pdb; pdb.set_trace() +>>> f(3) +9 +""" +\end{verbatim} - Provide the \var{module} (or dotted name of the module) containing - the docstring to be debugged and the fully qualified dotted - \var{name} of the object with the docstring to be debugged. + Then an interactive Python session may look like this: + +\begin{verbatim} +>>> import a, doctest +>>> doctest.testmod(a) +--Return-- +> (3)g()->None +-> import pdb; pdb.set_trace() +(Pdb) list + 1 def g(x): + 2 print x+3 + 3 -> import pdb; pdb.set_trace() +[EOF] +(Pdb) print x +6 +(Pdb) step +--Return-- +> (2)f()->None +-> g(x*2) +(Pdb) list + 1 def f(x): + 2 -> g(x*2) +[EOF] +(Pdb) print x +3 +(Pdb) step +--Return-- +> (1)?()->None +-> f(3) +(Pdb) cont +(0, 3) +>>> +\end{verbatim} + + \versionchanged[The ability to use \code{pdb.set_trace()} usefully + inside doctests was added]{2.4} +\end{itemize} + +Functions that convert doctests to Python code, and possibly run +the synthesized code under the debugger: + +\begin{funcdesc}{script_from_examples}{s} + Convert text with examples to a script. + + Argument \var{s} is a string containing doctest examples. The string + is converted to a Python script, where doctest examples in \var{s} + are converted to regular code, and everything else is converted to + Python comments. The generated script is returned as a string. + For example, given file \file{a.py} as above, + + \begin{verbatim} + >>> print doctest.script_from_examples(open("a.py").read()) + # """ + def f(x): + g(x*2) + def g(x): + print x+3 + import pdb; pdb.set_trace() + f(3) + # Expected: + ## 9 + ## """ + \end{verbatim} + + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{testsource}{module, name} + Convert the doctest for an object to a script. + + Argument \var{module} is a module object, or dotted name of a module, + containing the object whose doctests are of interest. Argument + \var{name} is the name (within the module) of the object with the + doctests of interest. The result is a string, containing the + object's docstring converted to a Python script, as described for + \function{script_from_examples()} above. For example, if module + \file{a.py} contains a top-level function \function{f()}, then + + \begin{verbatim} + import a, doctest + print doctest.testsource(a, "a.f") + \end{verbatim} + + prints a script version of function \function{f()}'s docstring, + with doctests converted to code, and the rest placed in comments. - The doctest examples are extracted (see function \function{testsource()}), - and written to a temporary file. The Python debugger, \refmodule{pdb}, - is then invoked on that file. \versionadded{2.3} \end{funcdesc} +\begin{funcdesc}{debug}{module, name\optional{, pm}} + Debug the doctests for an object. + + The \var{module} and \var{name} arguments are the same as for function + \function{testsource()} above. The synthesized Python script for the + named object's docstring is written to a temporary file, and then that + file is run under the control of the Python debugger, \refmodule{pdb}. + + A shallow copy of \code{\var{module}.__dict__} is used for both local + and global execution context. + + Optional argument \var{pm} controls whether post-mortem debugging is + used. If \var{pm} has a true value, the script file is run directly, + and the debugger gets involved only if the script terminates via raising + an unhandled exception. If it does, then post-mortem debugging is + invoked, via \code{pdb.post_mortem()}, passing the traceback object + from the unhandled exception. If \var{pm} is not specified, or is false, + the script is run under the debugger from the start, via passing an + appropriate \function{execfile()} call to \code{pdb.run()}. + + \versionadded{2.3} + + \versionchanged[The \var{pm} argument was added]{2.4} +\end{funcdesc} + +\begin{funcdesc}{debug_src}{src\optional{, pm}\optional{, globs}} + Debug the doctests in a string. + + This is like function \function{debug()} above, except that + a string containing doctest examples is specified directly, via + the \var{src} argument. + + Optional argument \var{pm} has the same meaning as in function + \function{debug()} above. + + Optional argument \var{globs} gives a dictionary to use as both + local and global execution context. If not specified, or \code{None}, + an empty dictionary is used. If specified, a shallow copy of the + dictionary is used. + + \versionadded{2.4} +\end{funcdesc} + +The \class{DebugRunner} class, and the special exceptions it may raise, +are of most interest to testing framework authors, and will only be +sketched here. See the source code, and especially \class{DebugRunner}'s +docstring (which is a doctest!) for more details: + \begin{classdesc}{DebugRunner}{\optional{checker}\optional{, verbose}\optional{, optionflags}} @@ -1591,6 +1731,9 @@ Doctest provides three mechanisms for debugging doctest examples: section~\ref{doctest-advanced-api}. \end{classdesc} +There are two exceptions that may be raised by \class{DebugRunner} +instances: + \begin{excclassdesc}{DocTestFailure}{test, example, got} An exception thrown by \class{DocTestRunner} to signal that a doctest example's actual output did not match its expected output. @@ -1608,20 +1751,7 @@ Doctest provides three mechanisms for debugging doctest examples: The example's actual output. \end{memberdesc} -\begin{funcdesc}{testsource}{module, name} - Extract the doctest examples from a docstring. - - Provide the \var{module} (or dotted name of the module) containing the - tests to be extracted and the \var{name} (within the module) of the object - with the docstring containing the tests to be extracted. - - The doctest examples are returned as a string containing Python - code. The expected output blocks in the examples are converted - to Python comments. - \versionadded{2.3} -\end{funcdesc} - -\begin{excclassdesc}{UnexpectedException}{test, example, got} +\begin{excclassdesc}{UnexpectedException}{test, example, exc_info} An exception thrown by \class{DocTestRunner} to signal that a doctest example raised an unexpected exception. The constructor arguments are used to initialize the member variables of the same