machow/quartodoc

quartodoc ignores imported attributes

Closed this issue · 5 comments

Problem

When I only import attributes (and specify them to __all__) in a rendered, quartodoc ignores them and doesn't render its documentation.

# module.py

from othermodule import CONSTANT, NOT_SHOWN_CONSTANT

__all__ = ["CONSTANT"]
# _quarto.yaml
quartodoc:
  ...
  sections:
    - title: Some title
      contents:
        - module

This is a problem because often in packages you have "private part of the package", and you only expose the "public" part via imports like that. For example you have a structure like this:

package/
  subpackage/
    __init__.py  # everything imported in here
    _internal.py 

Solution

Similar to pdoc: what to render can be decided based on contents of __all__. For example NOT_SHOWN_CONSTANT shouldn't be rendered because it is not in __all__.

machow commented

Hey! Does the include_imports option work?

# _quarto.yaml
quartodoc:
  ...
  sections:
    - title: Some title
      contents:
        - name: module
          include_imports: true

I think that should tell it to include objects imported into the module. This is analogous to sphinx's import-members option.

Sorry for the confusion. I think it's there so packages that document per module don't accidentally document functions multiple times, but I can see how it's frustrating to debug :/. (In the same vein, classes don't document inherited members by default).

If you want, you can set the option everywhere.

@machow Thanks for the quick response. I didn't find it in the documentation. I believe it will work, I will close the issue tomorrow when I get to try it.

Does it automatically ignore third-party imports? What if I used it on module like this:

# package/module.py
from sklearn.pipeline import Pipeline
from my_package.other_module import CONSTANT

__all__ = ["CONSTANT"]

@machow I'm afraid it doesn't work.

I have a rather complex and private case, so I'll try to simplify it for reproducibility.

# package/module.py
import asyncio
# _quarto.yaml
quartodoc:
  package: package
  ...
  sections:
    - title: Some modules
      contents:
        - name: module
          include_imports: true

It raises error:

Error
Traceback (most recent call last):
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 1214, in _resolve_target
    resolved = self.modules_collection.get_member(self.target_path)
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/mixins.py", line 76, in get_member
    return self.members[parts[0]]  # type: ignore[attr-defined]
KeyError: 'asyncio'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/path/to/project/venv/bin/quartodoc", line 8, in <module>
    sys.exit(cli())
  File "/path/to/project/venv/lib/python3.10/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
  File "/path/to/project/venv/lib/python3.10/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
  File "/path/to/project/venv/lib/python3.10/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/path/to/project/venv/lib/python3.10/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/path/to/project/venv/lib/python3.10/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/__main__.py", line 214, in build
    doc_build()
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/autosummary.py", line 515, in build
    blueprint = blueprint(self.layout, dynamic=self.dynamic, parser=self.parser)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 431, in blueprint
    return trans.visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 185, in visit
    return super().visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 45, in visit
    result = self.enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 222, in enter
    return super().enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 67, in enter
    result = self.visit(value)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 185, in visit
    return super().visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 45, in visit
    result = self.enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 86, in enter
    result = self.visit(child)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 185, in visit
    return super().visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 45, in visit
    result = self.enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 67, in enter
    result = self.visit(value)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 185, in visit
    return super().visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 45, in visit
    result = self.enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 86, in enter
    result = self.visit(child)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 185, in visit
    return super().visit(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/utils.py", line 45, in visit
    result = self.enter(el)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 489, in __call__
    return self._f(self._instance, *args, **kw_args)
  File "/path/to/project/venv/lib/python3.10/site-packages/plum/function.py", line 399, in __call__
    return _convert(method(*args, **kw_args), return_type)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 272, in enter
    raw_members = self._fetch_members(el, obj)
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 355, in _fetch_members
    options = {k: v for k, v in options.items() if v.docstring is not None}
  File "/path/to/project/venv/lib/python3.10/site-packages/quartodoc/builder/blueprint.py", line 355, in <dictcomp>
    options = {k: v for k, v in options.items() if v.docstring is not None}
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 966, in docstring
    return self.final_target.docstring
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 1190, in final_target
    target = target.target  # type: ignore[assignment]
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 1162, in target
    self.resolve_target()
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 1208, in resolve_target
    self._resolve_target()
  File "/path/to/project/venv/lib/python3.10/site-packages/griffe/dataclasses.py", line 1216, in _resolve_target
    raise AliasResolutionError(self) from error
griffe.exceptions.AliasResolutionError: Could not resolve alias package.module pointing at asyncio (in /path/to/project/package/module.py:9)

Versions

  • quartodoc: 0.6.4
  • quarto: 1.3.433
  • python: 3.10
machow commented

Currently it ignores third party imports, and all non-external functions in the module can be members. (The net effect is that I think your example should do what you want).

I added a fix to PR #300, which uses __all__ to get the members for modules. Will release in the next hour or so!

edit: released https://github.com/machow/quartodoc/releases/tag/v0.6.5

machow commented

It seems like this should be fixed in the current version. I tested using this code:

from quartodoc import Auto, blueprint, MdRenderer, preview
bp = blueprint(Auto(name = "quartodoc.tests.example_alias_target__nested", include_imports = True))

# note that the tabulate function, which was imported into the module
# gets rendered in the API doc page for the module
print(MdRenderer().render(bp))

Definitely let me know if it's still an issue, and I can dig into it more.