Decorator cllass hides docstring from doctest?

  • Thread starter Berthold =?iso-8859-15?Q?H=F6llmann?=
  • Start date
B

Berthold =?iso-8859-15?Q?H=F6llmann?=

Saving the following code to a file and running the code through
python does not give the expected error. disableling the "@decor" line
leads to the expected error message. Is this a bug or an overseen
feature?


--- snip dectest.py ---
class decor(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kw):
return self.f(*args, **kw)

@decor
def f(a, b):
""" False
"""
return a == b

def _test():
import doctest
doctest.testmod()

if __name__ == "__main__":
_test()
--- snip dectest.py ---

Our Python is:

Python 2.4.2 (#1, Dec 5 2005, 10:13:23)
[GCC 3.3.5 20050117 (prerelease) (SUSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.


Thanks
Berthold
 
D

Duncan Booth

Saving the following code to a file and running the code through
python does not give the expected error. disableling the "@decor" line
leads to the expected error message. Is this a bug or an overseen
feature?
It's a problem with your implementation of the decorator. In fact it is two
problems: the decorated 'f' is a class instance so doctest ignores it, and
it doesn't have a docstring so doctest ignores it.

If you rewrite the decorator so that the decorated 'f' is still a function
and preserve the docstring then it works as you might expect. e.g.

def decor(f):
def wrapper(*args, **kw):
return f(*args, **kw)
wrapper.__doc__ = f.__doc__
wrapper.__name__ = f.__name__
return wrapper
 
P

Peter Otten

Berthold said:
Saving the following code to a file and running the code through
python does not give the expected error. disableling the "@decor" line
leads to the expected error message. Is this a bug or an overseen
feature?

Neither, I'd say. Just an unfortunate interaction between doctest and
function decoration. For the most common case where one function is wrapped
by another, Python 2.5 has grown a "meta-decorator"
.... @functools.wraps(f)
.... def g():
.... f()
.... return g
........ def f():
.... "yadda yadda"
....'yadda yadda'

but with callable objects you're on your own, I think.
I came up with:

def register_doctest(name, doc):
global __test__
if doc:
try:
__test__
except NameError:
__test__ = {name: doc}
else:
if name in __test__:
raise ValueError("name clash")
__test__[name] = doc

class decor(object):
def __init__(self, f):
self.f = f
register_doctest(f.__name__, f.__doc__)
def __call__(self, *args, **kw):
return self.f(*args, **kw)

@decor
def f(a, b):
""" False
"""
return a == b

import doctest
doctest.testmod()

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top