pdoc icon indicating copy to clipboard operation
pdoc copied to clipboard

The idea for documenting reimported entities from submodules

Open Yura52 opened this issue 4 years ago • 5 comments

Hi!

  • I have a function my_lib.my_module.my_function
  • I do from .my_module import my_function in my_lib/__init__.py
  • I want users to access the function as my_lib.my_function

As far as I understand there is no way to tell pdoc to document the function as my_lib.my_function. Although I see from the website that this is an intentional design decision, I would like to share an idea that is:

  • simple
  • preserves strong correspondence between the source code and its documentation (i.e. pdoc will be able to fully understand the intended reimports and check their correctness)

The idea is to add a single mapping __pdoc_mapping__ in the root __init__.py (my_lib/__init__.py in the example above) with the following content:

__pdoc_mapping__ = {
    # old_name: new_name
    'my_function': 'my_module.my_function'
}

What do you think?

Yura52 avatar May 09 '21 10:05 Yura52

This is certainly a common use case, but distinguishing imported my_lib.my_function (that you want to show) from imported re (that you don't) is near impossible.

Pdoc should honor __all__ when present.

Can you first try if it works if you expose the function in __all__ in the module where you want it, and block it with __pdoc__ value False where you don't?

kernc avatar May 09 '21 23:05 kernc

I've just tried what you are suggesting and it works. However, it also makes it necessary to:

  1. put all other documented members of my_lib in __all__
  2. duplicate my intention in the form of __pdoc__['my_function'] = False in my_lib/my_module.py

The suggested __pdoc_mapping__ frees __all__ from this additional documentation-related responsibility (which, in theory, can be inappropriate) and removes the duplication.

distinguishing imported my_lib.my_function (that you want to show) from imported re (that you don't) is near impossible.

__pdoc_mapping__ also solves this problem, since this mapping should contain all imported entities that are supposed to be documented.

Yura52 avatar May 10 '21 14:05 Yura52

While __pdoc_mapping__ is a clear self-sufficient concept which is convenient to discuss, I should say that there are other ways to implement the idea. Especially I would like to mention the following approach: dicts can be allowed as values for __pdoc__, while booleans and strings can be treated as some special cases. Then the story becomes the following:

# This dictionary
__pdoc__ = {
    'some_function': False,
    'SomeClass': 'Custom docstring',
    'my_function': {'source': 'my_module.my_function'},
    'something_else': {'source': 'my_module.submodule.whatever', show: False, 'doc': 'Better docstring'},
}

# is equivalent to this dictionary:
__pdoc__ = {
    'some_function': {'show': False},
    'SomeClass': {'doc': 'Custom docstring'},
    'my_function': {'source': 'my_module.my_function'},
    'something_else': {'source': 'my_module.submodule.whatever', show: False, 'doc': 'Better docstring'},
}

Yura52 avatar May 10 '21 14:05 Yura52

mapping is little complex.

I'm thinking about such situation:

__pdoc__ = {
    'MyClass': True
}

MyClass is under the submodule _base and reimported in __init__.

When inspect.getmembers() iter this module, just document the MyClass object; meanwhile, module _base will not be documented.

See: https://github.com/pdoc3/pdoc/blob/f49faf04a8f236474cda70116046d89f3725faee/pdoc/init.py#L694

ignore this comment. _is_whitelisted method while ask supermodule for pdoc, which conflicts.

iyume avatar Aug 02 '21 08:08 iyume

I stumbled upon this issue whilst trying to find a fix for duplicate entries in the documentation when I import my public API in a package's __init__.py file. I've tried __pdoc__ = {"__all__": False} which does not work. Is the only way to do it to iterate over every member in __all__ and mark it as False. I currently have something like the following which works:

from myproject.foo import Foo
from myproject.bar import Bar

__all__ = [
    "Foo",
    "Bar",
]

__pdoc__ = {}
for _obj in __all__:
    __pdoc__[_obj] = False

Is this the only way? I have __init__.py files which import classes in all of my subpackages so this pattern will need to be repeated in a lot of places. It would be great if there was a command line option to just ignore imports in the __init__.py files completely

amin-nejad avatar Dec 17 '21 16:12 amin-nejad