Skip to content

Commit 4791b0b

Browse files
committed
fix: Don't conflate passed argument with class member (instance attribute)
Issue-357: #357
1 parent da6a070 commit 4791b0b

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/_griffe/expressions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,9 @@ def canonical_path(self) -> str:
150150

151151
@property
152152
def canonical_name(self) -> str:
153-
"""Name of the expressed name/attribute."""
154-
return self.canonical_path.rsplit(".", 1)[-1]
153+
"""Name of the expressed name/attribute/parameter."""
154+
# We must handle things like `griffe.Visitor` and `griffe.Visitor(code)`.
155+
return self.canonical_path.rsplit(".", 1)[-1].split("(", 1)[-1].removesuffix(")")
155156

156157
@property
157158
def is_classvar(self) -> bool:

src/_griffe/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,6 +2063,23 @@ def annotation(self) -> str | Expr | None:
20632063
"""The type annotation of the returned value."""
20642064
return self.returns
20652065

2066+
def resolve(self, name: str) -> str:
2067+
"""Resolve a name within this object's and parents' scope.
2068+
2069+
Parameters:
2070+
name: The name to resolve.
2071+
2072+
Raises:
2073+
NameResolutionError: When the name could not be resolved.
2074+
2075+
Returns:
2076+
The resolved name.
2077+
"""
2078+
# We're in an `__init__` method and name is a parameter name.
2079+
if self.parent and self.name == "__init__" and name in self.parameters:
2080+
return f"{self.parent.path}({name})"
2081+
return super().resolve(name)
2082+
20662083
def as_dict(self, **kwargs: Any) -> dict[str, Any]:
20672084
"""Return this function's data as a dictionary.
20682085

tests/test_expressions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,21 @@ def test_length_one_tuple_as_string() -> None:
9292
code = "x = ('a',)"
9393
with temporary_visited_module(code) as module:
9494
assert str(module["x"].value) == "('a',)"
95+
96+
97+
def test_resolving_init_parameter() -> None:
98+
"""Instance attribute values should resolve to matching parameters.
99+
100+
They must not resolve to the member of the same name in the same class,
101+
or to objects with the same name in higher scopes.
102+
"""
103+
with temporary_visited_module(
104+
"""
105+
x = 1
106+
107+
class Class:
108+
def __init__(self, x: int):
109+
self.x: int = x
110+
""",
111+
) as module:
112+
assert module["Class.x"].value.canonical_path == "module.Class(x)"

0 commit comments

Comments
 (0)