Skip to content

Commit d400cb1

Browse files
committed
refactor: Preserve alias members path by re-aliasing members instead of returning target's members
1 parent 5bf0746 commit d400cb1

2 files changed

Lines changed: 71 additions & 86 deletions

File tree

src/griffe/dataclasses.py

Lines changed: 12 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -420,15 +420,6 @@ def inherited_members(self) -> dict[str, Alias]:
420420
inherited_members[name] = Alias(name, member, parent=self, inherited=True)
421421
return inherited_members
422422

423-
@property
424-
def all_members(self) -> dict[str, Object | Alias]:
425-
"""All members (declared and inherited).
426-
427-
This method is part of the consumer API:
428-
do not use when producing Griffe trees!
429-
"""
430-
return {**self.inherited_members, **self.members}
431-
432423
@property
433424
def is_module(self) -> bool:
434425
"""Tell if this object is a module."""
@@ -477,54 +468,6 @@ def filter_members(self, *predicates: Callable[[Object | Alias], bool]) -> dict[
477468
members[name] = member
478469
return members
479470

480-
@property
481-
def modules(self) -> dict[str, Module]:
482-
"""Return the module members.
483-
484-
This method is part of the consumer API:
485-
do not use when producing Griffe trees!
486-
487-
Returns:
488-
A dictionary of modules.
489-
"""
490-
return {name: member for name, member in self.all_members.items() if member.kind is Kind.MODULE} # type: ignore[misc]
491-
492-
@property
493-
def classes(self) -> dict[str, Class]:
494-
"""Return the class members.
495-
496-
This method is part of the consumer API:
497-
do not use when producing Griffe trees!
498-
499-
Returns:
500-
A dictionary of classes.
501-
"""
502-
return {name: member for name, member in self.all_members.items() if member.kind is Kind.CLASS} # type: ignore[misc]
503-
504-
@property
505-
def functions(self) -> dict[str, Function]:
506-
"""Return the function members.
507-
508-
This method is part of the consumer API:
509-
do not use when producing Griffe trees!
510-
511-
Returns:
512-
A dictionary of functions.
513-
"""
514-
return {name: member for name, member in self.all_members.items() if member.kind is Kind.FUNCTION} # type: ignore[misc]
515-
516-
@property
517-
def attributes(self) -> dict[str, Attribute]:
518-
"""Return the attribute members.
519-
520-
This method is part of the consumer API:
521-
do not use when producing Griffe trees!
522-
523-
Returns:
524-
A dictionary of attributes.
525-
"""
526-
return {name: member for name, member in self.all_members.items() if member.kind is Kind.ATTRIBUTE} # type: ignore[misc]
527-
528471
@property
529472
def module(self) -> Module:
530473
"""Return the parent module of this object.
@@ -798,7 +741,7 @@ def __init__(
798741
lineno: int | None = None,
799742
endlineno: int | None = None,
800743
runtime: bool = True,
801-
parent: Module | Class | None = None,
744+
parent: Module | Class | Alias | None = None,
802745
inherited: bool = False,
803746
) -> None:
804747
"""Initialize the alias.
@@ -818,7 +761,7 @@ def __init__(
818761
self.alias_endlineno: int | None = endlineno
819762
self.runtime: bool = runtime
820763
self.inherited: bool = inherited
821-
self._parent: Module | Class | None = parent
764+
self._parent: Module | Class | Alias | None = parent
822765
self._passed_through: bool = False
823766
if isinstance(target, str):
824767
self._target: Object | Alias | None = None
@@ -896,7 +839,7 @@ def has_docstrings(self) -> bool:
896839
return False
897840

898841
@property
899-
def parent(self) -> Module | Class | None:
842+
def parent(self) -> Module | Class | Alias | None:
900843
"""Return the parent of this alias.
901844
902845
Returns:
@@ -905,7 +848,7 @@ def parent(self) -> Module | Class | None:
905848
return self._parent
906849

907850
@parent.setter
908-
def parent(self, value: Module | Class) -> None:
851+
def parent(self, value: Module | Class | Alias) -> None:
909852
self._parent = value
910853
self._update_target_aliases()
911854

@@ -938,9 +881,10 @@ def docstring(self) -> Docstring | None: # noqa: D102
938881
def docstring(self, docstring: Docstring | None) -> None:
939882
self.final_target.docstring = docstring
940883

941-
@property
884+
@cached_property
942885
def members(self) -> dict[str, Object | Alias]: # noqa: D102
943-
return self.final_target.members
886+
final_target = self.final_target
887+
return {name: Alias(name, target=member, parent=self) for name, member in final_target.members.items()}
944888

945889
@property
946890
def labels(self) -> set[str]: # noqa: D102
@@ -961,13 +905,12 @@ def aliases(self) -> dict[str, Alias]: # noqa: D102
961905
def member_is_exported(self, member: Object | Alias, *, explicitely: bool = True) -> bool: # noqa: D102
962906
return self.final_target.member_is_exported(member, explicitely=explicitely)
963907

964-
@property
908+
@cached_property
965909
def inherited_members(self) -> dict[str, Alias]: # noqa: D102
966-
return self.final_target.inherited_members
967-
968-
@property
969-
def all_members(self) -> dict[str, Object | Alias]: # noqa: D102
970-
return self.final_target.all_members
910+
final_target = self.final_target
911+
return {
912+
name: Alias(name, target=member, parent=self) for name, member in final_target.inherited_members.items()
913+
}
971914

972915
def is_kind(self, kind: str | Kind | set[str | Kind]) -> bool: # noqa: D102
973916
return self.final_target.is_kind(kind)
@@ -994,22 +937,6 @@ def has_labels(self, labels: set[str]) -> bool: # noqa: D102
994937
def filter_members(self, *predicates: Callable[[Object | Alias], bool]) -> dict[str, Object | Alias]: # noqa: D102
995938
return self.final_target.filter_members(*predicates)
996939

997-
@property
998-
def modules(self) -> dict[str, Module]: # noqa: D102
999-
return self.final_target.modules
1000-
1001-
@property
1002-
def classes(self) -> dict[str, Class]: # noqa: D102
1003-
return self.final_target.classes
1004-
1005-
@property
1006-
def functions(self) -> dict[str, Function]: # noqa: D102
1007-
return self.final_target.functions
1008-
1009-
@property
1010-
def attributes(self) -> dict[str, Attribute]: # noqa: D102
1011-
return self.final_target.attributes
1012-
1013940
@property
1014941
def module(self) -> Module: # noqa: D102
1015942
return self.final_target.module

src/griffe/mixins.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
from contextlib import suppress
77
from typing import TYPE_CHECKING, Any, Sequence, TypeVar
88

9+
from griffe.enumerations import Kind
910
from griffe.exceptions import AliasResolutionError, CyclicAliasError
1011
from griffe.logger import get_logger
1112
from griffe.merger import merge_stubs
1213

1314
if TYPE_CHECKING:
14-
from griffe.dataclasses import Alias, Object
15+
from griffe.dataclasses import Alias, Attribute, Class, Function, Module, Object
1516

1617
logger = get_logger(__name__)
1718
_ObjType = TypeVar("_ObjType")
@@ -206,6 +207,63 @@ def set_member(self, key: str | Sequence[str], value: Object | Alias) -> None:
206207
class ObjectAliasMixin:
207208
"""A mixin for methods that appear both in objects and aliases, unchanged."""
208209

210+
@property
211+
def all_members(self) -> dict[str, Object | Alias]:
212+
"""All members (declared and inherited).
213+
214+
This method is part of the consumer API:
215+
do not use when producing Griffe trees!
216+
"""
217+
return {**self.inherited_members, **self.members} # type: ignore[attr-defined]
218+
219+
@property
220+
def modules(self) -> dict[str, Module]:
221+
"""Return the module members.
222+
223+
This method is part of the consumer API:
224+
do not use when producing Griffe trees!
225+
226+
Returns:
227+
A dictionary of modules.
228+
"""
229+
return {name: member for name, member in self.all_members.items() if member.kind is Kind.MODULE} # type: ignore[misc]
230+
231+
@property
232+
def classes(self) -> dict[str, Class]:
233+
"""Return the class members.
234+
235+
This method is part of the consumer API:
236+
do not use when producing Griffe trees!
237+
238+
Returns:
239+
A dictionary of classes.
240+
"""
241+
return {name: member for name, member in self.all_members.items() if member.kind is Kind.CLASS} # type: ignore[misc]
242+
243+
@property
244+
def functions(self) -> dict[str, Function]:
245+
"""Return the function members.
246+
247+
This method is part of the consumer API:
248+
do not use when producing Griffe trees!
249+
250+
Returns:
251+
A dictionary of functions.
252+
"""
253+
return {name: member for name, member in self.all_members.items() if member.kind is Kind.FUNCTION} # type: ignore[misc]
254+
255+
@property
256+
def attributes(self) -> dict[str, Attribute]:
257+
"""Return the attribute members.
258+
259+
This method is part of the consumer API:
260+
do not use when producing Griffe trees!
261+
262+
Returns:
263+
A dictionary of attributes.
264+
"""
265+
return {name: member for name, member in self.all_members.items() if member.kind is Kind.ATTRIBUTE} # type: ignore[misc]
266+
209267
def is_exported(self, *, explicitely: bool = True) -> bool:
210268
"""Tell if this object/alias is implicitely exported by its parent.
211269

0 commit comments

Comments
 (0)