Skip to content

Commit ee1df17

Browse files
authored
New semantic analyzer: Enable namedtuple tests and fix self-check error (#6452)
This fixes the `Name 'cls' already defined error` in self-check with new analyzer. The error is caused by the fact that now we actually analyze generated methods. I solve them simply by using underscored versions of `_self` and `_cls` (this is btw the same what runtime implementation does for some generated methods). I also enable both named tuple test files. This needs the same temporary redundant variable hack as I did for typed dicts, it can be removed when we will not need to be compatible with old analyzer, I will create an issue so we will not forget about this. I skip a bunch of test cases for recursive named tuples (there is already an issue for this). I also skip one test because it is tricky to fix, I will open a follow-up issue.
1 parent 3f7444a commit ee1df17

File tree

5 files changed

+39
-19
lines changed

5 files changed

+39
-19
lines changed

mypy/newsemanal/semanal.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,6 +1915,16 @@ def analyze_namedtuple_assign(self, s: AssignmentStmt) -> bool:
19151915
# Yes, it's a valid namedtuple, but defer if it is not ready.
19161916
if not info:
19171917
self.mark_incomplete(name, lvalue, becomes_typeinfo=True)
1918+
else:
1919+
# TODO: This is needed for one-to-one compatibility with old analyzer, otherwise
1920+
# type checker will try to infer Any for the l.h.s. causing named tuple class
1921+
# object to have type Any when it appears in runtime context.
1922+
# Remove this and update the checker after new analyzer is the default one!
1923+
# See also #6458.
1924+
lvalue.fullname = self.qualified_name(name)
1925+
lvalue.is_inferred_def = True
1926+
lvalue.kind = kind = self.current_symbol_kind()
1927+
lvalue.node = self.make_name_lvalue_var(lvalue, kind, inferred=True)
19181928
return True
19191929

19201930
def analyze_typeddict_assign(self, s: AssignmentStmt) -> bool:

mypy/newsemanal/semanal_namedtuple.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,9 @@ def add_method(funcname: str,
407407
is_new: bool = False,
408408
) -> None:
409409
if is_classmethod or is_new:
410-
first = [Argument(Var('cls'), TypeType.make_normalized(selftype), None, ARG_POS)]
410+
first = [Argument(Var('_cls'), TypeType.make_normalized(selftype), None, ARG_POS)]
411411
else:
412-
first = [Argument(Var('self'), selftype, None, ARG_POS)]
412+
first = [Argument(Var('_self'), selftype, None, ARG_POS)]
413413
args = first + args
414414

415415
types = [arg.type_annotation for arg in args]

mypy/test/hacks.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
'check-callable.test',
1313
'check-classes.test',
1414
'check-classvar.test',
15-
'check-class-namedtuple.test',
1615
'check-custom-plugin.test',
1716
'check-dataclasses.test',
1817
'check-default-plugin.test',
@@ -28,7 +27,6 @@
2827
'check-literal.test',
2928
'check-modules.test',
3029
'check-multiple-inheritance.test',
31-
'check-namedtuple.test',
3230
'check-newtype.test',
3331
'check-optional.test',
3432
'check-overloading.test',

test-data/unit/check-class-namedtuple.test

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,9 @@ reveal_type(takes_base(Base(1))) # E: Revealed type is 'builtins.int'
587587
reveal_type(takes_base(Child(1))) # E: Revealed type is 'builtins.int'
588588
[builtins fixtures/tuple.pyi]
589589

590+
-- Depends on collecting functions via AST, not symbol tables.
590591
[case testNewNamedTupleIllegalNames]
592+
# flags: --no-new-semantic-analyzer
591593
from typing import Callable, NamedTuple
592594

593595
class XMethBad(NamedTuple):
@@ -612,16 +614,16 @@ class AnnotationsAsAMethod(NamedTuple):
612614

613615
class ReuseNames(NamedTuple):
614616
x: int
615-
def x(self) -> str: # E: Name 'x' already defined on line 22
617+
def x(self) -> str: # E: Name 'x' already defined on line 23
616618
return ''
617619

618620
def y(self) -> int:
619621
return 0
620-
y: str # E: Name 'y' already defined on line 26
622+
y: str # E: Name 'y' already defined on line 27
621623

622624
class ReuseCallableNamed(NamedTuple):
623625
z: Callable[[ReuseNames], int]
624-
def z(self) -> int: # E: Name 'z' already defined on line 31
626+
def z(self) -> int: # E: Name 'z' already defined on line 32
625627
return 0
626628

627629
[builtins fixtures/dict.pyi]

test-data/unit/check-namedtuple.test

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -346,12 +346,13 @@ x._replace(5) # E: Too many positional arguments for "_replace" of "X"
346346
[builtins fixtures/list.pyi]
347347

348348
[case testNamedTupleReplaceAsClass]
349+
# flags: --new-semantic-analyzer --no-strict-optional
349350
from collections import namedtuple
350351

351352
X = namedtuple('X', ['x', 'y'])
352353
x = None # type: X
353354
X._replace(x, x=1, y=2)
354-
X._replace(x=1, y=2) # E: Missing positional argument "self" in call to "_replace" of "X"
355+
X._replace(x=1, y=2) # E: Missing positional argument "_self" in call to "_replace" of "X"
355356

356357
[builtins fixtures/list.pyi]
357358

@@ -497,7 +498,9 @@ b = B._make(['']) # type: B
497498

498499
[builtins fixtures/list.pyi]
499500

501+
-- Depends on tuple fallback PR
500502
[case testNamedTupleIncompatibleRedefinition]
503+
# flags: --no-new-semantic-analyzer
501504
from typing import NamedTuple
502505
class Crash(NamedTuple):
503506
count: int # E: Incompatible types in assignment (expression has type "int", base class "tuple" defined the type as "Callable[[Tuple[int, ...], Any], int]")
@@ -573,6 +576,7 @@ tmp/b.py:4: error: Revealed type is 'Tuple[Any, fallback=a.N]'
573576
tmp/b.py:7: error: Revealed type is 'Tuple[Any, fallback=a.N]'
574577

575578
[case testSimpleSelfReferentialNamedTuple]
579+
# flags: --no-new-semantic-analyzer
576580
from typing import NamedTuple
577581
class MyNamedTuple(NamedTuple):
578582
parent: 'MyNamedTuple'
@@ -583,8 +587,8 @@ def bar(nt: MyNamedTuple) -> MyNamedTuple:
583587
x: MyNamedTuple
584588
reveal_type(x.parent)
585589
[out]
586-
main:2: error: Recursive types not fully supported yet, nested types replaced with "Any"
587-
main:9: error: Revealed type is 'Tuple[Any, fallback=__main__.MyNamedTuple]'
590+
main:3: error: Recursive types not fully supported yet, nested types replaced with "Any"
591+
main:10: error: Revealed type is 'Tuple[Any, fallback=__main__.MyNamedTuple]'
588592

589593
-- Some crazy self-referential named tuples and types dicts
590594
-- to be sure that everything works
@@ -611,6 +615,7 @@ class B:
611615
[out]
612616

613617
[case testSelfRefNT1]
618+
# flags: --no-new-semantic-analyzer
614619
from typing import Tuple, NamedTuple
615620

616621
Node = NamedTuple('Node', [ # E: Recursive types not fully supported yet, nested types replaced with "Any"
@@ -623,6 +628,7 @@ reveal_type(n) # E: Revealed type is 'Tuple[builtins.str, builtins.tuple[Tuple[b
623628

624629

625630
[case testSelfRefNT2]
631+
# flags: --no-new-semantic-analyzer
626632
from typing import Tuple, NamedTuple
627633

628634
A = NamedTuple('A', [ # E
@@ -637,10 +643,11 @@ n: A
637643
reveal_type(n) # E: Revealed type is 'Tuple[builtins.str, builtins.tuple[Tuple[Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.A], builtins.int, fallback=__main__.B]], fallback=__main__.A]'
638644
[builtins fixtures/tuple.pyi]
639645
[out]
640-
main:3: error: Recursive types not fully supported yet, nested types replaced with "Any"
641-
main:7: error: Recursive types not fully supported yet, nested types replaced with "Any"
646+
main:4: error: Recursive types not fully supported yet, nested types replaced with "Any"
647+
main:8: error: Recursive types not fully supported yet, nested types replaced with "Any"
642648

643649
[case testSelfRefNT3]
650+
# flags: --no-new-semantic-analyzer
644651
from typing import NamedTuple, Tuple
645652

646653
class B(NamedTuple): # E
@@ -659,9 +666,10 @@ lst = [m, n]
659666
reveal_type(lst[0]) # E: Revealed type is 'Tuple[builtins.object, builtins.object]'
660667
[builtins fixtures/tuple.pyi]
661668
[out]
662-
main:3: error: Recursive types not fully supported yet, nested types replaced with "Any"
669+
main:4: error: Recursive types not fully supported yet, nested types replaced with "Any"
663670

664671
[case testSelfRefNT4]
672+
# flags: --no-new-semantic-analyzer
665673
from typing import NamedTuple
666674

667675
class B(NamedTuple): # E
@@ -676,10 +684,11 @@ n: A
676684
reveal_type(n.y[0]) # E: Revealed type is 'Tuple[builtins.str, Tuple[Any, builtins.int, fallback=__main__.B], fallback=__main__.A]'
677685
[builtins fixtures/tuple.pyi]
678686
[out]
679-
main:3: error: Recursive types not fully supported yet, nested types replaced with "Any"
680-
main:7: error: Recursive types not fully supported yet, nested types replaced with "Any"
687+
main:4: error: Recursive types not fully supported yet, nested types replaced with "Any"
688+
main:8: error: Recursive types not fully supported yet, nested types replaced with "Any"
681689

682690
[case testSelfRefNT5]
691+
# flags: --no-new-semantic-analyzer
683692
from typing import NamedTuple
684693

685694
B = NamedTuple('B', [ # E: Recursive types not fully supported yet, nested types replaced with "Any"
@@ -697,6 +706,7 @@ reveal_type(f) # E: Revealed type is 'def (m: Tuple[Tuple[builtins.str, Tuple[An
697706
[builtins fixtures/tuple.pyi]
698707

699708
[case testRecursiveNamedTupleInBases]
709+
# flags: --no-new-semantic-analyzer
700710
from typing import List, NamedTuple, Union
701711

702712
Exp = Union['A', 'B'] # E: Recursive types not fully supported yet, nested types replaced with "Any"
@@ -716,6 +726,7 @@ my_eval(A([B(1), B(2)])) # OK
716726
[out]
717727

718728
[case testNamedTupleImportCycle]
729+
# flags: --new-semantic-analyzer
719730
import b
720731
[file a.py]
721732
class C:
@@ -725,10 +736,8 @@ from b import tp
725736
x: tp
726737
reveal_type(x.x) # E: Revealed type is 'builtins.int'
727738

728-
# Unfortunately runtime part doesn't work yet, see docstring in SemanticAnalyzerPass3.update_imported_vars()
729-
reveal_type(tp) # E: Revealed type is 'Any' \
730-
# E: Cannot determine type of 'tp'
731-
tp('x') # E: Cannot determine type of 'tp'
739+
reveal_type(tp) # E: Revealed type is 'def (x: builtins.int) -> Tuple[builtins.int, fallback=b.tp]'
740+
tp('x') # E: Argument 1 to "tp" has incompatible type "str"; expected "int"
732741

733742
[file b.py]
734743
from a import C
@@ -738,6 +747,7 @@ tp = NamedTuple('tp', [('x', int)])
738747
[out]
739748

740749
[case testSubclassOfRecursiveNamedTuple]
750+
# flags: --no-new-semantic-analyzer
741751
from typing import List, NamedTuple
742752

743753
class Command(NamedTuple): # type: ignore

0 commit comments

Comments
 (0)