Skip to content

Commit

Permalink
Give symbols a better understanding of fullnames with a mwthod that i…
Browse files Browse the repository at this point in the history
…s named localNameToFullName(), which is used as a fallback method when the name cannot be found on the regular model. This will help fix #295
  • Loading branch information
tristanlatr committed Dec 11, 2022
1 parent c7a772b commit 4834757
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 86 deletions.
25 changes: 13 additions & 12 deletions pydoctor/astbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ def visit_Scope(self, node: Union[ast.ClassDef, ast.FunctionDef, ast.AsyncFuncti
def depart_Scope(self, node: Union[ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef]) -> None:
builder = self.visitor.builder
current = builder.current
if current.scope is None:
current.scope = builder.currentScope
if current._stmt is None:
current._stmt = builder.currentScope

assert self.visitor.builder._stmtStack.pop().node is node

Expand Down Expand Up @@ -169,7 +169,9 @@ def __init__(self) -> None:
self.ast_cache: Dict[Path, Optional[ast.Module]] = {}

def _postParse(self, ast_mod:ast.Module, ctx: model.Module) -> None:
ctx.scope = symbols.buildSymbols(ast_mod, getattr(ctx.parent, 'scope', None))
ctx._stmt = symbols.buildSymbols(ast_mod,
parent=ctx.parent._stmt if ctx.parent is not None else None,
name=ctx.name)

def parseFile(self, path: Path, ctx: model.Module) -> Optional[ast.Module]:
try:
Expand Down Expand Up @@ -1202,18 +1204,17 @@ def addAttribute(self,


def processModuleAST(self, mod_ast: ast.Module, mod: model.Module) -> None:
scope = mod.scope
assert scope is not None
module_stmt = mod._stmt
assert module_stmt is not None

# TODO, the iteration should go in the oter way checking if any of the keys in MODULE_VARIABLES_META_PARSERS
# are present in the symbols instead of the opposite.
for name in scope.symbols:
for name in MODULE_VARIABLES_META_PARSERS:
try:
module_var_parser = MODULE_VARIABLES_META_PARSERS[name]
symbol = module_stmt.symbols[name]
except KeyError:
continue
else:
module_var_parser(scope.symbols[name], mod)
module_var_parser = MODULE_VARIABLES_META_PARSERS[name]
module_var_parser(symbol, mod)

vis = self.ModuleVistor(self, mod)
vis.extensions.add(*self.system._astbuilder_visitors)
Expand All @@ -1230,7 +1231,7 @@ def parseAll(symbol: symbols.Symbol, mod: model.Module) -> None:
# More or less temporary code to keep same functionality level as before.
# Plus free support for AnnAssign as well.
# TODO: support augmented assignments
assigns = symbols.filter_stmts_by_type(symbol.statements, symbols.Assignment)
assigns = [stmt for stmt in symbol.statements if isinstance(stmt, symbols.Assignment)]
values = [stmt.value for stmt in assigns if stmt.value is not None]
if not values:
return
Expand Down Expand Up @@ -1279,7 +1280,7 @@ def parseDocformat(symbol: symbols.Symbol, mod: model.Module) -> None:
__docformat__ = "restructuredtext"
"""
# get last assignment and warn if there are multiple.
assigns = symbols.filter_stmts_by_type(symbol.statements, symbols.Assignment)
assigns = [stmt for stmt in symbol.statements if isinstance(stmt, symbols.Assignment)]
values = [stmt.value for stmt in assigns if stmt.value is not None]
if not values:
return
Expand Down
36 changes: 19 additions & 17 deletions pydoctor/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from urllib.parse import quote

from pydoctor.options import Options
from pydoctor import factory, qnmatch, utils, linker, astutils, mro
from pydoctor import factory, qnmatch, utils, linker, astutils, mro, symbols
from pydoctor.epydoc.markup import ParsedDocstring
from pydoctor.sphinx import CacheT, SphinxInventory

Expand All @@ -53,12 +53,6 @@
# Functions can't contain anything.


_string_lineno_is_end = sys.version_info < (3,8) \
and platform.python_implementation() != 'PyPy'
"""True iff the 'lineno' attribute of an AST string node points to the last
line in the string, rather than the first line.
"""


class DocLocation(Enum):
OWN_PAGE = 1
Expand Down Expand Up @@ -158,7 +152,7 @@ def doctarget(self) -> 'Documentable':
def setup(self) -> None:
self.contents: Dict[str, Documentable] = {}
self._linker: Optional['linker.DocstringLinker'] = None
self.scope: Optional['Scope'] = None
self._stmt: Optional[symbols.Statement] = None
"""
If this documentable represents a L{Scope}, then it's stored here by the builder.
"""
Expand Down Expand Up @@ -227,11 +221,7 @@ def url(self) -> str:
return f'{page_url}#{quote(self.name)}'

def fullName(self) -> str:
parent = self.parent
if parent is None:
return self.name
else:
return f'{parent.fullName()}.{self.name}'
return symbols.HasNameAndParent.fullName(self)

def __repr__(self) -> str:
return f"{self.__class__.__name__} {self.fullName()!r}"
Expand Down Expand Up @@ -297,10 +287,24 @@ class E:
In the context of mod2.E, expandName("RenamedExternal") should be
"external_location.External" and expandName("renamed_mod.Local")
should be "mod1.Local". """
def localNameToFullName(o:Documentable, n:str) ->str:
try:
full_name = obj._localNameToFullName(p)
except LookupError:
# Fallback to symbols.localNameToFullName() if possible.
if obj._stmt is not None:
try:
full_name = symbols.localNameToFullName(obj._stmt, obj._stmt, name)
except LookupError:
full_name = p
else:
full_name = p
return full_name

parts = name.split('.')
obj: Documentable = self
for i, p in enumerate(parts):
full_name = obj._localNameToFullName(p)
full_name = localNameToFullName(obj, p)
if full_name == p and i != 0:
# The local name was not found.
# If we're looking at a class, we try our luck with the inherited members
Expand All @@ -310,8 +314,6 @@ class E:
full_name = inherited.fullName()
if full_name == p:
# We don't have a full name
# TODO: Instead of returning the input, _localNameToFullName()
# should probably either return None or raise LookupError.
full_name = f'{obj.fullName()}.{p}'
break
nxt = self.system.objForFullName(full_name)
Expand Down Expand Up @@ -455,7 +457,7 @@ def _localNameToFullName(self, name: str) -> str:
elif name in self._localNameToFullName_map:
return self._localNameToFullName_map[name]
else:
return name
raise LookupError()

@property
def module(self) -> 'Module':
Expand Down
Loading

0 comments on commit 4834757

Please sign in to comment.