From a55c84c4d1ed33fff0f96806b40d945a2e5891af Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Wed, 20 Nov 2019 01:50:36 +0800 Subject: [PATCH 1/7] add skeleton, need add logic for formatting error msg --- mypy/checker.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 0387ffce8549..d7a9c3dccdf1 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4027,7 +4027,9 @@ def check_subtype(self, subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - + if self.check_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] @@ -4378,6 +4380,22 @@ 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_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: + if (isinstance(subtype, TupleType) + and isinstance(supertype, Instance) + and supertype.type.fullname == 'builtins.tuple'): + # TODO: + self.fail("error message", context, code=code) + return True + return False + def conditional_type_map(expr: Expression, current_type: Optional[Type], From 370901d3d6e57240f337e7a0cadb69d9fd92cba3 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Thu, 21 Nov 2019 22:25:34 +0800 Subject: [PATCH 2/7] add testcase --- mypy/checker.py | 35 +++++++++++++++++++++++++------- test-data/unit/check-tuples.test | 15 ++++++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index d7a9c3dccdf1..872d13b4086c 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4380,7 +4380,7 @@ 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_tuple_assignment(self, + def check_long_tuple_assignment(self, subtype: ProperType, supertype: ProperType, context: Context, @@ -4388,12 +4388,33 @@ def check_tuple_assignment(self, subtype_label: Optional[str] = None, supertype_label: Optional[str] = None, code: Optional[ErrorCode] = None) -> bool: - if (isinstance(subtype, TupleType) - and isinstance(supertype, Instance) - and supertype.type.fullname == 'builtins.tuple'): - # TODO: - self.fail("error message", context, code=code) - return True + if isinstance(subtype, TupleType): + if isinstance(supertype, Instance) and supertype.type.fullname == 'builtins.tuple' and subtype: + lhs_type = supertype.args[0] + error_msg = "" + error_cnt = 0 + for i, t in enumerate(subtype.items): + if not is_subtype(t, lhs_type): + if error_cnt < 3: + error_msg += 'Tuple item {} has type "{}"; "{}" expected; '.format( + str(i), format_type_bare(t), format_type_bare(lhs_type)) + error_cnt += 1 + error_msg += 'Total {} items are incompatible; {} items are omitted'.format(str(error_cnt), str(max(0, error_cnt - 3))) + self.fail(msg + ' (' + error_msg + ')', context, code=code) + return True + elif isinstance(supertype, TupleType): + lhs_types = supertype.items + rhs_types = subtype.items + error_msg = "" + error_cnt = 0 + for i, l_t, r_t in enumerate(zip(lhs_types, rhs_types)): + if not is_subtype(l_t, r_t): + if error_cnt < 3: + error_msg += 'Tuple item {} has type "{}"; "{}" expected; '.format( + str(i), format_type_bare(t), format_type_bare(lhs_type)) + error_cnt += 1 + self.fail("error message", context, code=code) + return True return False diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 73c1c9ac6236..0734fa48eda4 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1241,3 +1241,18 @@ 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 + +t: Tuple[int, ...] = ( + 1, 2, 3, 4, 5, 6, 7, 8, "9", "10", 11, "12", "13", "12", 14, 15, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 3, 31, 32, 33, 34, 35, 36, 37, 3, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 30, 31, 32, 33, 34, 234234, 36, 37, 38, 39, 40, 1, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63 +) +[builtins fixtures/tuple.pyi] +[out] +main:4: error: Incompatible types in assignment (Tuple item 8 has type "str"; "int" expected; Tuple item 9 has type "str"; "int" expected; Tuple item 11 has type "str"; "int" expected; Total 5 items are incompatible; 2 items are omitted) \ No newline at end of file From 9c829d6dd22029bf13ceca223e864e0857f10133 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Thu, 21 Nov 2019 23:51:30 +0800 Subject: [PATCH 3/7] draft implementation completed --- mypy/checker.py | 65 ++++++++++++++++++++------------ test-data/unit/check-tuples.test | 47 +++++++++++++++++++---- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 872d13b4086c..2de3cfa84e72 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4027,7 +4027,7 @@ def check_subtype(self, subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - if self.check_tuple_assignment(subtype, supertype, context, msg, + 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]): @@ -4388,32 +4388,49 @@ def check_long_tuple_assignment(self, subtype_label: Optional[str] = None, supertype_label: Optional[str] = None, code: Optional[ErrorCode] = None) -> bool: + + 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 isinstance(supertype, Instance) and supertype.type.fullname == 'builtins.tuple' and subtype: + if (len(subtype.items) > 10 and + isinstance(supertype, Instance) and + supertype.type.fullname == 'builtins.tuple'): lhs_type = supertype.args[0] - error_msg = "" - error_cnt = 0 - for i, t in enumerate(subtype.items): - if not is_subtype(t, lhs_type): - if error_cnt < 3: - error_msg += 'Tuple item {} has type "{}"; "{}" expected; '.format( - str(i), format_type_bare(t), format_type_bare(lhs_type)) - error_cnt += 1 - error_msg += 'Total {} items are incompatible; {} items are omitted'.format(str(error_cnt), str(max(0, error_cnt - 3))) - self.fail(msg + ' (' + error_msg + ')', context, code=code) + 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): - lhs_types = supertype.items - rhs_types = subtype.items - error_msg = "" - error_cnt = 0 - for i, l_t, r_t in enumerate(zip(lhs_types, rhs_types)): - if not is_subtype(l_t, r_t): - if error_cnt < 3: - error_msg += 'Tuple item {} has type "{}"; "{}" expected; '.format( - str(i), format_type_bare(t), format_type_bare(lhs_type)) - error_cnt += 1 - self.fail("error message", context, code=code) + 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 diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 0734fa48eda4..c80106e8c259 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1245,14 +1245,47 @@ reveal_type(a + b) # N: Revealed type is 'Tuple[builtins.int, builtins.str, bui [case testAssigningWithLongTupleInitializer] from typing import Tuple +# long initializer assignment with few mismatches t: Tuple[int, ...] = ( - 1, 2, 3, 4, 5, 6, 7, 8, "9", "10", 11, "12", "13", "12", 14, 15, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 3, 31, 32, 33, 34, 35, 36, 37, 3, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 4, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 30, 31, 32, 33, 34, 234234, 36, 37, 38, 39, 40, 1, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63 + 1, 2, 3, 4, 5, 6, 7, 8, "str", "str", "str", 11, 12, 14, 15, + 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", + 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) + +# 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", +) + +# 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", +) + +# short tuple initializer assignment, no ellipsis +t5: Tuple[int, int] = (1, 2, "s", 4) + +# 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 +) + [builtins fixtures/tuple.pyi] [out] -main:4: error: Incompatible types in assignment (Tuple item 8 has type "str"; "int" expected; Tuple item 9 has type "str"; "int" expected; Tuple item 11 has type "str"; "int" expected; Total 5 items are incompatible; 2 items are omitted) \ No newline at end of file +main:5: error: 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) +main:12: error: 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) +main:18: error: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, ...]") +main:22: error: 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) +main:27: error: 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) +main:31: error: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, int]") +main:35: error: Incompatible types in assignment (expression has type Tuple[int, int, ... <15 more items>], variable has type Tuple[int, int, ... <10 more items>]) From 404ead68a9012e54097579872509bdea51eecbaf Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Fri, 22 Nov 2019 09:40:29 +0800 Subject: [PATCH 4/7] add docstring, fix test on python3.8 --- mypy/checker.py | 1 + test-data/unit/check-tuples.test | 22 +++++++--------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 2de3cfa84e72..4bb8a5e1fdc6 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4388,6 +4388,7 @@ def check_long_tuple_assignment(self, 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 = "" diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index c80106e8c259..d3298d443c6d 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1247,45 +1247,37 @@ 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, + 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", + 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) +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", + 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", + 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) +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 + 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] -[out] -main:5: error: 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) -main:12: error: 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) -main:18: error: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, ...]") -main:22: error: 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) -main:27: error: 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) -main:31: error: Incompatible types in assignment (expression has type "Tuple[int, int, str, int]", variable has type "Tuple[int, int]") -main:35: error: Incompatible types in assignment (expression has type Tuple[int, int, ... <15 more items>], variable has type Tuple[int, int, ... <10 more items>]) From 1d05e8d19c5d5d21ee17c03183c4e1180b4c8f19 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Fri, 22 Nov 2019 23:09:30 +0800 Subject: [PATCH 5/7] reformat error msg, change nested functions to instance method --- mypy/checker.py | 86 +++++++++++++++++++------------- test-data/unit/check-tuples.test | 43 ++++++++-------- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 4bb8a5e1fdc6..8fc054a6dded 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4381,60 +4381,74 @@ def infer_issubclass_maps(self, node: CallExpr, 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: + 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) + self.generate_imcompatiable_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, - format_long_tuple_type(subtype), supertype_label, - format_long_tuple_type(supertype)) + self.format_long_tuple_type(subtype), supertype_label, + self.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) + self.generate_imcompatiable_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 in 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_imcompatiable_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 imcompatiable tuple pairs""" + error_cnt = 0 + notes = [] # List[str] + notes_items = [] # List[Type] + 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))) + notes_items.append(rhs_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, item in zip(notes, notes_items): + self.note(note, context, code=code) + def conditional_type_map(expr: Expression, current_type: Optional[Type], diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index d3298d443c6d..1c7e4f57bcd2 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1246,38 +1246,41 @@ reveal_type(a + b) # N: Revealed type is 'Tuple[builtins.int, builtins.str, bui 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, -) +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", "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, -) +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, ...]") +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) -) +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 (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) -) +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>]) -) +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] From 4df5c048a8df42dba76f918cc1eeb6b3a68196d8 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Tue, 3 Dec 2019 10:19:13 +0800 Subject: [PATCH 6/7] fix spelling, remove unused var --- mypy/checker.py | 26 ++++++++++++-------------- test-data/unit/check-tuples.test | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 8fc054a6dded..a459d29a13b2 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4395,7 +4395,7 @@ def check_long_tuple_assignment(self, supertype.type.fullname == 'builtins.tuple'): lhs_type = supertype.args[0] lhs_types = [lhs_type] * len(subtype.items) - self.generate_imcompatiable_tuple_error(lhs_types, + self.generate_incompatible_tuple_error(lhs_types, subtype.items, context, msg, code) return True elif (isinstance(supertype, TupleType) and @@ -4407,13 +4407,13 @@ def check_long_tuple_assignment(self, self.format_long_tuple_type(supertype)) self.fail(error_msg, context, code=code) return True - self.generate_imcompatiable_tuple_error(supertype.items, + 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 in ellipsis notation""" + """Format very long tuple type using an ellipsis notation""" item_cnt = len(typ.items) if item_cnt > 10: return 'Tuple[{}, {}, ... <{} more items>]'\ @@ -4422,22 +4422,20 @@ def format_long_tuple_type(self, typ: TupleType) -> str: else: return format_type_bare(typ) - def generate_imcompatiable_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 imcompatiable tuple pairs""" + 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] - notes_items = [] # List[Type] 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; ' + notes.append('Expression tuple item {} has type "{}"; "{}" expected; ' .format(str(i), format_type_bare(rhs_t), format_type_bare(lhs_t))) - notes_items.append(rhs_t) error_cnt += 1 error_msg = msg + ' ({} tuple items are incompatible'.format(str(error_cnt)) @@ -4446,7 +4444,7 @@ def generate_imcompatiable_tuple_error(self, else: error_msg += ')' self.fail(error_msg, context, code=code) - for note, item in zip(notes, notes_items): + for note in notes: self.note(note, context, code=code) diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 1c7e4f57bcd2..4058bd509535 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1248,16 +1248,16 @@ 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; + # 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; + # 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) \ @@ -1266,15 +1266,15 @@ t2: Tuple[int, ...] = (1, 2, "s", 4) \ # 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; + # 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; + # 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]") From d15538d0316527fbd3f0f944228b4bc3254784aa Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Tue, 3 Dec 2019 10:38:59 +0800 Subject: [PATCH 7/7] move error-generation code to messages.py --- mypy/checker.py | 69 +--------------------------------------------- mypy/messages.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 68 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index a459d29a13b2..76fa7c33ab27 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -4027,7 +4027,7 @@ def check_subtype(self, subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - if self.check_long_tuple_assignment(subtype, supertype, context, msg, + 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]): @@ -4380,73 +4380,6 @@ 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.""" - 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 conditional_type_map(expr: Expression, current_type: Optional[Type], diff --git a/mypy/messages.py b/mypy/messages.py index a8c6882ad43f..52eb8aa1e5be 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -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.""" 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