summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2009-05-05 08:54:11 (GMT)
committerGeorg Brandl <georg@python.org>2009-05-05 08:54:11 (GMT)
commit4d4313d59dc0020fd9cd913e020de88b98f0ba50 (patch)
tree4a96df4e750f1eb680d694a43d2ff4317bf9de7b
parente3869c41f289126df4927a0bca97b3aa118f49d8 (diff)
downloadcpython-4d4313d59dc0020fd9cd913e020de88b98f0ba50.zip
cpython-4d4313d59dc0020fd9cd913e020de88b98f0ba50.tar.gz
cpython-4d4313d59dc0020fd9cd913e020de88b98f0ba50.tar.bz2
#5142: add module skipping feature to pdb.
-rw-r--r--Doc/library/pdb.rst53
-rw-r--r--Lib/bdb.py13
-rwxr-xr-xLib/pdb.py4
-rw-r--r--Lib/test/test_pdb.py99
-rw-r--r--Misc/NEWS2
5 files changed, 164 insertions, 7 deletions
diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst
index cfc219c..99dea6d 100644
--- a/Doc/library/pdb.rst
+++ b/Doc/library/pdb.rst
@@ -1,4 +1,3 @@
-
.. _debugger:
:mod:`pdb` --- The Python Debugger
@@ -53,7 +52,16 @@ useful than quitting the debugger upon program's exit.
.. 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 @@ Typical usage to inspect a crashed program is::
-> 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 @@ slightly different way:
.. 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 @@ run [*args* ...]
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.
diff --git a/Lib/bdb.py b/Lib/bdb.py
index f29fa46..6d6d419 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -1,5 +1,6 @@
"""Debugger basics"""
+import fnmatch
import sys
import os
import types
@@ -19,7 +20,8 @@ class Bdb:
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 @@ class Bdb:
# 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:
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 2f42b31..2ff265c 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -58,8 +58,8 @@ line_prefix = '\n-> ' # Probably a better default
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
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
new file mode 100644
index 0000000..68a7702
--- /dev/null
+++ b/Lib/test/test_pdb.py
@@ -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()
diff --git a/Misc/NEWS b/Misc/NEWS
index 4efa003..0152d9a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -273,6 +273,8 @@ Core and Builtins
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.