[Python-checkins] r72322 - in python/trunk: Doc/library/pdb.rst Lib/bdb.py Lib/pdb.py Lib/test/test_pdb.py Misc/NEWS

georg.brandl python-checkins at python.org
Tue May 5 10:54:11 CEST 2009


Author: georg.brandl
Date: Tue May  5 10:54:11 2009
New Revision: 72322

Log:
#5142: add module skipping feature to pdb.

Added:
   python/trunk/Lib/test/test_pdb.py   (contents, props changed)
Modified:
   python/trunk/Doc/library/pdb.rst
   python/trunk/Lib/bdb.py
   python/trunk/Lib/pdb.py
   python/trunk/Misc/NEWS

Modified: python/trunk/Doc/library/pdb.rst
==============================================================================
--- python/trunk/Doc/library/pdb.rst	(original)
+++ python/trunk/Doc/library/pdb.rst	Tue May  5 10:54:11 2009
@@ -1,4 +1,3 @@
-
 .. _debugger:
 
 :mod:`pdb` --- The Python Debugger
@@ -53,7 +52,16 @@
 .. versionadded:: 2.4
    Restarting post-mortem behavior added.
 
-Typical usage to inspect a crashed program is::
+The typical usage to break into the debugger from a running program is to
+insert ::
+
+   import pdb; pdb.set_trace()
+
+at the location you want to break into the debugger.  You can then step through
+the code following this statement, and continue running without debugger using
+the ``c`` command.
+
+The typical usage to inspect a crashed program is::
 
    >>> import pdb
    >>> import mymodule
@@ -70,10 +78,10 @@
    -> print spam
    (Pdb)
 
+
 The module defines the following functions; each enters the debugger in a
 slightly different way:
 
-
 .. function:: run(statement[, globals[, locals]])
 
    Execute the *statement* (given as a string) under debugger control.  The
@@ -117,7 +125,38 @@
 
 .. function:: pm()
 
-   Enter post-mortem debugging of the traceback found in ``sys.last_traceback``.
+   Enter post-mortem debugging of the traceback found in
+   :data:`sys.last_traceback`.
+
+
+The ``run_*`` functions and :func:`set_trace` are aliases for instantiating the
+:class:`Pdb` class and calling the method of the same name.  If you want to
+access further features, you have to do this yourself:
+
+.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None)
+
+   :class:`Pdb` is the debugger class.
+
+   The *completekey*, *stdin* and *stdout* arguments are passed to the
+   underlying :class:`cmd.Cmd` class; see the description there.
+
+   The *skip* argument, if given, must be an iterable of glob-style module name
+   patterns.  The debugger will not step into frames that originate in a module
+   that matches one of these patterns. [1]_
+
+   Example call to enable tracing with *skip*::
+
+      import pdb; pdb.Pdb(skip=['django.*']).set_trace()
+
+   .. versionadded:: 2.7
+      The *skip* argument.
+
+   .. method:: run(statement[, globals[, locals]])
+               runeval(expression[, globals[, locals]])
+               runcall(function[, argument, ...])
+               set_trace()
+
+      See the documentation for the functions explained above.
 
 
 .. _debugger-commands:
@@ -351,3 +390,9 @@
 
 q(uit)
    Quit from the debugger. The program being executed is aborted.
+
+
+.. rubric:: Footnotes
+
+.. [1] Whether a frame is considered to originate in a certain module
+       is determined by the ``__name__`` in the frame globals.

Modified: python/trunk/Lib/bdb.py
==============================================================================
--- python/trunk/Lib/bdb.py	(original)
+++ python/trunk/Lib/bdb.py	Tue May  5 10:54:11 2009
@@ -1,5 +1,6 @@
 """Debugger basics"""
 
+import fnmatch
 import sys
 import os
 import types
@@ -19,7 +20,8 @@
     The standard debugger class (pdb.Pdb) is an example.
     """
 
-    def __init__(self):
+    def __init__(self, skip=None):
+        self.skip = set(skip) if skip else None
         self.breaks = {}
         self.fncache = {}
 
@@ -94,9 +96,18 @@
     # methods, but they may if they want to redefine the
     # definition of stopping and breakpoints.
 
+    def is_skipped_module(self, module_name):
+        for pattern in self.skip:
+            if fnmatch.fnmatch(module_name, pattern):
+                return True
+        return False
+
     def stop_here(self, frame):
         # (CT) stopframe may now also be None, see dispatch_call.
         # (CT) the former test for None is therefore removed from here.
+        if self.skip and \
+               self.is_skipped_module(frame.f_globals.get('__name__')):
+            return False
         if frame is self.stopframe:
             return frame.f_lineno >= self.stoplineno
         while frame is not None and frame is not self.stopframe:

Modified: python/trunk/Lib/pdb.py
==============================================================================
--- python/trunk/Lib/pdb.py	(original)
+++ python/trunk/Lib/pdb.py	Tue May  5 10:54:11 2009
@@ -58,8 +58,8 @@
 
 class Pdb(bdb.Bdb, cmd.Cmd):
 
-    def __init__(self, completekey='tab', stdin=None, stdout=None):
-        bdb.Bdb.__init__(self)
+    def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
+        bdb.Bdb.__init__(self, skip=skip)
         cmd.Cmd.__init__(self, completekey, stdin, stdout)
         if stdout:
             self.use_rawinput = 0

Added: python/trunk/Lib/test/test_pdb.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/test/test_pdb.py	Tue May  5 10:54:11 2009
@@ -0,0 +1,99 @@
+# A test suite for pdb; at the moment, this only validates skipping of
+# specified test modules (RFE #5142).
+
+import imp
+import os
+import sys
+import doctest
+import tempfile
+
+from test import test_support
+# This little helper class is essential for testing pdb under doctest.
+from test_doctest import _FakeInput
+
+
+def test_pdb_skip_modules():
+    """This illustrates the simple case of module skipping.
+
+    >>> def skip_module():
+    ...     import string
+    ...     import pdb;pdb.Pdb(skip=['string*']).set_trace()
+    ...     string.lower('FOO')
+    >>> real_stdin = sys.stdin
+    >>> sys.stdin = _FakeInput([
+    ...    'step',
+    ...    'continue',
+    ...    ])
+
+    >>> try:
+    ...     skip_module()
+    ... finally:
+    ...     sys.stdin = real_stdin
+    > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()
+    -> string.lower('FOO')
+    (Pdb) step
+    --Return--
+    > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None
+    -> string.lower('FOO')
+    (Pdb) continue
+"""
+
+
+# Module for testing skipping of module that makes a callback
+mod = imp.new_module('module_to_skip')
+exec 'def foo_pony(callback): x = 1; callback(); return None' in mod.__dict__
+
+
+def test_pdb_skip_modules_with_callback():
+    """This illustrates skipping of modules that call into other code.
+
+    >>> def skip_module():
+    ...     def callback():
+    ...         return None
+    ...     import pdb;pdb.Pdb(skip=['module_to_skip*']).set_trace()
+    ...     mod.foo_pony(callback)
+    >>> real_stdin = sys.stdin
+    >>> sys.stdin = _FakeInput([
+    ...    'step',
+    ...    'step',
+    ...    'step',
+    ...    'step',
+    ...    'step',
+    ...    'continue',
+    ...    ])
+
+    >>> try:
+    ...     skip_module()
+    ... finally:
+    ...     sys.stdin = real_stdin
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()
+    -> mod.foo_pony(callback)
+    (Pdb) step
+    --Call--
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(2)callback()
+    -> def callback():
+    (Pdb) step
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()
+    -> return None
+    (Pdb) step
+    --Return--
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()->None
+    -> return None
+    (Pdb) step
+    --Return--
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None
+    -> mod.foo_pony(callback)
+    (Pdb) step
+    > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[3]>(4)<module>()
+    -> sys.stdin = real_stdin
+    (Pdb) continue
+"""
+
+
+def test_main():
+    from test import test_pdb
+    test_support.run_doctest(test_pdb, verbosity=True)
+
+
+if __name__ == '__main__':
+    test_main()

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Tue May  5 10:54:11 2009
@@ -273,6 +273,8 @@
 Library
 -------
 
+- Issue #5142: Add the ability to skip modules while stepping to pdb.
+
 - Issue #1309567: Fix linecache behavior of stripping subdirectories when
   looking for files given by a relative filename.
 


More information about the Python-checkins mailing list