Remove doctest.testmod's deprecated (in 2.4) `isprivate`

argument.  A lot of hair went into supporting that!
This commit is contained in:
Tim Peters 2006-06-05 01:43:03 +00:00
parent 76a82e89ab
commit bf0400abe9
4 changed files with 25 additions and 133 deletions

View File

@ -952,7 +952,7 @@ sections \ref{doctest-simple-testmod} and
\begin{funcdesc}{testmod}{\optional{m}\optional{, name}\optional{, \begin{funcdesc}{testmod}{\optional{m}\optional{, name}\optional{,
globs}\optional{, verbose}\optional{, globs}\optional{, verbose}\optional{,
isprivate}\optional{, report}\optional{, report}\optional{,
optionflags}\optional{, extraglobs}\optional{, optionflags}\optional{, extraglobs}\optional{,
raise_on_error}\optional{, exclude_empty}} raise_on_error}\optional{, exclude_empty}}
@ -990,19 +990,14 @@ sections \ref{doctest-simple-testmod} and
for function \function{testfile()} above, except that \var{globs} for function \function{testfile()} above, except that \var{globs}
defaults to \code{\var{m}.__dict__}. defaults to \code{\var{m}.__dict__}.
Optional argument \var{isprivate} specifies a function used to
determine whether a name is private. The default function treats
all names as public. \var{isprivate} can be set to
\code{doctest.is_private} to skip over names that are
private according to Python's underscore naming convention.
\deprecated{2.4}{\var{isprivate} was a stupid idea -- don't use it.
If you need to skip tests based on name, filter the list returned by
\code{DocTestFinder.find()} instead.}
\versionchanged[The parameter \var{optionflags} was added]{2.3} \versionchanged[The parameter \var{optionflags} was added]{2.3}
\versionchanged[The parameters \var{extraglobs}, \var{raise_on_error} \versionchanged[The parameters \var{extraglobs}, \var{raise_on_error}
and \var{exclude_empty} were added]{2.4} and \var{exclude_empty} were added]{2.4}
\versionchanged[The optional argument \var{isprivate}, deprecated
in 2.4, was removed]{2.5}
\end{funcdesc} \end{funcdesc}
There's also a function to run the doctests associated with a single object. There's also a function to run the doctests associated with a single object.

View File

@ -63,7 +63,6 @@ __all__ = [
'REPORT_ONLY_FIRST_FAILURE', 'REPORT_ONLY_FIRST_FAILURE',
'REPORTING_FLAGS', 'REPORTING_FLAGS',
# 1. Utility Functions # 1. Utility Functions
'is_private',
# 2. Example & DocTest # 2. Example & DocTest
'Example', 'Example',
'DocTest', 'DocTest',
@ -101,11 +100,6 @@ import unittest, difflib, pdb, tempfile
import warnings import warnings
from StringIO import StringIO from StringIO import StringIO
# Don't whine about the deprecated is_private function in this
# module's tests.
warnings.filterwarnings("ignore", "is_private", DeprecationWarning,
__name__, 0)
# There are 4 basic classes: # There are 4 basic classes:
# - Example: a <source, want> pair, plus an intra-docstring line number. # - Example: a <source, want> pair, plus an intra-docstring line number.
# - DocTest: a collection of examples, parsed from a docstring, plus # - DocTest: a collection of examples, parsed from a docstring, plus
@ -178,35 +172,6 @@ ELLIPSIS_MARKER = '...'
## 1. Utility Functions ## 1. Utility Functions
###################################################################### ######################################################################
def is_private(prefix, base):
"""prefix, base -> true iff name prefix + "." + base is "private".
Prefix may be an empty string, and base does not contain a period.
Prefix is ignored (although functions you write conforming to this
protocol may make use of it).
Return true iff base begins with an (at least one) underscore, but
does not both begin and end with (at least) two underscores.
>>> is_private("a.b", "my_func")
False
>>> is_private("____", "_my_func")
True
>>> is_private("someclass", "__init__")
False
>>> is_private("sometypo", "__init_")
True
>>> is_private("x.y.z", "_")
True
>>> is_private("_x.y.z", "__")
False
>>> is_private("", "") # senseless but consistent
False
"""
warnings.warn("is_private is deprecated; it wasn't useful; "
"examine DocTestFinder.find() lists instead",
DeprecationWarning, stacklevel=2)
return base[:1] == "_" and not base[:2] == "__" == base[-2:]
def _extract_future_flags(globs): def _extract_future_flags(globs):
""" """
Return the compiler-flags associated with the future features that Return the compiler-flags associated with the future features that
@ -759,7 +724,7 @@ class DocTestFinder:
""" """
def __init__(self, verbose=False, parser=DocTestParser(), def __init__(self, verbose=False, parser=DocTestParser(),
recurse=True, _namefilter=None, exclude_empty=True): recurse=True, exclude_empty=True):
""" """
Create a new doctest finder. Create a new doctest finder.
@ -779,12 +744,8 @@ class DocTestFinder:
self._verbose = verbose self._verbose = verbose
self._recurse = recurse self._recurse = recurse
self._exclude_empty = exclude_empty self._exclude_empty = exclude_empty
# _namefilter is undocumented, and exists only for temporary backward-
# compatibility support of testmod's deprecated isprivate mess.
self._namefilter = _namefilter
def find(self, obj, name=None, module=None, globs=None, def find(self, obj, name=None, module=None, globs=None, extraglobs=None):
extraglobs=None):
""" """
Return a list of the DocTests that are defined by the given Return a list of the DocTests that are defined by the given
object's docstring, or by any of its contained objects' object's docstring, or by any of its contained objects'
@ -862,13 +823,6 @@ class DocTestFinder:
self._find(tests, obj, name, module, source_lines, globs, {}) self._find(tests, obj, name, module, source_lines, globs, {})
return tests return tests
def _filter(self, obj, prefix, base):
"""
Return true if the given object should not be examined.
"""
return (self._namefilter is not None and
self._namefilter(prefix, base))
def _from_module(self, module, object): def _from_module(self, module, object):
""" """
Return true if the given object is defined in the given Return true if the given object is defined in the given
@ -910,9 +864,6 @@ class DocTestFinder:
# Look for tests in a module's contained objects. # Look for tests in a module's contained objects.
if inspect.ismodule(obj) and self._recurse: if inspect.ismodule(obj) and self._recurse:
for valname, val in obj.__dict__.items(): for valname, val in obj.__dict__.items():
# Check if this contained object should be ignored.
if self._filter(val, name, valname):
continue
valname = '%s.%s' % (name, valname) valname = '%s.%s' % (name, valname)
# Recurse to functions & classes. # Recurse to functions & classes.
if ((inspect.isfunction(val) or inspect.isclass(val)) and if ((inspect.isfunction(val) or inspect.isclass(val)) and
@ -941,9 +892,6 @@ class DocTestFinder:
# Look for tests in a class's contained objects. # Look for tests in a class's contained objects.
if inspect.isclass(obj) and self._recurse: if inspect.isclass(obj) and self._recurse:
for valname, val in obj.__dict__.items(): for valname, val in obj.__dict__.items():
# Check if this contained object should be ignored.
if self._filter(val, name, valname):
continue
# Special handling for staticmethod/classmethod. # Special handling for staticmethod/classmethod.
if isinstance(val, staticmethod): if isinstance(val, staticmethod):
val = getattr(obj, valname) val = getattr(obj, valname)
@ -1751,17 +1699,16 @@ class DebugRunner(DocTestRunner):
# class, updated by testmod. # class, updated by testmod.
master = None master = None
def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, def testmod(m=None, name=None, globs=None, verbose=None,
report=True, optionflags=0, extraglobs=None, report=True, optionflags=0, extraglobs=None,
raise_on_error=False, exclude_empty=False): raise_on_error=False, exclude_empty=False):
"""m=None, name=None, globs=None, verbose=None, isprivate=None, """m=None, name=None, globs=None, verbose=None, report=True,
report=True, optionflags=0, extraglobs=None, raise_on_error=False, optionflags=0, extraglobs=None, raise_on_error=False,
exclude_empty=False exclude_empty=False
Test examples in docstrings in functions and classes reachable Test examples in docstrings in functions and classes reachable
from module m (or the current module if m is not supplied), starting from module m (or the current module if m is not supplied), starting
with m.__doc__. Unless isprivate is specified, private names with m.__doc__.
are not skipped.
Also test examples reachable from dict m.__test__ if it exists and is Also test examples reachable from dict m.__test__ if it exists and is
not None. m.__test__ maps names to functions, classes and strings; not None. m.__test__ maps names to functions, classes and strings;
@ -1810,13 +1757,6 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
first unexpected exception or failure. This allows failures to be first unexpected exception or failure. This allows failures to be
post-mortem debugged. post-mortem debugged.
Deprecated in Python 2.4:
Optional keyword arg "isprivate" specifies a function used to
determine whether a name is private. The default function is
treat all functions as public. Optionally, "isprivate" can be
set to doctest.is_private to skip over functions marked as private
using the underscore naming convention; see its docs for details.
Advanced tomfoolery: testmod runs methods of a local instance of Advanced tomfoolery: testmod runs methods of a local instance of
class doctest.Tester, then merges the results into (or creates) class doctest.Tester, then merges the results into (or creates)
global Tester instance doctest.master. Methods of doctest.master global Tester instance doctest.master. Methods of doctest.master
@ -1827,11 +1767,6 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
""" """
global master global master
if isprivate is not None:
warnings.warn("the isprivate argument is deprecated; "
"examine DocTestFinder.find() lists instead",
DeprecationWarning)
# If no module was given, then use __main__. # If no module was given, then use __main__.
if m is None: if m is None:
# DWA - m will still be None if this wasn't invoked from the command # DWA - m will still be None if this wasn't invoked from the command
@ -1848,7 +1783,7 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
name = m.__name__ name = m.__name__
# Find, parse, and run all tests in the given module. # Find, parse, and run all tests in the given module.
finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty) finder = DocTestFinder(exclude_empty=exclude_empty)
if raise_on_error: if raise_on_error:
runner = DebugRunner(verbose=verbose, optionflags=optionflags) runner = DebugRunner(verbose=verbose, optionflags=optionflags)
@ -2021,8 +1956,7 @@ def run_docstring_examples(f, globs, verbose=False, name="NoName",
# actually used in any way. # actually used in any way.
class Tester: class Tester:
def __init__(self, mod=None, globs=None, verbose=None, def __init__(self, mod=None, globs=None, verbose=None, optionflags=0):
isprivate=None, optionflags=0):
warnings.warn("class Tester is deprecated; " warnings.warn("class Tester is deprecated; "
"use class doctest.DocTestRunner instead", "use class doctest.DocTestRunner instead",
@ -2037,9 +1971,8 @@ class Tester:
self.globs = globs self.globs = globs
self.verbose = verbose self.verbose = verbose
self.isprivate = isprivate
self.optionflags = optionflags self.optionflags = optionflags
self.testfinder = DocTestFinder(_namefilter=isprivate) self.testfinder = DocTestFinder()
self.testrunner = DocTestRunner(verbose=verbose, self.testrunner = DocTestRunner(verbose=verbose,
optionflags=optionflags) optionflags=optionflags)

View File

@ -512,15 +512,11 @@ will only be generated for it once:
>>> tests[1].name.split('.')[-1] in ['f', 'g'] >>> tests[1].name.split('.')[-1] in ['f', 'g']
True True
Filter Functions Empty Tests
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~
A filter function can be used to restrict which objects get examined, By default, an object with no doctests doesn't create any tests:
but this is temporary, undocumented internal support for testmod's
deprecated isprivate gimmick.
>>> def namefilter(prefix, base): >>> tests = doctest.DocTestFinder().find(SampleClass)
... return base.startswith('a_')
>>> tests = doctest.DocTestFinder(_namefilter=namefilter).find(SampleClass)
>>> tests.sort() >>> tests.sort()
>>> for t in tests: >>> for t in tests:
... print '%2s %s' % (len(t.examples), t.name) ... print '%2s %s' % (len(t.examples), t.name)
@ -528,6 +524,9 @@ deprecated isprivate gimmick.
3 SampleClass.NestedClass 3 SampleClass.NestedClass
1 SampleClass.NestedClass.__init__ 1 SampleClass.NestedClass.__init__
1 SampleClass.__init__ 1 SampleClass.__init__
2 SampleClass.a_classmethod
1 SampleClass.a_property
1 SampleClass.a_staticmethod
1 SampleClass.double 1 SampleClass.double
1 SampleClass.get 1 SampleClass.get
@ -536,8 +535,7 @@ tells it to include (empty) tests for objects with no doctests. This feature
is really to support backward compatibility in what doctest.master.summarize() is really to support backward compatibility in what doctest.master.summarize()
displays. displays.
>>> tests = doctest.DocTestFinder(_namefilter=namefilter, >>> tests = doctest.DocTestFinder(exclude_empty=False).find(SampleClass)
... exclude_empty=False).find(SampleClass)
>>> tests.sort() >>> tests.sort()
>>> for t in tests: >>> for t in tests:
... print '%2s %s' % (len(t.examples), t.name) ... print '%2s %s' % (len(t.examples), t.name)
@ -547,35 +545,12 @@ displays.
0 SampleClass.NestedClass.get 0 SampleClass.NestedClass.get
0 SampleClass.NestedClass.square 0 SampleClass.NestedClass.square
1 SampleClass.__init__ 1 SampleClass.__init__
1 SampleClass.double
1 SampleClass.get
If a given object is filtered out, then none of the objects that it
contains will be added either:
>>> def namefilter(prefix, base):
... return base == 'NestedClass'
>>> tests = doctest.DocTestFinder(_namefilter=namefilter).find(SampleClass)
>>> tests.sort()
>>> for t in tests:
... print '%2s %s' % (len(t.examples), t.name)
3 SampleClass
1 SampleClass.__init__
2 SampleClass.a_classmethod 2 SampleClass.a_classmethod
1 SampleClass.a_property 1 SampleClass.a_property
1 SampleClass.a_staticmethod 1 SampleClass.a_staticmethod
1 SampleClass.double 1 SampleClass.double
1 SampleClass.get 1 SampleClass.get
The filter function apply to contained objects, and *not* to the
object explicitly passed to DocTestFinder:
>>> def namefilter(prefix, base):
... return base == 'SampleClass'
>>> tests = doctest.DocTestFinder(_namefilter=namefilter).find(SampleClass)
>>> len(tests)
9
Turning off Recursion Turning off Recursion
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
DocTestFinder can be told not to look for tests in contained objects DocTestFinder can be told not to look for tests in contained objects
@ -1913,20 +1888,6 @@ def test_DocTestSuite():
modified the test globals, which are a copy of the modified the test globals, which are a copy of the
sample_doctest module dictionary. The test globals are sample_doctest module dictionary. The test globals are
automatically cleared for us after a test. automatically cleared for us after a test.
Finally, you can provide an alternate test finder. Here we'll
use a custom test_finder to to run just the test named bar.
However, the test in the module docstring, and the two tests
in the module __test__ dict, aren't filtered, so we actually
run three tests besides bar's. The filtering mechanisms are
poorly conceived, and will go away someday.
>>> finder = doctest.DocTestFinder(
... _namefilter=lambda prefix, base: base!='bar')
>>> suite = doctest.DocTestSuite('test.sample_doctest',
... test_finder=finder)
>>> suite.run(unittest.TestResult())
<unittest.TestResult run=4 errors=0 failures=1>
""" """
def test_DocFileSuite(): def test_DocFileSuite():

View File

@ -106,6 +106,9 @@ Extension Modules
Library Library
------- -------
- The optional ``is_private`` argument to ``doctest.testmod()``, deprecated
in 2.4, was removed.
- Patch #1359618: Speed up charmap encoder by using a trie structure - Patch #1359618: Speed up charmap encoder by using a trie structure
for lookup. for lookup.