Skip to content

Commit

Permalink
fix: Detect cyclic aliases and prevent resolution errors
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Jan 2, 2022
1 parent 5b5c63b commit de5dd12
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 5 deletions.
18 changes: 13 additions & 5 deletions src/griffe/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from griffe.collections import LinesCollection, ModulesCollection
from griffe.docstrings.dataclasses import DocstringSection
from griffe.docstrings.parsers import Parser, parse # noqa: WPS347
from griffe.exceptions import AliasResolutionError, BuiltinModuleError, NameResolutionError
from griffe.exceptions import AliasResolutionError, BuiltinModuleError, CyclicAliasError, NameResolutionError
from griffe.expressions import Expression, Name
from griffe.mixins import GetMembersMixin, ObjectAliasMixin, SetMembersMixin

Expand Down Expand Up @@ -703,15 +703,22 @@ def __init__(
else:
self._target = target
self._target_path = target.path
if self.parent is not None:
target.aliases[self.path] = self
if parent is not None:
with suppress(AliasResolutionError):
target.aliases[self.path] = self
self.lineno: int | None = lineno
self.endlineno: int | None = endlineno
self._parent: Module | Class | None = parent
self._passed_through: bool = False

def __getattr__(self, name: str) -> Any:
# forward everything to the target
return getattr(self.target, name)
if self._passed_through:
raise CyclicAliasError
self._passed_through = True
attr = getattr(self.target, name)
self._passed_through = False
return attr

def __getitem__(self, key):
# not handled by __getattr__
Expand Down Expand Up @@ -747,7 +754,8 @@ def parent(self) -> Module | Class | None:
def parent(self, value: Module | Class) -> None:
self._parent = value
if self.resolved:
self._target.aliases[self.path] = self # type: ignore[union-attr] # we just checked the target is not None
with suppress(AliasResolutionError):
self._target.aliases[self.path] = self # type: ignore[union-attr] # we just checked the target is not None

@cached_property
def path(self) -> str:
Expand Down
4 changes: 4 additions & 0 deletions src/griffe/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def __init__(self, target_path: str) -> None:
super().__init__(f"could not resolve {self.target_path}")


class CyclicAliasError(GriffeError):
"""Exception raised when a cycle is detected in aliases."""


class LastNodeError(GriffeError):
"""Exception raised when trying to access a next or previous node."""

Expand Down

0 comments on commit de5dd12

Please sign in to comment.