pdoc icon indicating copy to clipboard operation
pdoc copied to clipboard

pdoc3 skips a decorated function (callable object)

Open ShuhuaGao opened this issue 5 years ago • 3 comments

Expected Behavior

Generate the documentation for add3

Actual Behavior

Nothing is generated

Steps to Reproduce

  1. Create a script "pdoc_tt.py" as follows
from numba import cuda


@cuda.jit
def add3(a: int, b: int) -> int:
    """Add two integers

    Args:
        a (int): one integer
        b (int): the other integer

    Returns:
        int: the sum
    """
    return a + b


# add3 is a callable object of type 'numba.cuda.compiler.AutoJitCUDAKernel`
# set the two attributes below manually, since `AutoJitCUDAKernel` does not preserve them
add3.__module__ = __name__
add3.__doc__ = add3.py_func.__doc__  # the right hand  side is just the original __doc__

print(callable(add3))
print(add3.__module__)
print(add3.__doc__)

The package numba is found here

  1. run command pdoc3 --html pdoc_tt.py
  2. We see the following output in the terminal
True
pdoc_tt
Add two integers

    Args:
        a (int): one integer
        b (int): the other integer

    Returns:
        int: the sum

As we see, add3 is indeed callable, and its __module__ and __doc__ are also right. However, there is no documentation generated for add3 in the Html "pdoc_tt.html".

Additional info

Adding __pdoc__ = {'add3': True} makes no difference.

  • pdoc version: pdoc.exe 0.8.1 (on Windows 10)

ShuhuaGao avatar Jun 22 '20 15:06 ShuhuaGao

Well, it seems the reason is the following method in pdoc3:

def _is_function(obj):
    return inspect.isroutine(obj) and callable(obj)

Here, for the above add3 of type numba.cuda.compiler.AutoJitCUDAKernel, callable yields true while inspect.isroutine gives false. My question is why and is used here for the two conditions. That is, what is the problem if we use or instead?

ShuhuaGao avatar Jun 23 '20 15:06 ShuhuaGao

My question is why and is used here for the two conditions. That is, what is the problem if we use or instead?

When in doubt, best to flip the line and see what, if any, tests it breaks. (Hint: all of them.) The line was introduces as part of https://github.com/pdoc3/pdoc/pull/77, addressing read-only value descriptors (https://github.com/pdoc3/pdoc/issues/76).

The function ensures the passed object is callable and indeed a routine, as opposed to an arbitrary object which just happens to be callable (its class defines __call__), as is the case here.

If you can think of a way to adapt this condition check to also cover your case, a PR is welcome! https://github.com/pdoc3/pdoc/blob/64405338c0b58207f80d264b07cd7fe17694e2d5/pdoc/init.py#L611-L613

Pdoc3, though, diligently calls inspect.unwrap() on detected objects: https://github.com/pdoc3/pdoc/blob/64405338c0b58207f80d264b07cd7fe17694e2d5/pdoc/init.py#L604 so really it's numba at fault, for they should update_wrapper(). This way, you also wouldn't need to manually preserve __module__ and __doc__. I see this is already filed as https://github.com/numba/numba/issues/5902. :+1: It also seems to be an easy, good first issue, so welcome to give them a hand!

kernc avatar Jun 25 '20 18:06 kernc

Hi, kernc,

Thank you for your help. I have tried the or logic instead as follows:

def _is_function(obj):
    return inspect.isroutine(obj) or callable(obj)

aside from setting __module__ and __doc__ manually.

However, it still failed to generate the documentation. I guess more changes are needed for this workaround, which is a little beyond my capability. For now, I will wait for the update from numba.

ShuhuaGao avatar Jun 26 '20 01:06 ShuhuaGao