doctests and decorators

Eric Snow esnow at verio.net
Tue Jun 16 12:19:03 EDT 2009


On Jun 16, 9:59 am, Eric Snow <es... at verio.net> wrote:
> Apparently there is a known issue with doctests, in which tests in
> functions using externally defined decorators are ignored.  The
> recommended fix is to update the order of checks in the _from_module
> method of DocTestFinder in the doctest module.  The bug and fix are
> discussed at the following URLs (and several places in this group):
>
> http://bugs.python.org/issue1108http://mail.python.org/pipermail/python-list/2007-September/627866.html
>
> The fix implies that the inpect.getmodule function will find the
> module of the function object and not of the decorator.  However, in
> 2.4 the inspect.getmodule function returns the module of the
> decorator.  I have subsequently tested this in 2.5 and 2.6, and it
> also returns the module of the decorator.  As such, the fix for
> doctests does not work in my tests.  Below is the test code that I
> used:
>
> <EXAMPLE>
>
> test1.py
> ++++++++++++++++++++++++++++
> def decorator(function):
>     def new_function(*args, **kwargs):
>         return function(*args, **kwargs)
>     return new_function
>
> test2.py
> ++++++++++++++++++++++++++++
> import test1
> import inspect
>
> class Test(object):
>     @test1.decorator
>     def test2(self): pass
>
> def run_tests():
>     test = Test()
>     test.test2()
>
>     print("Test is class, test is instance, test2 is method of Test
> (has decorator)")
>     print("test's module:          %s" % inspect.getmodule(test))
>     print("Test's module:          %s" % inspect.getmodule(Test))
>     print("test.test2's module:    %s" % inspect.getmodule
> (test.test2))
>     print("Test.test2's module:    %s" % inspect.getmodule
> (Test.test2))
>     print("test.test2's func_name: %s" % test.test2.func_name)
>     print("Test.test2's func_name: %s" % Test.test2.func_name)
>
> if __name__ == "__main__":
>     run_tests()
>
> </EXAMPLE>
>
> Here is the output that I got in 2.4, 2.5, and 2.6:
>
> Test is class, test is instance, test2 is method of Test (has
> decorator)
> test's module:          <module '__main__' from 'test2.py'>
> Test's module:          <module '__main__' from 'test2.py'>
> test.test2's module:    <module 'test1' from '/tmp/test1.py'>
> Test.test2's module:    <module 'test1' from '/tmp/test1.py'>
> test.test2's func_name: new_function
> Test.test2's func_name: new_function
>
> If things were working right, then the module for test.test2 would be
> the same as the module for test.  I must be missing something, as the
> referenced discussion suggests a simple conclusion.  Any ideas?
>
> -eric

One work-around I found is the following change in example:

<EXAMPLE>

test1.py
++++++++++++++++++++++++++++
def decorator(function):
    def new_function(*args, **kwargs):
        return function(*args, **kwargs)
    new_function.__module__ = function.__module__
    new_function.__doc__ = function.__doc__
    new_function.__name__ = function.__name__
    return new_function

</EXAMPLE>

However, this seems pretty lame.  The doctest module should be able to
figure out that the docstring belongs is there in the module.

-eric



More information about the Python-list mailing list