Decorator cllass hides docstring from doctest?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Berthold Höllmann

    #1

    Decorator cllass hides docstring from doctest?

    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):
    """
    >>f(1,2)
    False
    >>f(2,2)
    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
    --
    __ Address:
    G / \ L Germanischer Lloyd
    phone: +49-40-36149-7374 -+----+- Vorsetzen 35 P.O.Box 111606
    fax : +49-40-36149-7320 \__/ D-20459 Hamburg D-20416 Hamburg

  • Duncan Booth

    #2
    Re: Decorator cllass hides docstring from doctest?

    berthold@despam med.com (Berthold =?iso-8859-15?Q?H=F6llmann ?=) wrote:
    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

    Comment

    • Michele Simionato

      #3
      Re: Decorator cllass hides docstring from doctest?

      Berthold Höllmann wrote:
      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?
      Others have already pointed out the mistake. I wrote a module to avoid
      this kind of issues, so you
      may want to check it out:



      Michele Simionato

      Comment

      • Peter Otten

        #4
        Re: Decorator cllass hides docstring from doctest?

        Berthold Höllmann wrote:
        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"
        >>import functools
        >>def deco(f):
        .... @functools.wrap s(f)
        .... def g():
        .... f()
        .... return g
        ....
        >>@deco
        .... def f():
        .... "yadda yadda"
        ....
        >>f.__doc__
        'yadda yadda'

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

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

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

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

        import doctest
        doctest.testmod ()

        Peter

        Comment

        Working...