Skip to content

Meaningful message with long tuple initializer #7995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4027,7 +4027,9 @@ def check_subtype(self,

subtype = get_proper_type(subtype)
supertype = get_proper_type(supertype)

if self.check_long_tuple_assignment(subtype, supertype, context, msg,
subtype_label, supertype_label, code=code):
return False
if self.should_suppress_optional_error([subtype]):
return False
extra_info = [] # type: List[str]
Expand Down Expand Up @@ -4378,6 +4380,61 @@ def infer_issubclass_maps(self, node: CallExpr,
yes_map, no_map = map(convert_to_typetype, (yes_map, no_map))
return yes_map, no_map

def check_long_tuple_assignment(self,
subtype: ProperType,
supertype: ProperType,
context: Context,
msg: str = message_registry.INCOMPATIBLE_TYPES,
subtype_label: Optional[str] = None,
supertype_label: Optional[str] = None,
code: Optional[ErrorCode] = None) -> bool:
"""Check if assignment error using long tuple initializers."""

def format_error_msg(msg: str, lhs_types: List[Type], rhs_types: List[Type]) -> str:
error_msg = ""
error_cnt = 0
for i, (lhs_t, rhs_t) in enumerate(zip(lhs_types, rhs_types)):
if not is_subtype(lhs_t, rhs_t):
if error_cnt < 3:
error_msg += 'expression Tuple item {} has type "{}"; "{}" expected; '\
.format(str(i), format_type_bare(rhs_t), format_type_bare(lhs_t))
error_cnt += 1
error_msg += 'Total {} items are incompatible; {} items are omitted'.format(
str(error_cnt), str(max(0, error_cnt - 3)))
return msg + ' (' + error_msg + ')'

def format_long_tuple_type(typ: TupleType) -> str:
item_cnt = len(typ.items)
if item_cnt > 10:
return 'Tuple[{}, {}, ... <{} more items>]'\
.format(format_type_bare(typ.items[0]),
format_type_bare(typ.items[1]), str(item_cnt - 2))
else:
return format_type_bare(typ)

if isinstance(subtype, TupleType):
if (len(subtype.items) > 10 and
isinstance(supertype, Instance) and
supertype.type.fullname == 'builtins.tuple'):
lhs_type = supertype.args[0]
lhs_types = [lhs_type] * len(subtype.items)
error_msg = format_error_msg(msg, lhs_types, subtype.items)
self.fail(error_msg, context, code=code)
return True
elif (isinstance(supertype, TupleType) and
(len(subtype.items) > 10 or len(supertype.items) > 10)):
if len(subtype.items) != len(supertype.items):
if supertype_label is not None and subtype_label is not None:
error_msg = "{} ({} {}, {} {})".format(msg, subtype_label,
format_long_tuple_type(subtype), supertype_label,
format_long_tuple_type(supertype))
self.fail(error_msg, context, code=code)
return True
error_msg = format_error_msg(msg, supertype.items, subtype.items)
self.fail(error_msg, context, code=code)
return True
return False


def conditional_type_map(expr: Expression,
current_type: Optional[Type],
Expand Down
40 changes: 40 additions & 0 deletions test-data/unit/check-tuples.test
Original file line number Diff line number Diff line change
Expand Up @@ -1241,3 +1241,43 @@ b = ("bar", 7)
reveal_type(a + b) # N: Revealed type is 'Tuple[builtins.int, builtins.str, builtins.int, builtins.str, builtins.int]'

[builtins fixtures/tuple.pyi]

[case testAssigningWithLongTupleInitializer]
from typing import Tuple

# long initializer assignment with few mismatches
t: Tuple[int, ...] = (
1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", 11, 12, 14, 15, # E: Incompatible types in assignment (expression Tuple item 8 has type "str"; "int" expected; expression Tuple item 9 has type "str"; "int" expected; expression Tuple item 10 has type "str"; "int" expected; Total 3 items are incompatible; 0 items are omitted)
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
)

# long initializer assignment with more mismatches
t1: Tuple[int, ...] = (
1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", "str", "str", "str", # E: Incompatible types in assignment (expression Tuple item 8 has type "str"; "int" expected; expression Tuple item 9 has type "str"; "int" expected; expression Tuple item 10 has type "str"; "int" expected; Total 7 items are incompatible; 4 items are omitted)
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
)

# short tuple initializer assignment
t2: Tuple[int, ...] = (1, 2, "s", 4) # E: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, ...]")

# long initializer assignment with few mismatches, no ellipsis
t3: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "str", "str", # E: Incompatible types in assignment (expression Tuple item 10 has type "str"; "int" expected; expression Tuple item 11 has type "str"; "int" expected; Total 2 items are incompatible; 0 items are omitted)
)

# long initializer assignment with more mismatches, no ellipsis
t4: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (
1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", # E: Incompatible types in assignment (expression Tuple item 8 has type "str"; "int" expected; expression Tuple item 9 has type "str"; "int" expected; expression Tuple item 10 has type "str"; "int" expected; Total 4 items are incompatible; 1 items are omitted)
)

# short tuple initializer assignment, no ellipsis
t5: Tuple[int, int] = (1, 2, "s", 4) # E: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, int]")

# long initializer assignment with mismatched pairs
t6: Tuple[int, int, int, int, int, int, int, int, int, int, int, int] = (
1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str", 1, 1, 1, 1, 1 # E: Incompatible types in assignment (expression has type Tuple[int, int, ... <15 more items>], variable has type Tuple[int, int, ... <10 more items>])
)

[builtins fixtures/tuple.pyi]
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy