Skip to content

Commit b4256a1

Browse files
Refactor checkexpr error messages (#10960)
1 parent b47245a commit b4256a1

File tree

4 files changed

+42
-29
lines changed

4 files changed

+42
-29
lines changed

mypy/checkexpr.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
callable_type, try_getting_str_literals, custom_special_method,
7272
is_literal_type_like,
7373
)
74+
from mypy.message_registry import ErrorMessage
7475
import mypy.errorcodes as codes
7576

7677
# Type of callback user for checking individual function arguments. See
@@ -1287,7 +1288,7 @@ def infer_function_type_arguments(self, callee_type: CallableType,
12871288
if isinstance(first_arg, (NoneType, UninhabitedType)):
12881289
inferred_args[0] = self.named_type('builtins.str')
12891290
elif not first_arg or not is_subtype(self.named_type('builtins.str'), first_arg):
1290-
self.msg.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE,
1291+
self.chk.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE,
12911292
context)
12921293
else:
12931294
# In dynamically typed functions use implicit 'Any' types for
@@ -1678,8 +1679,7 @@ def check_overload_call(self,
16781679
callable_name=callable_name,
16791680
object_type=object_type)
16801681
if union_interrupted:
1681-
self.chk.fail("Not all union combinations were tried"
1682-
" because there are too many unions", context)
1682+
self.chk.fail(message_registry.TOO_MANY_UNION_COMBINATIONS, context)
16831683
return result
16841684

16851685
def plausible_overload_call_targets(self,
@@ -3697,7 +3697,7 @@ def _super_arg_types(self, e: SuperExpr) -> Union[Type, Tuple[Type, Type]]:
36973697
return AnyType(TypeOfAny.unannotated)
36983698
elif len(e.call.args) == 0:
36993699
if self.chk.options.python_version[0] == 2:
3700-
self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e, code=codes.CALL_ARG)
3700+
self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e)
37013701
return AnyType(TypeOfAny.from_error)
37023702
elif not e.info:
37033703
# This has already been reported by the semantic analyzer.
@@ -4090,7 +4090,7 @@ def visit_await_expr(self, e: AwaitExpr) -> Type:
40904090
return self.check_awaitable_expr(actual_type, e,
40914091
message_registry.INCOMPATIBLE_TYPES_IN_AWAIT)
40924092

4093-
def check_awaitable_expr(self, t: Type, ctx: Context, msg: str) -> Type:
4093+
def check_awaitable_expr(self, t: Type, ctx: Context, msg: Union[str, ErrorMessage]) -> Type:
40944094
"""Check the argument to `await` and extract the type of value.
40954095
40964096
Also used by `async for` and `async with`.

mypy/errorcodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __str__(self) -> str:
3030

3131
ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General")
3232
NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General")
33-
CALL_ARG: Final = ErrorCode(
33+
CALL_ARG: Final[ErrorCode] = ErrorCode(
3434
"call-arg", "Check number, names and kinds of arguments in calls", "General"
3535
)
3636
ARG_TYPE: Final = ErrorCode("arg-type", "Check argument types in calls", "General")

mypy/message_registry.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
5151
YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected")
5252
INCOMPATIBLE_TYPES: Final = "Incompatible types"
5353
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment"
54+
INCOMPATIBLE_TYPES_IN_AWAIT: Final = ErrorMessage('Incompatible types in "await"')
5455
INCOMPATIBLE_REDEFINITION: Final = ErrorMessage("Incompatible redefinition")
55-
INCOMPATIBLE_TYPES_IN_AWAIT: Final = 'Incompatible types in "await"'
5656
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = (
5757
'Incompatible types in "async with" for "__aenter__"'
5858
)
@@ -61,14 +61,14 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
6161
)
6262
INCOMPATIBLE_TYPES_IN_ASYNC_FOR: Final = 'Incompatible types in "async for"'
6363

64-
INCOMPATIBLE_TYPES_IN_YIELD: Final = 'Incompatible types in "yield"'
65-
INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = 'Incompatible types in "yield from"'
64+
INCOMPATIBLE_TYPES_IN_YIELD: Final = ErrorMessage('Incompatible types in "yield"')
65+
INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = ErrorMessage('Incompatible types in "yield from"')
6666
INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION: Final = "Incompatible types in string interpolation"
6767
MUST_HAVE_NONE_RETURN_TYPE: Final = ErrorMessage('The return type of "{}" must be None')
68-
INVALID_TUPLE_INDEX_TYPE: Final = "Invalid tuple index type"
69-
TUPLE_INDEX_OUT_OF_RANGE: Final = "Tuple index out of range"
70-
INVALID_SLICE_INDEX: Final = "Slice index must be an integer or None"
71-
CANNOT_INFER_LAMBDA_TYPE: Final = "Cannot infer type of lambda"
68+
INVALID_TUPLE_INDEX_TYPE: Final = ErrorMessage("Invalid tuple index type")
69+
TUPLE_INDEX_OUT_OF_RANGE: Final = ErrorMessage("Tuple index out of range")
70+
INVALID_SLICE_INDEX: Final = ErrorMessage("Slice index must be an integer or None")
71+
CANNOT_INFER_LAMBDA_TYPE: Final = ErrorMessage("Cannot infer type of lambda")
7272
CANNOT_ACCESS_INIT: Final = 'Cannot access "__init__" directly'
7373
NON_INSTANCE_NEW_TYPE: Final = ErrorMessage('"__new__" must return a class instance (got {})')
7474
INVALID_NEW_TYPE: Final = ErrorMessage('Incompatible return type for "__new__"')
@@ -102,14 +102,16 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
102102
ARGUMENT_TYPE_EXPECTED: Final = ErrorMessage(
103103
"Function is missing a type annotation for one or more arguments", codes.NO_UNTYPED_DEF
104104
)
105-
KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = (
105+
KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = ErrorMessage(
106106
'Keyword argument only valid with "str" key type in call to "dict"'
107107
)
108108
ALL_MUST_BE_SEQ_STR: Final = ErrorMessage("Type of __all__ must be {}, not {}")
109-
INVALID_TYPEDDICT_ARGS: Final = (
109+
INVALID_TYPEDDICT_ARGS: Final = ErrorMessage(
110110
"Expected keyword arguments, {...}, or dict(...) in TypedDict constructor"
111111
)
112-
TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = "Expected TypedDict key to be string literal"
112+
TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = ErrorMessage(
113+
"Expected TypedDict key to be string literal"
114+
)
113115
MALFORMED_ASSERT: Final = ErrorMessage("Assertion is always true, perhaps remove parentheses?")
114116
DUPLICATE_TYPE_SIGNATURES: Final = "Function has duplicate type signatures"
115117
DESCRIPTOR_SET_NOT_CALLABLE: Final = ErrorMessage("{}.__set__ is not callable")
@@ -160,17 +162,23 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
160162
TYPEVAR_UNEXPECTED_ARGUMENT: Final = 'Unexpected argument to "TypeVar()"'
161163

162164
# Super
163-
TOO_MANY_ARGS_FOR_SUPER: Final = 'Too many arguments for "super"'
164-
TOO_FEW_ARGS_FOR_SUPER: Final = 'Too few arguments for "super"'
165-
SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = '"super" with a single argument not supported'
166-
UNSUPPORTED_ARG_1_FOR_SUPER: Final = 'Unsupported argument 1 for "super"'
167-
UNSUPPORTED_ARG_2_FOR_SUPER: Final = 'Unsupported argument 2 for "super"'
168-
SUPER_VARARGS_NOT_SUPPORTED: Final = 'Varargs not supported with "super"'
169-
SUPER_POSITIONAL_ARGS_REQUIRED: Final = '"super" only accepts positional arguments'
170-
SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = 'Argument 2 for "super" not an instance of argument 1'
171-
TARGET_CLASS_HAS_NO_BASE_CLASS: Final = "Target class has no base class"
172-
SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = "super() outside of a method is not supported"
173-
SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = (
165+
TOO_MANY_ARGS_FOR_SUPER: Final = ErrorMessage('Too many arguments for "super"')
166+
TOO_FEW_ARGS_FOR_SUPER: Final = ErrorMessage('Too few arguments for "super"', codes.CALL_ARG)
167+
SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = ErrorMessage(
168+
'"super" with a single argument not supported'
169+
)
170+
UNSUPPORTED_ARG_1_FOR_SUPER: Final = ErrorMessage('Unsupported argument 1 for "super"')
171+
UNSUPPORTED_ARG_2_FOR_SUPER: Final = ErrorMessage('Unsupported argument 2 for "super"')
172+
SUPER_VARARGS_NOT_SUPPORTED: Final = ErrorMessage('Varargs not supported with "super"')
173+
SUPER_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage('"super" only accepts positional arguments')
174+
SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = ErrorMessage(
175+
'Argument 2 for "super" not an instance of argument 1'
176+
)
177+
TARGET_CLASS_HAS_NO_BASE_CLASS: Final = ErrorMessage("Target class has no base class")
178+
SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = ErrorMessage(
179+
"super() outside of a method is not supported"
180+
)
181+
SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage(
174182
"super() requires one or more positional arguments in enclosing function"
175183
)
176184

@@ -210,6 +218,9 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
210218
"Only @runtime_checkable protocols can be used with instance and class checks"
211219
)
212220
CANNOT_INSTANTIATE_PROTOCOL: Final = ErrorMessage('Cannot instantiate protocol class "{}"')
221+
TOO_MANY_UNION_COMBINATIONS: Final = ErrorMessage(
222+
"Not all union combinations were tried because there are too many unions"
223+
)
213224

214225
CONTIGUOUS_ITERABLE_EXPECTED: Final = ErrorMessage("Contiguous iterable with same type expected")
215226
ITERABLE_TYPE_EXPECTED: Final = ErrorMessage("Invalid type '{}' for *expr (iterable expected)")

mypy/plugin.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class C: pass
120120
"""
121121

122122
from abc import abstractmethod
123-
from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict
123+
from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict, Union
124124
from mypy_extensions import trait, mypyc_attr
125125

126126
from mypy.nodes import (
@@ -134,6 +134,7 @@ class C: pass
134134
from mypy.options import Options
135135
from mypy.lookup import lookup_fully_qualified
136136
from mypy.errorcodes import ErrorCode
137+
from mypy.message_registry import ErrorMessage
137138

138139

139140
@trait
@@ -223,7 +224,8 @@ def type_context(self) -> List[Optional[Type]]:
223224
raise NotImplementedError
224225

225226
@abstractmethod
226-
def fail(self, msg: str, ctx: Context, *, code: Optional[ErrorCode] = None) -> None:
227+
def fail(self, msg: Union[str, ErrorMessage], ctx: Context, *,
228+
code: Optional[ErrorCode] = None) -> None:
227229
"""Emit an error message at given location."""
228230
raise NotImplementedError
229231

0 commit comments

Comments
 (0)