Skip to content

Commit 31defe3

Browse files
ilevkivskyiGuido van Rossum
authored and
Guido van Rossum
committed
Fix spurious error on acessing class names defined on self (#3719)
Fixes #3713 The idea is just to not show an error when accessing in the class body an attribute defined on ``self`` (mypy does not distinguishes them anyway). As well, the correct node is returned on lookup, previously this resulted in some spurious ``Any`` types. (In addition I enable two previously skipped test, just noticed them when added tests for this PR.)
1 parent 9ede13b commit 31defe3

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

mypy/semanal.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,7 @@ def tvar_scope_frame(self, frame: TypeVarScope) -> Iterator[None]:
33843384

33853385
def lookup(self, name: str, ctx: Context) -> SymbolTableNode:
33863386
"""Look up an unqualified name in all active namespaces."""
3387+
implicit_name = False
33873388
# 1a. Name declared using 'global x' takes precedence
33883389
if name in self.global_decls[-1]:
33893390
if name in self.globals:
@@ -3404,6 +3405,8 @@ def lookup(self, name: str, ctx: Context) -> SymbolTableNode:
34043405
node = self.type.names[name]
34053406
if not node.implicit:
34063407
return node
3408+
implicit_name = True
3409+
implicit_node = node
34073410
# 3. Local (function) scopes
34083411
for table in reversed(self.locals):
34093412
if table is not None and name in table:
@@ -3423,8 +3426,11 @@ def lookup(self, name: str, ctx: Context) -> SymbolTableNode:
34233426
node = table[name]
34243427
return node
34253428
# Give up.
3426-
self.name_not_defined(name, ctx)
3427-
self.check_for_obsolete_short_name(name, ctx)
3429+
if not implicit_name:
3430+
self.name_not_defined(name, ctx)
3431+
self.check_for_obsolete_short_name(name, ctx)
3432+
else:
3433+
return implicit_node
34283434
return None
34293435

34303436
def check_for_obsolete_short_name(self, name: str, ctx: Context) -> None:

test-data/unit/check-classes.test

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,43 @@ class A:
198198
main:6: error: Incompatible types in assignment (expression has type "str", variable has type "int")
199199
main:8: error: Incompatible types in assignment (expression has type "str", variable has type "int")
200200

201+
[case testClassNamesDefinedOnSelUsedInClassBody]
202+
class A(object):
203+
def f(self):
204+
self.attr = 1
205+
attr = 0
206+
207+
class B(object):
208+
attr = 0
209+
def f(self):
210+
self.attr = 1
211+
212+
class C(object):
213+
attr = 0
214+
def f(self):
215+
self.attr = 1
216+
attr = 0
217+
218+
class D(object):
219+
def g(self):
220+
self.attr = 1
221+
attr = 0
222+
def f(self):
223+
self.attr = 1
224+
[out]
225+
226+
[case testClassNamesDefinedOnSelUsedInClassBodyReveal]
227+
class A(object):
228+
def f(self) -> None:
229+
self.attr = 1
230+
reveal_type(attr) # E: Revealed type is 'builtins.int'
231+
232+
class B(object):
233+
attr = 0
234+
def f(self) -> None:
235+
reveal_type(self.attr) # E: Revealed type is 'builtins.int'
236+
[out]
237+
201238

202239
-- Method overriding
203240
-- -----------------
@@ -3386,9 +3423,7 @@ NT([])
33863423
[builtins fixtures/dict.pyi]
33873424
[out]
33883425

3389-
-- The two tests below will not crash after
3390-
-- https://github.com/python/mypy/issues/3319 is fixed
3391-
[case testCrashForwardSyntheticClassSyntax-skip]
3426+
[case testCrashForwardSyntheticClassSyntax]
33923427
from typing import NamedTuple
33933428
from mypy_extensions import TypedDict
33943429
class A1(NamedTuple):
@@ -3406,7 +3441,7 @@ reveal_type(y['b']) # E: Revealed type is '__main__.B'
34063441
[builtins fixtures/dict.pyi]
34073442
[out]
34083443

3409-
[case testCrashForwardSyntheticFunctionSyntax-skip]
3444+
[case testCrashForwardSyntheticFunctionSyntax]
34103445
from typing import NamedTuple
34113446
from mypy_extensions import TypedDict
34123447
A1 = NamedTuple('A1', [('b', 'B'), ('x', int)])

0 commit comments

Comments
 (0)