diff --git a/mypy/checker.py b/mypy/checker.py index 756edb80268f..7a2fae409e1a 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -56,6 +56,7 @@ is_literal_type_like, ) from mypy import message_registry +from mypy.message_registry import ErrorMessage from mypy.subtypes import ( is_subtype, is_equivalent, is_proper_subtype, is_more_precise, restrict_subtype_away, is_subtype_ignoring_tvars, is_callable_compatible, @@ -1014,10 +1015,9 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) # entirely pass/Ellipsis/raise NotImplementedError. if isinstance(return_type, UninhabitedType): # This is a NoReturn function - self.msg.fail(message_registry.INVALID_IMPLICIT_RETURN, defn) + self.fail(message_registry.INVALID_IMPLICIT_RETURN, defn) else: - self.msg.fail(message_registry.MISSING_RETURN_STATEMENT, defn, - code=codes.RETURN) + self.fail(message_registry.MISSING_RETURN_STATEMENT, defn) self.return_types.pop() @@ -1073,31 +1073,25 @@ def is_unannotated_any(t: Type) -> bool: if fdef.type is None and self.options.disallow_untyped_defs: if (not fdef.arguments or (len(fdef.arguments) == 1 and (fdef.arg_names[0] == 'self' or fdef.arg_names[0] == 'cls'))): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) if not has_return_statement(fdef) and not fdef.is_generator: self.note('Use "-> None" if function does not return a value', fdef, code=codes.NO_UNTYPED_DEF) else: - self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef) elif isinstance(fdef.type, CallableType): ret_type = get_proper_type(fdef.type.ret_type) if is_unannotated_any(ret_type): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) elif fdef.is_generator: if is_unannotated_any(self.get_generator_return_type(ret_type, fdef.is_coroutine)): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) elif fdef.is_coroutine and isinstance(ret_type, Instance): if is_unannotated_any(self.get_coroutine_return_type(ret_type)): - self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) if any(is_unannotated_any(t) for t in fdef.type.arg_types): - self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef, - code=codes.NO_UNTYPED_DEF) + self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef) def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None: self_type = fill_typevars_with_any(fdef.info) @@ -1372,7 +1366,7 @@ def check_getattr_method(self, typ: Type, context: Context, name: str) -> None: if len(self.scope.stack) == 1: # module scope if name == '__getattribute__': - self.msg.fail(message_registry.MODULE_LEVEL_GETATTRIBUTE, context) + self.fail(message_registry.MODULE_LEVEL_GETATTRIBUTE, context) return # __getattr__ is fine at the module level as of Python 3.7 (PEP 562). We could # show an error for Python < 3.7, but that would be annoying in code that supports @@ -2593,7 +2587,7 @@ def check_assignment_to_slots(self, lvalue: Lvalue) -> None: return self.fail( - 'Trying to assign name "{}" that is not in "__slots__" of type "{}"'.format( + message_registry.NAME_NOT_IN_SLOTS.format( lvalue.name, inst.type.fullname, ), lvalue, @@ -2637,16 +2631,16 @@ def check_assignment_to_multiple_lvalues(self, lvalues: List[Lvalue], rvalue: Ex elif self.type_is_iterable(typs) and isinstance(typs, Instance): if (iterable_type is not None and iterable_type != self.iterable_item_type(typs)): - self.fail("Contiguous iterable with same type expected", context) + self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context) else: if last_idx is None or last_idx + 1 == idx_rval: rvalues.append(rval) last_idx = idx_rval iterable_type = self.iterable_item_type(typs) else: - self.fail("Contiguous iterable with same type expected", context) + self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context) else: - self.fail("Invalid type '{}' for *expr (iterable expected)".format(typs), + self.fail(message_registry.ITERABLE_TYPE_EXPECTED.format(typs), context) else: rvalues.append(rval) @@ -3179,8 +3173,7 @@ def check_member_assignment(self, instance_type: Type, attribute_type: Type, dunder_set = attribute_type.type.get_method('__set__') if dunder_set is None: - self.msg.fail(message_registry.DESCRIPTOR_SET_NOT_CALLABLE.format(attribute_type), - context) + self.fail(message_registry.DESCRIPTOR_SET_NOT_CALLABLE.format(attribute_type), context) return AnyType(TypeOfAny.from_error), get_type, False function = function_type(dunder_set, self.named_type('builtins.function')) @@ -3363,8 +3356,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: # Functions returning a value of type None are allowed to have a None return. if is_lambda or isinstance(typ, NoneType): return - self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s, - code=codes.RETURN_VALUE) + self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s) else: self.check_subtype( subtype_label='got', @@ -3386,7 +3378,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: return if self.in_checked_function(): - self.fail(message_registry.RETURN_VALUE_EXPECTED, s, code=codes.RETURN_VALUE) + self.fail(message_registry.RETURN_VALUE_EXPECTED, s) def visit_if_stmt(self, s: IfStmt) -> None: """Type check an if statement.""" @@ -4236,23 +4228,16 @@ def format_expr_type() -> str: return f'Expression has type "{t}"' if isinstance(t, FunctionLike): - self.msg.fail( - f'Function "{t}" could always be true in boolean context', expr, - code=codes.TRUTHY_BOOL, - ) + self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(t), expr) elif isinstance(t, UnionType): - self.msg.fail( - f"{format_expr_type()} of which no members implement __bool__ or __len__ " - "so it could always be true in boolean context", + self.fail( + message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr, - code=codes.TRUTHY_BOOL, ) else: - self.msg.fail( - f'{format_expr_type()} which does not implement __bool__ or __len__ ' - 'so it could always be true in boolean context', + self.fail( + message_registry.TYPE_ALWAYS_TRUE.format(format_expr_type()), expr, - code=codes.TRUTHY_BOOL, ) def find_type_equals_check(self, node: ComparisonExpr, expr_indices: List[int] @@ -4385,7 +4370,7 @@ def find_isinstance_check_helper(self, node: Expression) -> Tuple[TypeMap, TypeM if node.callee.type_guard is not None: # TODO: Follow keyword args or *args, **kwargs if node.arg_kinds[0] != nodes.ARG_POS: - self.fail("Type guard requires positional argument", node) + self.fail(message_registry.TYPE_GUARD_POS_ARG_REQUIRED, node) return {}, {} if literal(expr) == LITERAL_TYPE: # Note: we wrap the target type, so that we can special case later. @@ -4931,7 +4916,7 @@ def check_subtype(self, subtype: Type, supertype: Type, context: Context, - msg: str = message_registry.INCOMPATIBLE_TYPES, + msg: Union[str, ErrorMessage] = message_registry.INCOMPATIBLE_TYPES, subtype_label: Optional[str] = None, supertype_label: Optional[str] = None, *, @@ -4941,9 +4926,14 @@ def check_subtype(self, if is_subtype(subtype, supertype): return True + if isinstance(msg, ErrorMessage): + msg_text = msg.value + code = msg.code + else: + msg_text = msg subtype = get_proper_type(subtype) supertype = get_proper_type(supertype) - if self.msg.try_report_long_tuple_assignment_error(subtype, supertype, context, msg, + if self.msg.try_report_long_tuple_assignment_error(subtype, supertype, context, msg_text, subtype_label, supertype_label, code=code): return False if self.should_suppress_optional_error([subtype]): @@ -4962,8 +4952,9 @@ def check_subtype(self, if isinstance(subtype, Instance) and isinstance(supertype, Instance): notes = append_invariance_notes([], subtype, supertype) if extra_info: - msg += ' (' + ', '.join(extra_info) + ')' - self.fail(msg, context, code=code) + msg_text += ' (' + ', '.join(extra_info) + ')' + + self.fail(ErrorMessage(msg_text, code=code), context) for note in notes: self.msg.note(note, context, code=code) if note_msg: @@ -5234,8 +5225,12 @@ def temp_node(self, t: Type, context: Optional[Context] = None) -> TempNode: """Create a temporary node with the given, fixed type.""" return TempNode(t, context=context) - def fail(self, msg: str, context: Context, *, code: Optional[ErrorCode] = None) -> None: + def fail(self, msg: Union[str, ErrorMessage], context: Context, *, + code: Optional[ErrorCode] = None) -> None: """Produce an error message.""" + if isinstance(msg, ErrorMessage): + self.msg.fail(msg.value, context, code=msg.code) + return self.msg.fail(msg, context, code=code) def note(self, diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index d9e11a044a18..53d496bbb1d6 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -44,8 +44,10 @@ def __str__(self) -> str: OVERRIDE: Final = ErrorCode( "override", "Check that method override is compatible with base class", "General" ) -RETURN: Final = ErrorCode("return", "Check that function always returns a value", "General") -RETURN_VALUE: Final = ErrorCode( +RETURN: Final[ErrorCode] = ErrorCode( + "return", "Check that function always returns a value", "General" +) +RETURN_VALUE: Final[ErrorCode] = ErrorCode( "return-value", "Check that return value is compatible with signature", "General" ) ASSIGNMENT: Final = ErrorCode( @@ -94,11 +96,11 @@ def __str__(self) -> str: ) # These error codes aren't enabled by default. -NO_UNTYPED_DEF: Final = ErrorCode( +NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode( "no-untyped-def", "Check that every function has an annotation", "General" ) NO_UNTYPED_CALL: Final = ErrorCode( - 'no-untyped-call', + "no-untyped-call", "Disallow calling functions without type annotations from annotated functions", "General", ) @@ -122,11 +124,11 @@ def __str__(self) -> str: REDUNDANT_EXPR: Final = ErrorCode( "redundant-expr", "Warn about redundant expressions", "General", default_enabled=False ) -TRUTHY_BOOL: Final = ErrorCode( - 'truthy-bool', +TRUTHY_BOOL: Final[ErrorCode] = ErrorCode( + "truthy-bool", "Warn about expressions that could always evaluate to true in boolean contexts", - 'General', - default_enabled=False + "General", + default_enabled=False, ) NAME_MATCH: Final = ErrorCode( "name-match", "Check that type definition has consistent naming", "General" diff --git a/mypy/errors.py b/mypy/errors.py index 3a0e0e14d8b3..18fb0434baaa 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -11,6 +11,7 @@ from mypy.options import Options from mypy.version import __version__ as mypy_version from mypy.errorcodes import ErrorCode, IMPORT +from mypy.message_registry import ErrorMessage from mypy import errorcodes as codes from mypy.util import DEFAULT_SOURCE_OFFSET, is_typeshed_file @@ -677,7 +678,12 @@ def render_messages(self, result.append((file, -1, -1, 'note', 'In class "{}":'.format(e.type), e.allow_dups, None)) - result.append((file, e.line, e.column, e.severity, e.message, e.allow_dups, e.code)) + if isinstance(e.message, ErrorMessage): + result.append( + (file, e.line, e.column, e.severity, e.message.value, e.allow_dups, e.code)) + else: + result.append( + (file, e.line, e.column, e.severity, e.message, e.allow_dups, e.code)) prev_import_context = e.import_ctx prev_function_or_member = e.function_or_member diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 48b53336f15d..75658ccf02c9 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -6,36 +6,52 @@ add a method to MessageBuilder and call this instead. """ +from typing import NamedTuple, Optional from typing_extensions import Final +from mypy import errorcodes as codes + + +class ErrorMessage(NamedTuple): + value: str + code: Optional[codes.ErrorCode] = None + + def format(self, *args: object, **kwargs: object) -> "ErrorMessage": + return ErrorMessage(self.value.format(*args, **kwargs), code=self.code) + + # Invalid types INVALID_TYPE_RAW_ENUM_VALUE: Final = "Invalid type: try using Literal[{}.{}] instead?" # Type checker error message constants -NO_RETURN_VALUE_EXPECTED: Final = "No return value expected" -MISSING_RETURN_STATEMENT: Final = "Missing return statement" -INVALID_IMPLICIT_RETURN: Final = "Implicit return in function which does not return" -INCOMPATIBLE_RETURN_VALUE_TYPE: Final = "Incompatible return value type" -RETURN_VALUE_EXPECTED: Final = "Return value expected" -NO_RETURN_EXPECTED: Final = "Return statement in function which does not return" -INVALID_EXCEPTION: Final = "Exception must be derived from BaseException" -INVALID_EXCEPTION_TYPE: Final = "Exception type must be derived from BaseException" -RETURN_IN_ASYNC_GENERATOR: Final = '"return" with value in async generator is not allowed' -INVALID_RETURN_TYPE_FOR_GENERATOR: Final = ( +NO_RETURN_VALUE_EXPECTED: Final = ErrorMessage("No return value expected", codes.RETURN_VALUE) +MISSING_RETURN_STATEMENT: Final = ErrorMessage("Missing return statement", codes.RETURN) +INVALID_IMPLICIT_RETURN: Final = ErrorMessage("Implicit return in function which does not return") +INCOMPATIBLE_RETURN_VALUE_TYPE: Final = ErrorMessage( + "Incompatible return value type", codes.RETURN_VALUE +) +RETURN_VALUE_EXPECTED: Final = ErrorMessage("Return value expected", codes.RETURN_VALUE) +NO_RETURN_EXPECTED: Final = ErrorMessage("Return statement in function which does not return") +INVALID_EXCEPTION: Final = ErrorMessage("Exception must be derived from BaseException") +INVALID_EXCEPTION_TYPE: Final = ErrorMessage("Exception type must be derived from BaseException") +RETURN_IN_ASYNC_GENERATOR: Final = ErrorMessage( + '"return" with value in async generator is not allowed' +) +INVALID_RETURN_TYPE_FOR_GENERATOR: Final = ErrorMessage( 'The return type of a generator function should be "Generator"' " or one of its supertypes" ) -INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR: Final = ( +INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR: Final = ErrorMessage( 'The return type of an async generator function should be "AsyncGenerator" or one of its ' "supertypes" ) -INVALID_GENERATOR_RETURN_ITEM_TYPE: Final = ( +INVALID_GENERATOR_RETURN_ITEM_TYPE: Final = ErrorMessage( "The return type of a generator function must be None in" " its third type parameter in Python 2" ) -YIELD_VALUE_EXPECTED: Final = "Yield value expected" +YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected") INCOMPATIBLE_TYPES: Final = "Incompatible types" INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment" -INCOMPATIBLE_REDEFINITION: Final = "Incompatible redefinition" +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__"' @@ -48,49 +64,76 @@ INCOMPATIBLE_TYPES_IN_YIELD: Final = 'Incompatible types in "yield"' INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = 'Incompatible types in "yield from"' INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION: Final = "Incompatible types in string interpolation" -MUST_HAVE_NONE_RETURN_TYPE: Final = 'The return type of "{}" must be None' +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" CANNOT_ACCESS_INIT: Final = 'Cannot access "__init__" directly' -NON_INSTANCE_NEW_TYPE: Final = '"__new__" must return a class instance (got {})' -INVALID_NEW_TYPE: Final = 'Incompatible return type for "__new__"' -BAD_CONSTRUCTOR_TYPE: Final = "Unsupported decorated constructor type" +NON_INSTANCE_NEW_TYPE: Final = ErrorMessage('"__new__" must return a class instance (got {})') +INVALID_NEW_TYPE: Final = ErrorMessage('Incompatible return type for "__new__"') +BAD_CONSTRUCTOR_TYPE: Final = ErrorMessage("Unsupported decorated constructor type") CANNOT_ASSIGN_TO_METHOD: Final = "Cannot assign to a method" CANNOT_ASSIGN_TO_TYPE: Final = "Cannot assign to a type" -INCONSISTENT_ABSTRACT_OVERLOAD: Final = ( +INCONSISTENT_ABSTRACT_OVERLOAD: Final = ErrorMessage( "Overloaded method has both abstract and non-abstract variants" ) -MULTIPLE_OVERLOADS_REQUIRED: Final = "Single overload definition, multiple required" -READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ( +MULTIPLE_OVERLOADS_REQUIRED: Final = ErrorMessage("Single overload definition, multiple required") +READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE: Final = ErrorMessage( "Read-only property cannot override read-write property" ) FORMAT_REQUIRES_MAPPING: Final = "Format requires a mapping" -RETURN_TYPE_CANNOT_BE_CONTRAVARIANT: Final = ( +RETURN_TYPE_CANNOT_BE_CONTRAVARIANT: Final = ErrorMessage( "Cannot use a contravariant type variable as return type" ) -FUNCTION_PARAMETER_CANNOT_BE_COVARIANT: Final = ( +FUNCTION_PARAMETER_CANNOT_BE_COVARIANT: Final = ErrorMessage( "Cannot use a covariant type variable as a parameter" ) INCOMPATIBLE_IMPORT_OF: Final = "Incompatible import of" -FUNCTION_TYPE_EXPECTED: Final = "Function is missing a type annotation" -ONLY_CLASS_APPLICATION: Final = "Type application is only supported for generic classes" -RETURN_TYPE_EXPECTED: Final = "Function is missing a return type annotation" -ARGUMENT_TYPE_EXPECTED: Final = "Function is missing a type annotation for one or more arguments" +FUNCTION_TYPE_EXPECTED: Final = ErrorMessage( + "Function is missing a type annotation", codes.NO_UNTYPED_DEF +) +ONLY_CLASS_APPLICATION: Final = ErrorMessage( + "Type application is only supported for generic classes" +) +RETURN_TYPE_EXPECTED: Final = ErrorMessage( + "Function is missing a return type annotation", codes.NO_UNTYPED_DEF +) +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 only valid with "str" key type in call to "dict"' ) -ALL_MUST_BE_SEQ_STR: Final = "Type of __all__ must be {}, not {}" +ALL_MUST_BE_SEQ_STR: Final = ErrorMessage("Type of __all__ must be {}, not {}") INVALID_TYPEDDICT_ARGS: Final = ( "Expected keyword arguments, {...}, or dict(...) in TypedDict constructor" ) TYPEDDICT_KEY_MUST_BE_STRING_LITERAL: Final = "Expected TypedDict key to be string literal" -MALFORMED_ASSERT: Final = "Assertion is always true, perhaps remove parentheses?" +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 = "{}.__set__ is not callable" +DESCRIPTOR_SET_NOT_CALLABLE: Final = ErrorMessage("{}.__set__ is not callable") DESCRIPTOR_GET_NOT_CALLABLE: Final = "{}.__get__ is not callable" -MODULE_LEVEL_GETATTRIBUTE: Final = "__getattribute__ is not valid at the module level" +MODULE_LEVEL_GETATTRIBUTE: Final = ErrorMessage( + "__getattribute__ is not valid at the module level" +) +NAME_NOT_IN_SLOTS: Final = ErrorMessage( + 'Trying to assign name "{}" that is not in "__slots__" of type "{}"' +) +TYPE_ALWAYS_TRUE: Final = ErrorMessage( + "{} which does not implement __bool__ or __len__ " + "so it could always be true in boolean context", + code=codes.TRUTHY_BOOL, +) +TYPE_ALWAYS_TRUE_UNIONTYPE: Final = ErrorMessage( + "{} of which no members implement __bool__ or __len__ " + "so it could always be true in boolean context", + code=codes.TRUTHY_BOOL, +) +FUNCTION_ALWAYS_TRUE: Final = ErrorMessage( + 'Function "{}" could always be true in boolean context', + code=codes.TRUTHY_BOOL, +) # Generic GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = ( @@ -122,38 +165,42 @@ ) # Self-type -MISSING_OR_INVALID_SELF_TYPE: Final = ( +MISSING_OR_INVALID_SELF_TYPE: Final = ErrorMessage( "Self argument missing for a non-static method (or an invalid type for self)" ) -ERASED_SELF_TYPE_NOT_SUPERTYPE: Final = ( +ERASED_SELF_TYPE_NOT_SUPERTYPE: Final = ErrorMessage( 'The erased type of self "{}" is not a supertype of its class "{}"' ) -INVALID_SELF_TYPE_OR_EXTRA_ARG: Final = ( +INVALID_SELF_TYPE_OR_EXTRA_ARG: Final = ErrorMessage( "Invalid type for self, or extra argument type in function annotation" ) # Final -CANNOT_INHERIT_FROM_FINAL: Final = 'Cannot inherit from final class "{}"' -DEPENDENT_FINAL_IN_CLASS_BODY: Final = ( +CANNOT_INHERIT_FROM_FINAL: Final = ErrorMessage('Cannot inherit from final class "{}"') +DEPENDENT_FINAL_IN_CLASS_BODY: Final = ErrorMessage( "Final name declared in class body cannot depend on type variables" ) CANNOT_ACCESS_FINAL_INSTANCE_ATTR: Final = ( 'Cannot access final instance attribute "{}" on class object' ) -CANNOT_MAKE_DELETABLE_FINAL: Final = "Deletable attribute cannot be final" +CANNOT_MAKE_DELETABLE_FINAL: Final = ErrorMessage("Deletable attribute cannot be final") # ClassVar -CANNOT_OVERRIDE_INSTANCE_VAR: Final = ( +CANNOT_OVERRIDE_INSTANCE_VAR: Final = ErrorMessage( 'Cannot override instance variable (previously declared on base class "{}") with class ' "variable" ) -CANNOT_OVERRIDE_CLASS_VAR: Final = ( +CANNOT_OVERRIDE_CLASS_VAR: Final = ErrorMessage( 'Cannot override class variable (previously declared on base class "{}") with instance ' "variable" ) # Protocol -RUNTIME_PROTOCOL_EXPECTED: Final = ( +RUNTIME_PROTOCOL_EXPECTED: Final = ErrorMessage( "Only @runtime_checkable protocols can be used with instance and class checks" ) -CANNOT_INSTANTIATE_PROTOCOL: Final = 'Cannot instantiate protocol class "{}"' +CANNOT_INSTANTIATE_PROTOCOL: Final = ErrorMessage('Cannot instantiate protocol class "{}"') + +CONTIGUOUS_ITERABLE_EXPECTED: Final = ErrorMessage("Contiguous iterable with same type expected") +ITERABLE_TYPE_EXPECTED: Final = ErrorMessage("Invalid type '{}' for *expr (iterable expected)") +TYPE_GUARD_POS_ARG_REQUIRED: Final = ErrorMessage("Type guard requires positional argument")