Doctest and third party decorator

Viewed 159

I need to doc-test a method which has to be wrapped with a decorator that does not apply @functools.wraps or functools.update_wrapper to the method being wrapped. In this case, the doctest does not see the docstring of the method to be tested:

@third_party_decorator
def method_to_be_tested():
    """
    >>> method_to_be_tested()
    "foo"
    """
    return "foo"

This question is similar, however, I cannot change the code of the decorator.

What is the best thing I can do?

2 Answers

You may not be able to change the code of third_party_decorator, but you can wrap it once again to address the problem, and even re-use the same name if necessary:

def third_party_decorator(f):
    # badly behaved decorator, this removed f's docstring
    def no_docstring():
        return f()
    return no_docstring

old_third_party_decorator = third_party_decorator

def third_party_decorator(f):
    # replace third_party_decorator AND preserve docstring
    new_f = old_third_party_decorator(f)
    new_f.__doc__ = f.__doc__
    return new_f

@third_party_decorator
def method_to_be_tested():
    """
    >>> method_to_be_tested()
    'foo'
    """
    return "foo"

import doctest
print(doctest.testmod())

A small meta-decorator to fix this:

def w(decorator): 
    def wrapper(func): 
        return wraps(func)(decorator(func))
    return wrapper 

Use:

@w(third_party_decorator)
def method_to_be_tested():
    """
    >>> method_to_be_tested()
    "foo"
    """
    return "foo"

Or, monkey-patch it (do it only once):

third_party_decorator = w(third_party_decorator)
Related