doctest suggestion

Tim Hochberg tim.hochberg at ieee.org
Fri Sep 28 23:11:53 CEST 2001


[Sorry, my stupid mailer sent this before I was ready.]

Hi all and particularly Tim Peters if your listening,

I like doctest a lot and use it for all of my unit testing. However, I
frequently run into problems when I import a class or function from a module
using "from X import Y". Y's docstring gets run in the current environment
and frequently the doctests fail because they rely on some aspects of Xs
environment.

It seemed like it would be useful to skip tests in docstrings on objects
imported from another module. I threw together a proof of concept of this
which is attached below; this version ignores the docstrings on imported
functions and classes.

So here's the suggestion: I would really like to see this functionality
included in doctest in some way. I'm willing to clean up the changes to my
code and submit a patch if that's appropriate. However, first I wanted
solicit opinions as to whether this approach is a good one or if there's a
more elegant way to go about it:

-tim

Here are the two changed parts, the method rundict from Tester and the
function testmod:


    def rundict(self, d, name, module=None):
        # Docstring elided
        if not hasattr(d, "items"):
            raise TypeError("Tester.rundict: d must support .items(); " +
                            `d`)
        f = t = 0
        # Run the tests by alpha order of names, for consistency in
        # verbose-mode output.
        names = d.keys()
        names.sort()
        for thisname in names:
            value = d[thisname]
            # Stuff in this if statement is new....
            if type(value) in (_FunctionType, _ClassType):
                if module is not None:
                    if (type(value) == _FunctionType) and
(value.func_globals != module.__dict__):
                        continue
                    if (type(value) == _ClassType) and (value.__module__ !=
module):
                        continue
                f2, t2 = self.__runone(value, name + "." + thisname)
                f = f + f2
                t = t + t2
        return f, t

def testmod(m, name=None, globs=None, verbose=None, isprivate=None,
               report=1):
    # docstring elided...
    global master

    if type(m) is not _ModuleType:
        raise TypeError("testmod: module required; " + `m`)
    if name is None:
        name = m.__name__
    tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate)
    failures, tries = tester.rundoc(m, name)
    f, t = tester.rundict(m.__dict__, name, m) # we now pass m in...
    failures = failures + f
    tries = tries + t
    if hasattr(m, "__test__"):
        testdict = m.__test__
        if testdict:
            if not hasattr(testdict, "items"):
                raise TypeError("testmod: module.__test__ must support "
                                ".items(); " + `testdict`)
            f, t = tester.run__test__(testdict, name + ".__test__")
            failures = failures + f
            tries = tries + t
    if report:
        tester.summarize()
    if master is None:
        master = tester
    else:
        master.merge(tester)
    return failures, tries





More information about the Python-list mailing list