Skip to content

Commit

Permalink
Display ellipsis when formatting variadic tuple[T, ...] (python#11857)
Browse files Browse the repository at this point in the history
Previously variadic tuples were displayed as `builtins.tuple[T]`, which
is misleading. That syntax ordinarily indicates a tuple with a single
element. This change adds the `...` ellipsis when formatting.

The formatting of non-variadic tuples is unchanged (e.g. `Tuple[T, U]`).

Fixes python#9522
  • Loading branch information
intgr authored and tushar-deepsource committed Jan 20, 2022
1 parent 082e47a commit dd240f7
Show file tree
Hide file tree
Showing 17 changed files with 83 additions and 79 deletions.
8 changes: 6 additions & 2 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,7 @@ class TupleType(ProperType):
Instance variables:
items: Tuple item types
partial_fallback: The (imprecise) underlying instance type that is used
for non-tuple methods. This is generally builtins.tuple[Any] for
for non-tuple methods. This is generally builtins.tuple[Any, ...] for
regular tuples, but it's different for named tuples and classes with
a tuple base class. Use mypy.typeops.tuple_fallback to calculate the
precise fallback type derived from item types.
Expand Down Expand Up @@ -2203,7 +2203,11 @@ def visit_instance(self, t: Instance) -> str:
if t.erased:
s += '*'
if t.args:
s += '[{}]'.format(self.list_str(t.args))
if t.type.fullname == 'builtins.tuple':
assert len(t.args) == 1
s += '[{}, ...]'.format(self.list_str(t.args))
else:
s += '[{}]'.format(self.list_str(t.args))
if self.id_mapper:
s += '<{}>'.format(self.id_mapper.id(t.type))
return s
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-annotated.test
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ from typing import Tuple
from typing_extensions import Annotated
Alias = Annotated[Tuple[int, ...], ...]
x: Alias
reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(x) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/tuple.pyi]

[case testAnnotatedAliasTypeVar]
Expand Down
8 changes: 4 additions & 4 deletions test-data/unit/check-fastparse.test
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def f(a, # type: A
):
reveal_type(a) # N: Revealed type is "__main__.A"
reveal_type(b) # N: Revealed type is "Union[__main__.B, None]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]"
reveal_type(d) # N: Revealed type is "Union[__main__.D, None]"
reveal_type(e) # N: Revealed type is "__main__.E"
reveal_type(kwargs) # N: Revealed type is "builtins.dict[builtins.str, __main__.F]"
Expand All @@ -179,7 +179,7 @@ def f(a, # type: A
# type: (...) -> int
reveal_type(a) # N: Revealed type is "__main__.A"
reveal_type(b) # N: Revealed type is "Union[__main__.B, None]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]"
reveal_type(d) # N: Revealed type is "Union[__main__.D, None]"
reveal_type(e) # N: Revealed type is "__main__.E"
reveal_type(kwargs) # N: Revealed type is "builtins.dict[builtins.str, __main__.F]"
Expand Down Expand Up @@ -221,7 +221,7 @@ def f(a, # type: A
):
reveal_type(a) # N: Revealed type is "__main__.A"
reveal_type(b) # N: Revealed type is "Union[__main__.B, None]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]"
[builtins fixtures/dict.pyi]
[out]

Expand All @@ -239,7 +239,7 @@ def f(a, # type: A
# type: (...) -> int
reveal_type(a) # N: Revealed type is "__main__.A"
reveal_type(b) # N: Revealed type is "Union[__main__.B, None]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C]"
reveal_type(args) # N: Revealed type is "builtins.tuple[__main__.C, ...]"
return "not an int" # E: Incompatible return value type (got "str", expected "int")
[builtins fixtures/dict.pyi]
[out]
Expand Down
8 changes: 4 additions & 4 deletions test-data/unit/check-generic-alias.test
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ t11: type[int]
reveal_type(t1) # N: Revealed type is "builtins.list[Any]"
reveal_type(t2) # N: Revealed type is "builtins.list[builtins.int]"
reveal_type(t3) # N: Revealed type is "builtins.list[builtins.str]"
reveal_type(t4) # N: Revealed type is "builtins.tuple[Any]"
reveal_type(t4) # N: Revealed type is "builtins.tuple[Any, ...]"
# TODO: ideally these would reveal builtins.tuple
reveal_type(t5) # N: Revealed type is "Tuple[builtins.int]"
reveal_type(t6) # N: Revealed type is "Tuple[builtins.int, builtins.str]"
# TODO: this is incorrect, see #9522
reveal_type(t7) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(t7) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(t8) # N: Revealed type is "builtins.dict[Any, Any]"
reveal_type(t9) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]"
reveal_type(t10) # N: Revealed type is "builtins.type"
Expand Down Expand Up @@ -252,13 +252,13 @@ B = tuple[int, str]
x: B = (1, 'x')
y: B = ('x', 1) # E: Incompatible types in assignment (expression has type "Tuple[str, int]", variable has type "Tuple[int, str]")

reveal_type(tuple[int, ...]()) # N: Revealed type is "builtins.tuple[builtins.int*]"
reveal_type(tuple[int, ...]()) # N: Revealed type is "builtins.tuple[builtins.int*, ...]"
[builtins fixtures/tuple.pyi]

[case testTypeAliasWithBuiltinTupleInStub]
# flags: --python-version 3.6
import m
reveal_type(m.a) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(m.a) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(m.b) # N: Revealed type is "Tuple[builtins.int, builtins.str]"

[file m.pyi]
Expand Down
6 changes: 3 additions & 3 deletions test-data/unit/check-generics.test
Original file line number Diff line number Diff line change
Expand Up @@ -2073,9 +2073,9 @@ class Base(Generic[T]):
return (cls(item),)
return cls(item)

reveal_type(Base.make_some) # N: Revealed type is "Overload(def [T] (item: T`1) -> __main__.Base[T`1], def [T] (item: T`1, n: builtins.int) -> builtins.tuple[__main__.Base[T`1]])"
reveal_type(Base.make_some) # N: Revealed type is "Overload(def [T] (item: T`1) -> __main__.Base[T`1], def [T] (item: T`1, n: builtins.int) -> builtins.tuple[__main__.Base[T`1], ...])"
reveal_type(Base.make_some(1)) # N: Revealed type is "__main__.Base[builtins.int*]"
reveal_type(Base.make_some(1, 1)) # N: Revealed type is "builtins.tuple[__main__.Base[builtins.int*]]"
reveal_type(Base.make_some(1, 1)) # N: Revealed type is "builtins.tuple[__main__.Base[builtins.int*], ...]"

class Sub(Base[str]): ...
Sub.make_some(1) # E: No overload variant of "make_some" of "Base" matches argument type "int" \
Expand Down Expand Up @@ -2183,7 +2183,7 @@ class C(Generic[T]):
class D(C[str]): ...

reveal_type(D.get()) # N: Revealed type is "builtins.str*"
reveal_type(D.get(42)) # N: Revealed type is "builtins.tuple[builtins.str*]"
reveal_type(D.get(42)) # N: Revealed type is "builtins.tuple[builtins.str*, ...]"
[builtins fixtures/classmethod.pyi]

[case testGenericClassMethodAnnotation]
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-namedtuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ Node = NamedTuple('Node', [
('children', Tuple['Node', ...]), # E: Cannot resolve name "Node" (possible cyclic definition)
])
n: Node
reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.Node]"
reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ...], fallback=__main__.Node]"
[builtins fixtures/tuple.pyi]

[case testSelfRefNT2]
Expand All @@ -689,7 +689,7 @@ class B(NamedTuple):
y: int

n: A
reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.A]"
reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ...], fallback=__main__.A]"
[builtins fixtures/tuple.pyi]

[case testSelfRefNT3]
Expand Down
26 changes: 13 additions & 13 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -2589,12 +2589,12 @@ def f(*args): pass
i: int
reveal_type(f(i)) # N: Revealed type is "Tuple[builtins.int]"
reveal_type(f(i, i)) # N: Revealed type is "Tuple[builtins.int, builtins.int]"
reveal_type(f(i, i, i)) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(i, i, i)) # N: Revealed type is "builtins.tuple[builtins.int, ...]"

reveal_type(f(*[])) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*[i])) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*[i, i])) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*[i, i, i])) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*[])) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(*[i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(*[i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(*[i, i, i])) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/list.pyi]

[case testOverloadVarargsSelectionWithTuples]
Expand All @@ -2608,10 +2608,10 @@ def f(*xs: int) -> Tuple[int, ...]: ...
def f(*args): pass

i: int
reveal_type(f(*())) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*())) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(*(i,))) # N: Revealed type is "Tuple[builtins.int]"
reveal_type(f(*(i, i))) # N: Revealed type is "Tuple[builtins.int, builtins.int]"
reveal_type(f(*(i, i, i))) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*(i, i, i))) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/tuple.pyi]

[case testOverloadVarargsSelectionWithNamedTuples]
Expand All @@ -2631,7 +2631,7 @@ b: B
c: C
reveal_type(f(*a)) # N: Revealed type is "Tuple[builtins.int, builtins.int]"
reveal_type(f(*b)) # N: Revealed type is "Tuple[builtins.int, builtins.int]"
reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/tuple.pyi]

[case testOverloadKwargsSelectionWithDict]
Expand All @@ -2645,10 +2645,10 @@ def f(**xs: int) -> Tuple[int, ...]: ...
def f(**kwargs): pass

empty: Dict[str, int]
reveal_type(f(**empty)) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(**{'x': 4})) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(**{'x': 4, 'y': 4})) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(**{'a': 4, 'b': 4, 'c': 4})) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(**empty)) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(**{'x': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(**{'x': 4, 'y': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
reveal_type(f(**{'a': 4, 'b': 4, 'c': 4})) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/dict.pyi]

[case testOverloadKwargsSelectionWithTypedDict]
Expand All @@ -2672,7 +2672,7 @@ c: C

reveal_type(f(**a)) # N: Revealed type is "Tuple[builtins.int]"
reveal_type(f(**b)) # N: Revealed type is "Tuple[builtins.int, builtins.int]"
reveal_type(f(**c)) # N: Revealed type is "builtins.tuple[builtins.int]"
reveal_type(f(**c)) # N: Revealed type is "builtins.tuple[builtins.int, ...]"
[builtins fixtures/dict.pyi]

[case testOverloadVarargsAndKwargsSelection]
Expand Down
8 changes: 4 additions & 4 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,9 @@ reveal_type(P) # N: Revealed type is "Overload(def [T] (use_str: Literal[True])
reveal_type(P(use_str=True)) # N: Revealed type is "lib.P[builtins.str]"
reveal_type(P(use_str=False)) # N: Revealed type is "lib.P[builtins.int]"

reveal_type(C) # N: Revealed type is "Overload(def [T] (item: T`1, use_tuple: Literal[False]) -> lib.C[T`1], def [T] (item: T`1, use_tuple: Literal[True]) -> lib.C[builtins.tuple[T`1]])"
reveal_type(C) # N: Revealed type is "Overload(def [T] (item: T`1, use_tuple: Literal[False]) -> lib.C[T`1], def [T] (item: T`1, use_tuple: Literal[True]) -> lib.C[builtins.tuple[T`1, ...]])"
reveal_type(C(0, use_tuple=False)) # N: Revealed type is "lib.C[builtins.int*]"
reveal_type(C(0, use_tuple=True)) # N: Revealed type is "lib.C[builtins.tuple[builtins.int*]]"
reveal_type(C(0, use_tuple=True)) # N: Revealed type is "lib.C[builtins.tuple[builtins.int*, ...]]"

T = TypeVar('T')
class SubP(P[T]):
Expand Down Expand Up @@ -949,9 +949,9 @@ class Other(Base): ...
class Double(Sub): ...

reveal_type(Other.make()) # N: Revealed type is "__main__.Other*"
reveal_type(Other.make(3)) # N: Revealed type is "builtins.tuple[__main__.Other*]"
reveal_type(Other.make(3)) # N: Revealed type is "builtins.tuple[__main__.Other*, ...]"
reveal_type(Double.make()) # N: Revealed type is "__main__.Sub"
reveal_type(Double.make(3)) # N: Revealed type is "builtins.tuple[__main__.Sub]"
reveal_type(Double.make(3)) # N: Revealed type is "builtins.tuple[__main__.Sub, ...]"
[file lib.pyi]
from typing import overload, TypeVar, Type, Tuple

Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-serialize.test
Original file line number Diff line number Diff line change
Expand Up @@ -1030,8 +1030,8 @@ x: Tuple[int, ...]
y: tuple
[builtins fixtures/tuple.pyi]
[out2]
tmp/a.py:2: note: Revealed type is "builtins.tuple[builtins.int]"
tmp/a.py:3: note: Revealed type is "builtins.tuple[Any]"
tmp/a.py:2: note: Revealed type is "builtins.tuple[builtins.int, ...]"
tmp/a.py:3: note: Revealed type is "builtins.tuple[Any, ...]"

[case testSerializeNone]
import a
Expand Down
Loading

0 comments on commit dd240f7

Please sign in to comment.