Remove the horrid generators hack from doctest.py. This relies on a

somewhat less horrid hack <wink>:  if a module does
    from __future__ import X
then the module dict D is left in a state such that (viewing X as a
string)
    D[X] is getattr(__future__, X)
So by examining D for all the names of future features, and making that
test for each, we can make a darned good guess as to which future-features
were imported by the module.  The appropriate flags are then sucked out
of the __future__ module, and passed on to compile()'s new optional
arguments (PEP 264).

Also gave doctest a meaningful __all__, removed the history of changes
(CVS serves that purpose now), and removed the __version__ vrbl (similarly;
before CVS, it was a reasonable clue, but not anymore).
This commit is contained in:
Tim Peters 2001-08-18 00:05:50 +00:00
parent ec927348c2
commit 4fd9e2fc13
1 changed files with 36 additions and 74 deletions

View File

@ -1,4 +1,4 @@
# Module doctest version 0.9.7 # Module doctest.
# Released to the public domain 16-Jan-2001, # Released to the public domain 16-Jan-2001,
# by Tim Peters (tim.one@home.com). # by Tim Peters (tim.one@home.com).
@ -294,70 +294,14 @@ ok
Test passed. Test passed.
""" """
# 0,0,1 06-Mar-1999 __all__ = [
# initial version posted 'testmod',
# 0,0,2 06-Mar-1999 'run_docstring_examples',
# loosened parsing: 'is_private',
# cater to stinkin' tabs 'Tester',
# don't insist on a blank after PS2 prefix ]
# so trailing "... " line from a compound stmt no longer
# breaks if the file gets whitespace-trimmed
# better error msgs for inconsistent leading whitespace
# 0,9,1 08-Mar-1999
# exposed the Tester class and added client methods
# plus docstring examples of their use (eww - head-twisting!)
# fixed logic error in reporting total # of tests & failures
# added __test__ support to testmod (a pale reflection of Christian
# Tismer's vision ...)
# removed the "deep" argument; fiddle __test__ instead
# simplified endcase logic for extracting tests, and running them.
# before, if no output was expected but some was produced
# anyway via an eval'ed result, the discrepancy wasn't caught
# made TestClass private and used __test__ to get at it
# many doc updates
# speed _SpoofOut for long expected outputs
# 0,9,2 09-Mar-1999
# throw out comments from examples, enabling use of the much simpler
# exec compile(... "single") ...
# for simulating the runtime; that barfs on comment-only lines
# used the traceback module to do a much better job of reporting
# exceptions
# run __doc__ values thru str(), "just in case"
# privateness of names now determined by an overridable "isprivate"
# function
# by default a name now considered to be private iff it begins with
# an underscore but doesn't both begin & end with two of 'em; so
# e.g. Class.__init__ etc are searched now -- as they always
# should have been
# 0,9,3 18-Mar-1999
# added .flush stub to _SpoofOut (JPython buglet diagnosed by
# Hugh Emberson)
# repaired ridiculous docs about backslashes in examples
# minor internal changes
# changed source to Unix line-end conventions
# moved __test__ logic into new Tester.run__test__ method
# 0,9,4 27-Mar-1999
# report item name and line # in failing examples
# 0,9,5 29-Jun-1999
# allow straightforward exceptions in examples - thanks to Mark Hammond!
# 0,9,6 16-Jan-2001
# fiddling for changes in Python 2.0: some of the embedded docstring
# examples no longer worked *exactly* as advertised, due to minor
# language changes, and running doctest on itself pointed that out.
# Hard to think of a better example of why this is useful <wink>.
# 0,9,7 9-Feb-2001
# string method conversion
# XXX Until generators are part of the language, examples in doctest'ed import __future__
# modules will inherit doctest's __future__ settings (see PEP 236 for
# more on that). In the absence of a better working idea, the std
# test suite needs generators, while the set of doctest'ed modules that
# don't use "yield" in a generator context may well be empty. So
# enable generators here. This can go away when generators are no
# longer optional.
from __future__ import generators
__version__ = 0, 9, 7
import types import types
_FunctionType = types.FunctionType _FunctionType = types.FunctionType
@ -375,8 +319,6 @@ _isEmpty = re.compile(r"\s*$").match
_isComment = re.compile(r"\s*#").match _isComment = re.compile(r"\s*#").match
del re del re
__all__ = []
# Extract interactive examples from a string. Return a list of triples, # Extract interactive examples from a string. Return a list of triples,
# (source, outcome, lineno). "source" is the source code, and ends # (source, outcome, lineno). "source" is the source code, and ends
# with a newline iff the source spans more than one line. "outcome" is # with a newline iff the source spans more than one line. "outcome" is
@ -487,7 +429,8 @@ def _tag_out(printer, *tag_msg_pairs):
# stuff to "the real" stdout, and fakeout is an instance of _SpoofOut # stuff to "the real" stdout, and fakeout is an instance of _SpoofOut
# that captures the examples' std output. Return (#failures, #tries). # that captures the examples' std output. Return (#failures, #tries).
def _run_examples_inner(out, fakeout, examples, globs, verbose, name): def _run_examples_inner(out, fakeout, examples, globs, verbose, name,
compileflags):
import sys, traceback import sys, traceback
OK, BOOM, FAIL = range(3) OK, BOOM, FAIL = range(3)
NADA = "nothing" NADA = "nothing"
@ -499,7 +442,8 @@ def _run_examples_inner(out, fakeout, examples, globs, verbose, name):
("Expecting", want or NADA)) ("Expecting", want or NADA))
fakeout.clear() fakeout.clear()
try: try:
exec compile(source, "<string>", "single") in globs exec compile(source, "<string>", "single",
compileflags, 1) in globs
got = fakeout.get() got = fakeout.get()
state = OK state = OK
except: except:
@ -538,17 +482,28 @@ def _run_examples_inner(out, fakeout, examples, globs, verbose, name):
return failures, len(examples) return failures, len(examples)
# Get the future-flags associated with the future features that have been
# imported into globs.
def _extract_future_flags(globs):
flags = 0
for fname in __future__.all_feature_names:
feature = globs.get(fname, None)
if feature is getattr(__future__, fname):
flags |= feature.compiler_flag
return flags
# Run list of examples, in a shallow copy of context (dict) globs. # Run list of examples, in a shallow copy of context (dict) globs.
# Return (#failures, #tries). # Return (#failures, #tries).
def _run_examples(examples, globs, verbose, name): def _run_examples(examples, globs, verbose, name, compileflags):
import sys import sys
saveout = sys.stdout saveout = sys.stdout
globs = globs.copy() globs = globs.copy()
try: try:
sys.stdout = fakeout = _SpoofOut() sys.stdout = fakeout = _SpoofOut()
x = _run_examples_inner(saveout.write, fakeout, examples, x = _run_examples_inner(saveout.write, fakeout, examples,
globs, verbose, name) globs, verbose, name, compileflags)
finally: finally:
sys.stdout = saveout sys.stdout = saveout
# While Python gc can clean up most cycles on its own, it doesn't # While Python gc can clean up most cycles on its own, it doesn't
@ -562,7 +517,8 @@ def _run_examples(examples, globs, verbose, name):
globs.clear() globs.clear()
return x return x
def run_docstring_examples(f, globs, verbose=0, name="NoName"): def run_docstring_examples(f, globs, verbose=0, name="NoName",
compileflags=None):
"""f, globs, verbose=0, name="NoName" -> run examples from f.__doc__. """f, globs, verbose=0, name="NoName" -> run examples from f.__doc__.
Use (a shallow copy of) dict globs as the globals for execution. Use (a shallow copy of) dict globs as the globals for execution.
@ -587,7 +543,9 @@ def run_docstring_examples(f, globs, verbose=0, name="NoName"):
e = _extract_examples(doc) e = _extract_examples(doc)
if not e: if not e:
return 0, 0 return 0, 0
return _run_examples(e, globs, verbose, name) if compileflags is None:
compileflags = _extract_future_flags(globs)
return _run_examples(e, globs, verbose, name, compileflags)
def is_private(prefix, base): def is_private(prefix, base):
"""prefix, base -> true iff name prefix + "." + base is "private". """prefix, base -> true iff name prefix + "." + base is "private".
@ -724,6 +682,8 @@ see its docs for details.
self.name2ft = {} # map name to (#failures, #trials) pair self.name2ft = {} # map name to (#failures, #trials) pair
self.compileflags = _extract_future_flags(globs)
def runstring(self, s, name): def runstring(self, s, name):
""" """
s, name -> search string s for examples to run, logging as name. s, name -> search string s for examples to run, logging as name.
@ -755,7 +715,8 @@ see its docs for details.
f = t = 0 f = t = 0
e = _extract_examples(s) e = _extract_examples(s)
if e: if e:
f, t = _run_examples(e, self.globs, self.verbose, name) f, t = _run_examples(e, self.globs, self.verbose, name,
self.compileflags)
if self.verbose: if self.verbose:
print f, "of", t, "examples failed in string", name print f, "of", t, "examples failed in string", name
self.__record_outcome(name, f, t) self.__record_outcome(name, f, t)
@ -793,7 +754,8 @@ see its docs for details.
"when object.__name__ doesn't exist; " + `object`) "when object.__name__ doesn't exist; " + `object`)
if self.verbose: if self.verbose:
print "Running", name + ".__doc__" print "Running", name + ".__doc__"
f, t = run_docstring_examples(object, self.globs, self.verbose, name) f, t = run_docstring_examples(object, self.globs, self.verbose, name,
self.compileflags)
if self.verbose: if self.verbose:
print f, "of", t, "examples failed in", name + ".__doc__" print f, "of", t, "examples failed in", name + ".__doc__"
self.__record_outcome(name, f, t) self.__record_outcome(name, f, t)