Skip to content

Refactor checkexpr error messages #10960

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 8 commits into from
Nov 24, 2021
Merged
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
10 changes: 5 additions & 5 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
@@ -71,6 +71,7 @@
callable_type, try_getting_str_literals, custom_special_method,
is_literal_type_like,
)
from mypy.message_registry import ErrorMessage
import mypy.errorcodes as codes

# Type of callback user for checking individual function arguments. See
@@ -1265,7 +1266,7 @@ def infer_function_type_arguments(self, callee_type: CallableType,
if isinstance(first_arg, (NoneType, UninhabitedType)):
inferred_args[0] = self.named_type('builtins.str')
elif not first_arg or not is_subtype(self.named_type('builtins.str'), first_arg):
self.msg.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE,
self.chk.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE,
context)
else:
# In dynamically typed functions use implicit 'Any' types for
@@ -1656,8 +1657,7 @@ def check_overload_call(self,
callable_name=callable_name,
object_type=object_type)
if union_interrupted:
self.chk.fail("Not all union combinations were tried"
" because there are too many unions", context)
self.chk.fail(message_registry.TOO_MANY_UNION_COMBINATIONS, context)
return result

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

def check_awaitable_expr(self, t: Type, ctx: Context, msg: str) -> Type:
def check_awaitable_expr(self, t: Type, ctx: Context, msg: Union[str, ErrorMessage]) -> Type:
"""Check the argument to `await` and extract the type of value.

Also used by `async for` and `async with`.
2 changes: 1 addition & 1 deletion mypy/errorcodes.py
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ def __str__(self) -> str:

ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General")
NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General")
CALL_ARG: Final = ErrorCode(
CALL_ARG: Final[ErrorCode] = ErrorCode(
"call-arg", "Check number, names and kinds of arguments in calls", "General"
)
ARG_TYPE: Final = ErrorCode("arg-type", "Check argument types in calls", "General")
53 changes: 32 additions & 21 deletions mypy/message_registry.py
Original file line number Diff line number Diff line change
@@ -51,8 +51,8 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected")
INCOMPATIBLE_TYPES: Final = "Incompatible types"
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment"
INCOMPATIBLE_TYPES_IN_AWAIT: Final = ErrorMessage('Incompatible types in "await"')
INCOMPATIBLE_REDEFINITION: Final = ErrorMessage("Incompatible redefinition")
INCOMPATIBLE_TYPES_IN_AWAIT: Final = 'Incompatible types in "await"'
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = (
'Incompatible types in "async with" for "__aenter__"'
)
@@ -61,14 +61,14 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
)
INCOMPATIBLE_TYPES_IN_ASYNC_FOR: Final = 'Incompatible types in "async for"'

INCOMPATIBLE_TYPES_IN_YIELD: Final = 'Incompatible types in "yield"'
INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = 'Incompatible types in "yield from"'
INCOMPATIBLE_TYPES_IN_YIELD: Final = ErrorMessage('Incompatible types in "yield"')
INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = ErrorMessage('Incompatible types in "yield from"')
INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION: Final = "Incompatible types in string interpolation"
MUST_HAVE_NONE_RETURN_TYPE: Final = ErrorMessage('The return type of "{}" must be None')
INVALID_TUPLE_INDEX_TYPE: Final = "Invalid tuple index type"
TUPLE_INDEX_OUT_OF_RANGE: Final = "Tuple index out of range"
INVALID_SLICE_INDEX: Final = "Slice index must be an integer or None"
CANNOT_INFER_LAMBDA_TYPE: Final = "Cannot infer type of lambda"
INVALID_TUPLE_INDEX_TYPE: Final = ErrorMessage("Invalid tuple index type")
TUPLE_INDEX_OUT_OF_RANGE: Final = ErrorMessage("Tuple index out of range")
INVALID_SLICE_INDEX: Final = ErrorMessage("Slice index must be an integer or None")
CANNOT_INFER_LAMBDA_TYPE: Final = ErrorMessage("Cannot infer type of lambda")
CANNOT_ACCESS_INIT: Final = 'Cannot access "__init__" directly'
NON_INSTANCE_NEW_TYPE: Final = ErrorMessage('"__new__" must return a class instance (got {})')
INVALID_NEW_TYPE: Final = ErrorMessage('Incompatible return type for "__new__"')
@@ -102,14 +102,16 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
ARGUMENT_TYPE_EXPECTED: Final = ErrorMessage(
"Function is missing a type annotation for one or more arguments", codes.NO_UNTYPED_DEF
)
KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = (
KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = ErrorMessage(
'Keyword argument only valid with "str" key type in call to "dict"'
)
ALL_MUST_BE_SEQ_STR: Final = ErrorMessage("Type of __all__ must be {}, not {}")
INVALID_TYPEDDICT_ARGS: Final = (
INVALID_TYPEDDICT_ARGS: Final = ErrorMessage(
"Expected keyword arguments, {...}, or dict(...) in TypedDict constructor"
)
TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = "Expected TypedDict key to be string literal"
TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = ErrorMessage(
"Expected TypedDict key to be string literal"
)
MALFORMED_ASSERT: Final = ErrorMessage("Assertion is always true, perhaps remove parentheses?")
DUPLICATE_TYPE_SIGNATURES: Final = "Function has duplicate type signatures"
DESCRIPTOR_SET_NOT_CALLABLE: Final = ErrorMessage("{}.__set__ is not callable")
@@ -154,17 +156,23 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
INVALID_TYPEVAR_ARG_VALUE: Final = 'Invalid type argument value for "{}"'

# Super
TOO_MANY_ARGS_FOR_SUPER: Final = 'Too many arguments for "super"'
TOO_FEW_ARGS_FOR_SUPER: Final = 'Too few arguments for "super"'
SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = '"super" with a single argument not supported'
UNSUPPORTED_ARG_1_FOR_SUPER: Final = 'Unsupported argument 1 for "super"'
UNSUPPORTED_ARG_2_FOR_SUPER: Final = 'Unsupported argument 2 for "super"'
SUPER_VARARGS_NOT_SUPPORTED: Final = 'Varargs not supported with "super"'
SUPER_POSITIONAL_ARGS_REQUIRED: Final = '"super" only accepts positional arguments'
SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = 'Argument 2 for "super" not an instance of argument 1'
TARGET_CLASS_HAS_NO_BASE_CLASS: Final = "Target class has no base class"
SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = "super() outside of a method is not supported"
SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = (
TOO_MANY_ARGS_FOR_SUPER: Final = ErrorMessage('Too many arguments for "super"')
TOO_FEW_ARGS_FOR_SUPER: Final = ErrorMessage('Too few arguments for "super"', codes.CALL_ARG)
SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = ErrorMessage(
'"super" with a single argument not supported'
)
UNSUPPORTED_ARG_1_FOR_SUPER: Final = ErrorMessage('Unsupported argument 1 for "super"')
UNSUPPORTED_ARG_2_FOR_SUPER: Final = ErrorMessage('Unsupported argument 2 for "super"')
SUPER_VARARGS_NOT_SUPPORTED: Final = ErrorMessage('Varargs not supported with "super"')
SUPER_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage('"super" only accepts positional arguments')
SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1: Final = ErrorMessage(
'Argument 2 for "super" not an instance of argument 1'
)
TARGET_CLASS_HAS_NO_BASE_CLASS: Final = ErrorMessage("Target class has no base class")
SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED: Final = ErrorMessage(
"super() outside of a method is not supported"
)
SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED: Final = ErrorMessage(
"super() requires one or more positional arguments in enclosing function"
)

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

CONTIGUOUS_ITERABLE_EXPECTED: Final = ErrorMessage("Contiguous iterable with same type expected")
ITERABLE_TYPE_EXPECTED: Final = ErrorMessage("Invalid type '{}' for *expr (iterable expected)")
6 changes: 4 additions & 2 deletions mypy/plugin.py
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ class C: pass
"""

from abc import abstractmethod
from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict
from typing import Any, Callable, List, Tuple, Optional, NamedTuple, TypeVar, Dict, Union
from mypy_extensions import trait, mypyc_attr

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


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

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