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 all 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
4 changes: 3 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.msg.try_report_long_tuple_assignment_error(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
71 changes: 71 additions & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,77 @@ def print_more(self,
.format(len(conflicts) - max_items),
context, offset=offset, code=code)

def try_report_long_tuple_assignment_error(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:
"""Try to generate meaningful error message for very long tuple assignment

Returns a bool: True when generating long tuple assignment error,
False when no such error reported
"""
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)
self.generate_incompatible_tuple_error(lhs_types,
subtype.items, context, msg, 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,
self.format_long_tuple_type(subtype), supertype_label,
self.format_long_tuple_type(supertype))
self.fail(error_msg, context, code=code)
return True
self.generate_incompatible_tuple_error(supertype.items,
subtype.items, context, msg, code)
return True
return False

def format_long_tuple_type(self, typ: TupleType) -> str:
"""Format very long tuple type using an ellipsis notation"""
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)

def generate_incompatible_tuple_error(self,
lhs_types: List[Type],
rhs_types: List[Type],
context: Context,
msg: str = message_registry.INCOMPATIBLE_TYPES,
code: Optional[ErrorCode] = None) -> None:
"""Generate error message for individual incompatible tuple pairs"""
error_cnt = 0
notes = [] # List[str]
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:
notes.append('Expression tuple item {} has type "{}"; "{}" expected; '
.format(str(i), format_type_bare(rhs_t), format_type_bare(lhs_t)))
error_cnt += 1

error_msg = msg + ' ({} tuple items are incompatible'.format(str(error_cnt))
if error_cnt - 3 > 0:
error_msg += '; {} items are omitted)'.format(str(error_cnt - 3))
else:
error_msg += ')'
self.fail(error_msg, context, code=code)
for note in notes:
self.note(note, context, code=code)


def quote_type_string(type_string: str) -> str:
"""Quotes a type representation for use in messages."""
Expand Down
43 changes: 43 additions & 0 deletions test-data/unit/check-tuples.test
Original file line number Diff line number Diff line change
Expand Up @@ -1241,3 +1241,46 @@ 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) \
# E: Incompatible types in assignment (3 tuple items are incompatible) \
# N: Expression tuple item 8 has type "str"; "int" expected; \
# N: Expression tuple item 9 has type "str"; "int" expected; \
# N: Expression tuple item 10 has type "str"; "int" expected;

# long initializer assignment with more mismatches
t1: Tuple[int, ...] = (1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", "str") \
# E: Incompatible types in assignment (4 tuple items are incompatible; 1 items are omitted) \
# N: Expression tuple item 8 has type "str"; "int" expected; \
# N: Expression tuple item 9 has type "str"; "int" expected; \
# N: Expression tuple item 10 has type "str"; "int" expected;

# 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 (2 tuple items are incompatible) \
# N: Expression tuple item 10 has type "str"; "int" expected; \
# N: Expression tuple item 11 has type "str"; "int" expected;

# 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 (4 tuple items are incompatible; 1 items are omitted) \
# N: Expression tuple item 8 has type "str"; "int" expected; \
# N: Expression tuple item 9 has type "str"; "int" expected; \
# N: Expression tuple item 10 has type "str"; "int" expected;

# 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