Skip to content

Commit

Permalink
Merge pull request #300 from machow/fix-external-alias-members
Browse files Browse the repository at this point in the history
fix: resolve external alias members via loading
  • Loading branch information
machow authored Oct 20, 2023
2 parents a37b560 + 7cd7f05 commit 0205d17
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 11 deletions.
49 changes: 38 additions & 11 deletions quartodoc/builder/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from griffe.loader import GriffeLoader
from griffe.collections import ModulesCollection, LinesCollection
from griffe.docstrings.parsers import Parser
from griffe.exceptions import AliasResolutionError
from functools import partial
from textwrap import indent

Expand Down Expand Up @@ -120,6 +121,26 @@ def _non_default_entries(el: Auto):
return {k: getattr(el, k) for k in el._fields_specified}


def _resolve_alias(obj: dc.Alias | dc.Object, get_object):
if not isinstance(obj, dc.Alias):
return obj

# attempt to resolve alias, loading external modules when needed ----
max_tries = 100

new_obj = obj
for ii in range(max_tries):
if not new_obj.is_alias:
break

try:
new_obj = new_obj.target
except AliasResolutionError as e:
new_obj = get_object(e.alias.target_path)

return new_obj


class BlueprintTransformer(PydanticTransformer):
def __init__(self, get_object=None, parser="numpy"):
if get_object is None:
Expand Down Expand Up @@ -296,8 +317,9 @@ def enter(self, el: Auto):

# do no document submodules
if (
_is_external_alias(doc.obj, obj.package)
or doc.obj.kind.value == "module"
# _is_external_alias(doc.obj, obj.package)
doc.obj.kind.value
== "module"
):
continue

Expand Down Expand Up @@ -332,13 +354,19 @@ def enter(self, el: Auto):
signature_name=el.signature_name,
)

@staticmethod
def _fetch_members(el: Auto, obj: dc.Object | dc.Alias):
def _fetch_members(self, el: Auto, obj: dc.Object | dc.Alias):
# Note that this could be a static method, if we passed in the griffe loader

if el.members is not None:
return el.members

options = obj.all_members if el.include_inherited else obj.members

# use the __all__ attribute of modules to filter members
# otherwise, all members are included in the initial options
if obj.is_module and obj.exports is not None:
options = {k: v for k, v in options.items() if v.is_exported}

if el.include:
raise NotImplementedError("include argument currently unsupported.")

Expand All @@ -348,9 +376,14 @@ def _fetch_members(el: Auto, obj: dc.Object | dc.Alias):
if not el.include_private:
options = {k: v for k, v in options.items() if not k.startswith("_")}

if not el.include_imports and not el.include_inherited:
if not (el.include_imports or el.include_inherited):
options = {k: v for k, v in options.items() if not v.is_alias}

# resolve any remaining aliases ----
# the reamining filters require attributes on the target object.
for obj in options.values():
_resolve_alias(obj, self.get_object)

if not el.include_empty:
options = {k: v for k, v in options.items() if v.docstring is not None}

Expand All @@ -363,12 +396,6 @@ def _fetch_members(el: Auto, obj: dc.Object | dc.Alias):
if not el.include_functions:
options = {k: v for k, v in options.items() if not v.is_function}

# for modules, remove any Alias objects, since they were imported from
# other places. Sphinx has a flag for this behavior, so may be good
# to do something similar.
# if obj.is_module:
# options = {k: v for k, v in options.items() if not v.is_alias}

return sorted(options)


Expand Down
1 change: 1 addition & 0 deletions quartodoc/tests/example_alias_target.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from quartodoc.tests.example_alias_target__nested import ( # noqa: F401
nested_alias_target,
tabulate as external_alias,
)


Expand Down
2 changes: 2 additions & 0 deletions quartodoc/tests/example_alias_target__nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
This function gets imported in example_alias_target, and from there imported into example.
"""

from tabulate import tabulate # noqa: F401


def nested_alias_target():
"""A nested alias target"""
15 changes: 15 additions & 0 deletions quartodoc/tests/test_builder_blueprint.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from functools import partial
from griffe.exceptions import AliasResolutionError
from quartodoc import get_object
from quartodoc import layout as lo
from quartodoc.builder.blueprint import (
_non_default_entries,
_resolve_alias,
BlueprintTransformer,
blueprint,
WorkaroundKeyError,
)
import pytest


TEST_MOD = "quartodoc.tests.example"


Expand Down Expand Up @@ -38,6 +42,17 @@ def bp():
return BlueprintTransformer()


def test_func_resolve_alias():
obj = get_object("quartodoc.tests.example_alias_target.external_alias")
assert obj.is_alias
with pytest.raises(AliasResolutionError):
obj.target

resolved = _resolve_alias(obj, get_object)

assert resolved.path == "tabulate.tabulate"


def test_non_default_entries_auto():
assert _non_default_entries(lo.Auto(name="a_func", include_attributes=False)) == {
"name": "a_func",
Expand Down

0 comments on commit 0205d17

Please sign in to comment.