Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decorated functions #58

Open
hyukim17 opened this issue Jul 15, 2015 · 9 comments

Comments

Projects
None yet
3 participants
@hyukim17
Copy link

commented Jul 15, 2015

Is there an easy way to allow pdoc to access the doc of decorated functions?

For example, how can I make pdoc document:

@memoize
def func(a, b, c):
"""
Doc string
"""
return a, b, c

@hyukim17

This comment has been minimized.

Copy link
Author

commented Jul 15, 2015

It seems especially tricky if the decorator returns a callable object instance, not a function.

@BurntSushi

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2015

Use functools.wraps in your memoize decorator: https://docs.python.org/2.7/library/functools.html#functools.wraps

@hyukim17

This comment has been minimized.

Copy link
Author

commented Jul 15, 2015

Tried using http://stackoverflow.com/questions/6394511/python-functools-wraps-equivalent-for-classes to wrap the class instance.

However, pdoc will recognize it as a var, not a function, and still not carry over the docs.

@BurntSushi

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2015

Can you please produce a minimal example of your problem? Everything seems to be working fine for me:

[andrew@Liger tmp] cat issue58.py 
from functools import total_ordering

@total_ordering
class Foo(object):
    def __le__(self, _):
        return True
[andrew@Liger tmp] pdoc --html issue58.py

Result: http://burntsushi.net/stuff/issue58.m.html

@hyukim17

This comment has been minimized.

Copy link
Author

commented Jul 15, 2015

Sure, try this:

import functools

class Decorator(object):
  def __init__(self, func):
    self.f = func

    functools.update_wrapper(self, func)

  def __call__(self, *args, **kwargs):
    return self.f(*args, **kwargs)

@Decorator
def func(a):
  """
    Awesome func.
  """

  return a

The resulting docs will list func as a variable and include no docs.

@BurntSushi BurntSushi added the bug label Jul 15, 2015

@BurntSushi

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2015

Interesting. This one may be quite difficult to fix:

import functools


class Decorator(object):
  def __init__(self, func):
    self.f = func

    functools.update_wrapper(self, func)

  def __call__(self, *args, **kwargs):
    return self.f(*args, **kwargs)


@Decorator
def func(a):
  """
    Awesome func.
  """

  return a

import inspect
for x in filter(lambda s: s.startswith('is'), dir(inspect)):
    print(x, getattr(inspect, x)(func))

Outputs:

('isabstract', False)
('isbuiltin', False)
('isclass', False)
('iscode', False)
('isdatadescriptor', False)
('isframe', False)
('isfunction', False)
('isgenerator', False)
('isgeneratorfunction', False)
('isgetsetdescriptor', False)
('ismemberdescriptor', False)
('ismethod', False)
('ismethoddescriptor', False)
('ismodule', False)
('isroutine', False)
('istraceback', False)

Which means inspect apparently can't tell what it is. pdoc will fall back to a variable.

@hyukim17

This comment has been minimized.

Copy link
Author

commented Jul 15, 2015

  1. What can I hack in to make pdoc recognize it as a function?
  2. Regardless of the type, why do the docs not show up?
@BurntSushi

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2015

I can't think of anything you can do in your source code. You could patch pdoc by modifying the logic here: https://github.com/BurntSushi/pdoc/blob/master/pdoc/__init__.py#L571-L588 --- Namely, by looking for __call__ and interpreting it as a function. But that's going to fail as soon as inspect.getargspec is called. So you could also interpret it as a class, which is unfortunate, but the docs should show up (the source probably won't though).

            if inspect.isfunction(obj) or inspect.isbuiltin(obj):
                self.doc[name] = Function(name, self, obj)
            elif inspect.ismethod(obj):
                self.doc[name] = Function(name, self, obj)
            elif inspect.isclass(obj):
                self.doc[name] = Class(name, self, obj)
            elif inspect.ismodule(obj):
                # Only document modules that are submodules or are forcefully
                # exported by __all__.
                if obj is not self.module and \
                        (self.__is_exported(name, obj)
                         or self.is_submodule(obj.__name__)):
                    self.doc[name] = self.__new_submodule(name, obj)
            elif name in vardocs:
                self.doc[name] = vardocs[name]
            elif hasattr(obj, '__call__'):
                self.doc[name] = Class(name, self, obj)
            else:
                # Catch all for variables.
                self.doc[name] = Variable(name, self, '', cls=None)

The docs don't show because variables don't have __doc__ attributes. Therefore, when func gets interprets as a variable, its __doc__ attribute is never checked. I guess that would be another way to fix this (inside of pdoc). Maybe by changing the else in the above code to:

            else:
                # Catch all for variables.
                self.doc[name] = Variable(name, self, getattr(obj, '__doc__', ''), cls=None)
@fritzvd

This comment has been minimized.

Copy link

commented Jun 27, 2016

Hi,

I'm running into the same issue, is this being worked on? Or is this an as is bug and you have to patch it yourself?

Fritz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.