From c0a8c6e5f4b5a3023bc8606f376a39d82b87ede0 Mon Sep 17 00:00:00 2001 From: Chad Dombrova Date: Tue, 15 Jan 2019 00:06:15 -0800 Subject: [PATCH] Move message constants to mypy.message_registry This is in preparation for message filtering --- mypy/checker.py | 96 +++++++++++++------------- mypy/checkexpr.py | 63 ++++++++--------- mypy/checkmember.py | 16 ++--- mypy/checkstrformat.py | 10 +-- mypy/fastparse.py | 8 +-- mypy/fastparse2.py | 4 +- mypy/message_registry.py | 139 +++++++++++++++++++++++++++++++++++++ mypy/messages.py | 144 +++------------------------------------ mypy/plugins/default.py | 8 +-- mypy/semanal.py | 5 +- mypy/semanal_pass3.py | 6 +- mypy/typeanal.py | 6 +- 12 files changed, 260 insertions(+), 245 deletions(-) create mode 100644 mypy/message_registry.py diff --git a/mypy/checker.py b/mypy/checker.py index 6e2df88b0497..525726e42f05 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -41,7 +41,7 @@ map_type_from_supertype, bind_self, erase_to_bound, type_object_type, analyze_descriptor_access, is_final_node ) -from mypy import messages +from mypy import message_registry from mypy.subtypes import ( is_subtype, is_equivalent, is_proper_subtype, is_more_precise, restrict_subtype_away, is_subtype_ignoring_tvars, is_callable_compatible, @@ -294,7 +294,7 @@ def check_first_pass(self) -> None: [self.named_type('builtins.unicode')]) if not is_subtype(all_.type, seq_str): str_seq_s, all_s = self.msg.format_distinctly(seq_str, all_.type) - self.fail(messages.ALL_MUST_BE_SEQ_STR.format(str_seq_s, all_s), + self.fail(message_registry.ALL_MUST_BE_SEQ_STR.format(str_seq_s, all_s), all_node) self.tscope.leave() @@ -432,7 +432,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None: # valid overloads. return None if len(defn.items) == 1: - self.fail(messages.MULTIPLE_OVERLOADS_REQUIRED, defn) + self.fail(message_registry.MULTIPLE_OVERLOADS_REQUIRED, defn) if defn.is_property: # HACK: Infer the type of the property. @@ -443,7 +443,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None: if fdef.func.is_abstract: num_abstract += 1 if num_abstract not in (0, len(defn.items)): - self.fail(messages.INCONSISTENT_ABSTRACT_OVERLOAD, defn) + self.fail(message_registry.INCONSISTENT_ABSTRACT_OVERLOAD, defn) if defn.impl: defn.impl.accept(self) if defn.info: @@ -744,11 +744,11 @@ def _visit_func_def(self, defn: FuncDef) -> None: del partial_types[var] else: # Trying to redefine something like partial empty list as function. - self.fail(messages.INCOMPATIBLE_REDEFINITION, defn) + self.fail(message_registry.INCOMPATIBLE_REDEFINITION, defn) else: # TODO: Update conditional type binder. self.check_subtype(new_type, orig_type, defn, - messages.INCOMPATIBLE_REDEFINITION, + message_registry.INCOMPATIBLE_REDEFINITION, 'redefinition with type', 'original type') @@ -799,7 +799,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) if (fdef.info and fdef.name() in ('__init__', '__init_subclass__') and not isinstance(typ.ret_type, NoneTyp) and not self.dynamic_funcs[-1]): - self.fail(messages.MUST_HAVE_NONE_RETURN_TYPE.format(fdef.name()), + self.fail(message_registry.MUST_HAVE_NONE_RETURN_TYPE.format(fdef.name()), item) self.check_for_missing_annotations(fdef) @@ -826,24 +826,25 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) # Refuse contravariant return type variable if isinstance(typ.ret_type, TypeVarType): if typ.ret_type.variance == CONTRAVARIANT: - self.fail(messages.RETURN_TYPE_CANNOT_BE_CONTRAVARIANT, + self.fail(message_registry.RETURN_TYPE_CANNOT_BE_CONTRAVARIANT, typ.ret_type) # Check that Generator functions have the appropriate return type. if defn.is_generator: if defn.is_async_generator: if not self.is_async_generator_return_type(typ.ret_type): - self.fail(messages.INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR, typ) + self.fail(message_registry.INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR, + typ) else: if not self.is_generator_return_type(typ.ret_type, defn.is_coroutine): - self.fail(messages.INVALID_RETURN_TYPE_FOR_GENERATOR, typ) + self.fail(message_registry.INVALID_RETURN_TYPE_FOR_GENERATOR, typ) # Python 2 generators aren't allowed to return values. if (self.options.python_version[0] == 2 and isinstance(typ.ret_type, Instance) and typ.ret_type.type.fullname() == 'typing.Generator'): if not isinstance(typ.ret_type.args[2], (NoneTyp, AnyType)): - self.fail(messages.INVALID_GENERATOR_RETURN_ITEM_TYPE, typ) + self.fail(message_registry.INVALID_GENERATOR_RETURN_ITEM_TYPE, typ) # Fix the type if decorated with `@types.coroutine` or `@asyncio.coroutine`. if defn.is_awaitable_coroutine: @@ -882,13 +883,13 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) if typ.arg_names[i] in ['self', 'cls']: if (self.options.python_version[0] < 3 and is_same_type(erased, arg_type) and not isclass): - msg = messages.INVALID_SELF_TYPE_OR_EXTRA_ARG + msg = message_registry.INVALID_SELF_TYPE_OR_EXTRA_ARG note = '(Hint: typically annotations omit the type for self)' else: - msg = messages.ERASED_SELF_TYPE_NOT_SUPERTYPE.format( + msg = message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format( erased, ref_type) else: - msg = messages.MISSING_OR_INVALID_SELF_TYPE + msg = message_registry.MISSING_OR_INVALID_SELF_TYPE self.fail(msg, defn) if note: self.note(note, defn) @@ -902,7 +903,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) ctx = arg_type # type: Context if ctx.line < 0: ctx = typ - self.fail(messages.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, ctx) + self.fail(message_registry.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, ctx) if typ.arg_kinds[i] == nodes.ARG_STAR: # builtins.tuple[T] is typing.Tuple[T, ...] arg_type = self.named_generic_type('builtins.tuple', @@ -948,9 +949,9 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: Optional[str]) # entirely pass/Ellipsis. if isinstance(return_type, UninhabitedType): # This is a NoReturn function - self.msg.note(messages.INVALID_IMPLICIT_RETURN, defn) + self.msg.note(message_registry.INVALID_IMPLICIT_RETURN, defn) else: - self.msg.fail(messages.MISSING_RETURN_STATEMENT, defn) + self.msg.fail(message_registry.MISSING_RETURN_STATEMENT, defn) self.return_types.pop() @@ -981,20 +982,20 @@ def is_unannotated_any(t: Type) -> bool: check_incomplete_defs = self.options.disallow_incomplete_defs and has_explicit_annotation if show_untyped and (self.options.disallow_untyped_defs or check_incomplete_defs): if fdef.type is None and self.options.disallow_untyped_defs: - self.fail(messages.FUNCTION_TYPE_EXPECTED, fdef) + self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef) elif isinstance(fdef.type, CallableType): ret_type = fdef.type.ret_type if is_unannotated_any(ret_type): - self.fail(messages.RETURN_TYPE_EXPECTED, fdef) + 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(messages.RETURN_TYPE_EXPECTED, fdef) + 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(messages.RETURN_TYPE_EXPECTED, fdef) + self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) if any(is_unannotated_any(t) for t in fdef.type.arg_types): - self.fail(messages.ARGUMENT_TYPE_EXPECTED, fdef) + self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef) def is_trivial_body(self, block: Block) -> bool: body = block.body @@ -1218,7 +1219,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(messages.MODULE_LEVEL_GETATTRIBUTE, context) + self.msg.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 @@ -1527,7 +1528,7 @@ def visit_class_def(self, defn: ClassDef) -> None: self.check_protocol_variance(defn) for base in typ.mro[1:]: if base.is_final: - self.fail(messages.CANNOT_INHERIT_FROM_FINAL.format(base.name()), defn) + self.fail(message_registry.CANNOT_INHERIT_FROM_FINAL.format(base.name()), defn) with self.tscope.class_scope(defn.info), self.enter_partial_types(is_class=True): old_binder = self.binder self.binder = ConditionalTypeBinder() @@ -1680,7 +1681,7 @@ def check_import(self, node: ImportBase) -> None: if lvalue_type is None: # TODO: This is broken. lvalue_type = AnyType(TypeOfAny.special_form) - message = '{} "{}"'.format(messages.INCOMPATIBLE_IMPORT_OF, + message = '{} "{}"'.format(message_registry.INCOMPATIBLE_IMPORT_OF, cast(NameExpr, assign.rvalue).name) self.check_simple_assignment(lvalue_type, assign.rvalue, node, msg=message, lvalue_name='local name', @@ -1732,7 +1733,7 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: self.check_final(s) if (s.is_final_def and s.type and not has_no_typevars(s.type) and self.scope.active_class() is not None): - self.fail(messages.DEPENDENT_FINAL_IN_CLASS_BODY, s) + self.fail(message_registry.DEPENDENT_FINAL_IN_CLASS_BODY, s) def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type: bool = True, new_syntax: bool = False) -> None: @@ -1926,7 +1927,7 @@ def check_compatibility_super(self, lvalue: RefExpr, lvalue_type: Optional[Type] lvalue_node.is_staticmethod = True return self.check_subtype(compare_type, base_type, lvalue, - messages.INCOMPATIBLE_TYPES_IN_ASSIGNMENT, + message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT, 'expression has type', 'base class "%s" defined the type as' % base.name()) return True @@ -1976,10 +1977,10 @@ def check_compatibility_classvar_super(self, node: Var, if not isinstance(base_node, Var): return True if node.is_classvar and not base_node.is_classvar: - self.fail(messages.CANNOT_OVERRIDE_INSTANCE_VAR.format(base.name()), node) + self.fail(message_registry.CANNOT_OVERRIDE_INSTANCE_VAR.format(base.name()), node) return False elif not node.is_classvar and base_node.is_classvar: - self.fail(messages.CANNOT_OVERRIDE_CLASS_VAR.format(base.name()), node) + self.fail(message_registry.CANNOT_OVERRIDE_CLASS_VAR.format(base.name()), node) return False return True @@ -2481,7 +2482,7 @@ def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type def check_simple_assignment(self, lvalue_type: Optional[Type], rvalue: Expression, context: Context, - msg: str = messages.INCOMPATIBLE_TYPES_IN_ASSIGNMENT, + msg: str = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT, lvalue_name: str = 'variable', rvalue_name: str = 'expression') -> Type: if self.is_stub and isinstance(rvalue, EllipsisExpr): @@ -2538,7 +2539,8 @@ 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(messages.DESCRIPTOR_SET_NOT_CALLABLE.format(attribute_type), context) + self.msg.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')) @@ -2649,7 +2651,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: return_type = self.return_types[-1] if isinstance(return_type, UninhabitedType): - self.fail(messages.NO_RETURN_EXPECTED, s) + self.fail(message_registry.NO_RETURN_EXPECTED, s) return if s.expr: @@ -2670,7 +2672,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: allow_none_return=allow_none_func_call) if defn.is_async_generator: - self.fail(messages.RETURN_IN_ASYNC_GENERATOR, s) + self.fail(message_registry.RETURN_IN_ASYNC_GENERATOR, s) return # Returning a value of type Any is always fine. if isinstance(typ, AnyType): @@ -2691,7 +2693,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, NoneTyp): return - self.fail(messages.NO_RETURN_VALUE_EXPECTED, s) + self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s) else: self.check_subtype( subtype_label='got', @@ -2699,7 +2701,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: supertype_label='expected', supertype=return_type, context=s, - msg=messages.INCOMPATIBLE_RETURN_VALUE_TYPE) + msg=message_registry.INCOMPATIBLE_RETURN_VALUE_TYPE) else: # Empty returns are valid in Generators with Any typed returns, but not in # coroutines. @@ -2711,7 +2713,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None: return if self.in_checked_function(): - self.fail(messages.RETURN_VALUE_EXPECTED, s) + self.fail(message_registry.RETURN_VALUE_EXPECTED, s) def visit_if_stmt(self, s: IfStmt) -> None: """Type check an if statement.""" @@ -2776,7 +2778,7 @@ def visit_assert_stmt(self, s: AssertStmt) -> None: self.expr_checker.accept(s.msg) if isinstance(s.expr, TupleExpr) and len(s.expr.items) > 0: - self.warn(messages.MALFORMED_ASSERT, s) + self.warn(message_registry.MALFORMED_ASSERT, s) # If this is asserting some isinstance check, bind that type in the following code true_map, _ = self.find_isinstance_check(s.expr) @@ -2818,7 +2820,7 @@ def type_check_raise(self, e: Expression, s: RaiseStmt, expected_type = self.named_type('builtins.BaseException') # type: Type if optional: expected_type = UnionType([expected_type, NoneTyp()]) - self.check_subtype(typ, expected_type, s, messages.INVALID_EXCEPTION) + self.check_subtype(typ, expected_type, s, message_registry.INVALID_EXCEPTION) def visit_try_stmt(self, s: TryStmt) -> None: """Type check a try statement.""" @@ -2922,17 +2924,17 @@ def check_except_handler_test(self, n: Expression) -> Type: if isinstance(ttype, FunctionLike): item = ttype.items()[0] if not item.is_type_obj(): - self.fail(messages.INVALID_EXCEPTION_TYPE, n) + self.fail(message_registry.INVALID_EXCEPTION_TYPE, n) return AnyType(TypeOfAny.from_error) exc_type = item.ret_type elif isinstance(ttype, TypeType): exc_type = ttype.item else: - self.fail(messages.INVALID_EXCEPTION_TYPE, n) + self.fail(message_registry.INVALID_EXCEPTION_TYPE, n) return AnyType(TypeOfAny.from_error) if not is_subtype(exc_type, self.named_type('builtins.BaseException')): - self.fail(messages.INVALID_EXCEPTION_TYPE, n) + self.fail(message_registry.INVALID_EXCEPTION_TYPE, n) return AnyType(TypeOfAny.from_error) all_types.append(exc_type) @@ -2973,7 +2975,7 @@ def analyze_async_iterable_item_type(self, expr: Expression) -> Tuple[Type, Type iterator = echk.check_method_call_by_name('__aiter__', iterable, [], [], expr)[0] awaitable = echk.check_method_call_by_name('__anext__', iterator, [], [], expr)[0] item_type = echk.check_awaitable_expr(awaitable, expr, - messages.INCOMPATIBLE_TYPES_IN_ASYNC_FOR) + message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_FOR) return iterator, item_type def analyze_iterable_item_type(self, expr: Expression) -> Tuple[Type, Type]: @@ -3032,7 +3034,7 @@ def visit_decorator(self, e: Decorator) -> None: sig = self.function_type(e.func) # type: Type for d in reversed(e.decorators): if refers_to_fullname(d, 'typing.overload'): - self.fail(messages.MULTIPLE_OVERLOADS_REQUIRED, e) + self.fail(message_registry.MULTIPLE_OVERLOADS_REQUIRED, e) continue dec = self.expr_checker.accept(d) temp = self.temp_node(sig) @@ -3072,7 +3074,7 @@ def check_incompatible_property_override(self, e: Decorator) -> None: base_attr.node.is_property and cast(Decorator, base_attr.node.items[0]).var.is_settable_property): - self.fail(messages.READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE, e) + self.fail(message_registry.READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE, e) def visit_with_stmt(self, s: WithStmt) -> None: for expr, target in zip(s.expr, s.target): @@ -3095,14 +3097,14 @@ def check_async_with_item(self, expr: Expression, target: Optional[Expression], ctx = echk.accept(expr) obj = echk.check_method_call_by_name('__aenter__', ctx, [], [], expr)[0] obj = echk.check_awaitable_expr( - obj, expr, messages.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER) + obj, expr, message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER) if target: self.check_assignment(target, self.temp_node(obj, expr), infer_lvalue_type) arg = self.temp_node(AnyType(TypeOfAny.special_form), expr) res = echk.check_method_call_by_name( '__aexit__', ctx, [arg] * 3, [nodes.ARG_POS] * 3, expr)[0] echk.check_awaitable_expr( - res, expr, messages.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT) + res, expr, message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT) def check_with_item(self, expr: Expression, target: Optional[Expression], infer_lvalue_type: bool) -> None: @@ -3436,7 +3438,7 @@ def find_isinstance_check(self, node: Expression # def check_subtype(self, subtype: Type, supertype: Type, context: Context, - msg: str = messages.INCOMPATIBLE_TYPES, + msg: str = message_registry.INCOMPATIBLE_TYPES, subtype_label: Optional[str] = None, supertype_label: Optional[str] = None) -> bool: """Generate an error if the subtype is not compatible with diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 9d29c1bd0bba..c1fc9c74b7d6 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -41,7 +41,7 @@ from mypy.sametypes import is_same_type from mypy.erasetype import replace_meta_vars, erase_type from mypy.messages import MessageBuilder -from mypy import messages +from mypy import message_registry from mypy.infer import infer_type_arguments, infer_function_type_arguments from mypy import join from mypy.meet import narrow_declared_type @@ -395,7 +395,7 @@ def check_runtime_protocol_test(self, e: CallExpr) -> None: if (isinstance(tp, CallableType) and tp.is_type_obj() and tp.type_object().is_protocol and not tp.type_object().runtime_protocol): - self.chk.fail(messages.RUNTIME_PROTOCOL_EXPECTED, e) + self.chk.fail(message_registry.RUNTIME_PROTOCOL_EXPECTED, e) def check_protocol_issubclass(self, e: CallExpr) -> None: for expr in mypy.checker.flatten(e.args[1]): @@ -434,7 +434,7 @@ def check_typeddict_call(self, callee: TypedDictType, return self.check_typeddict_call_with_kwargs( callee, OrderedDict(), context) - self.chk.fail(messages.INVALID_TYPEDDICT_ARGS, context) + self.chk.fail(message_registry.INVALID_TYPEDDICT_ARGS, context) return AnyType(TypeOfAny.from_error) def check_typeddict_call_with_dict(self, callee: TypedDictType, @@ -446,7 +446,7 @@ def check_typeddict_call_with_dict(self, callee: TypedDictType, for item_name_expr, item_arg in kwargs.items: if not isinstance(item_name_expr, StrExpr): key_context = item_name_expr or item_arg - self.chk.fail(messages.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, key_context) + self.chk.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, key_context) return AnyType(TypeOfAny.from_error) item_names.append(item_name_expr.value) @@ -472,7 +472,7 @@ def check_typeddict_call_with_kwargs(self, callee: TypedDictType, item_value = kwargs[item_name] self.chk.check_simple_assignment( lvalue_type=item_expected_type, rvalue=item_value, context=item_value, - msg=messages.INCOMPATIBLE_TYPES, + msg=message_registry.INCOMPATIBLE_TYPES, lvalue_name='TypedDict item "{}"'.format(item_name), rvalue_name='expression') @@ -757,7 +757,7 @@ def check_callable_call(self, elif (callee.is_type_obj() and callee.type_object().is_protocol # Exception for Type[...] and not callee.from_type_type): - self.chk.fail(messages.CANNOT_INSTANTIATE_PROTOCOL + self.chk.fail(message_registry.CANNOT_INSTANTIATE_PROTOCOL .format(callee.type_object().name()), context) formal_to_actual = map_actuals_to_formals( @@ -1005,7 +1005,7 @@ def infer_function_type_arguments(self, callee_type: CallableType, if isinstance(first_arg, (NoneTyp, 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(messages.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE, + self.msg.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE, context) else: # In dynamically typed functions use implicit 'Any' types for @@ -2402,7 +2402,7 @@ def visit_index_expr_helper(self, e: IndexExpr) -> Type: if n >= 0 and n < len(left_type.items): return left_type.items[n] else: - self.chk.fail(messages.TUPLE_INDEX_OUT_OF_RANGE, e) + self.chk.fail(message_registry.TUPLE_INDEX_OUT_OF_RANGE, e) return AnyType(TypeOfAny.from_error) else: return self.nonliteral_tuple_index_helper(left_type, index) @@ -2444,7 +2444,7 @@ def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) expected_type = UnionType.make_union([self.named_type('builtins.int'), self.named_type('builtins.slice')]) if not self.chk.check_subtype(index_type, expected_type, index, - messages.INVALID_TUPLE_INDEX_TYPE, + message_registry.INVALID_TUPLE_INDEX_TYPE, 'actual type', 'expected type'): return AnyType(TypeOfAny.from_error) else: @@ -2553,14 +2553,14 @@ def visit_type_application(self, tapp: TypeApplication) -> Type: tp = type_object_type(item.type, self.named_type) return self.apply_type_arguments_to_callable(tp, item.args, tapp) else: - self.chk.fail(messages.ONLY_CLASS_APPLICATION, tapp) + self.chk.fail(message_registry.ONLY_CLASS_APPLICATION, tapp) return AnyType(TypeOfAny.from_error) # Type application of a normal generic class in runtime context. # This is typically used as `x = G[int]()`. tp = self.accept(tapp.expr) if isinstance(tp, (CallableType, Overloaded)): if not tp.is_type_obj(): - self.chk.fail(messages.ONLY_CLASS_APPLICATION, tapp) + self.chk.fail(message_registry.ONLY_CLASS_APPLICATION, tapp) return self.apply_type_arguments_to_callable(tp, tapp.types, tapp) if isinstance(tp, AnyType): return AnyType(TypeOfAny.from_another_any, source_any=tp) @@ -2888,7 +2888,7 @@ def infer_lambda_type_using_context(self, e: LambdaExpr) -> Tuple[Optional[Calla return callable_ctx, None if callable_ctx.arg_kinds != arg_kinds: # Incompatible context; cannot use it to infer types. - self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e) + self.chk.fail(message_registry.CANNOT_INFER_LAMBDA_TYPE, e) return None, None return callable_ctx, callable_ctx @@ -2902,15 +2902,15 @@ def visit_super_expr(self, e: SuperExpr) -> Type: def check_super_arguments(self, e: SuperExpr) -> None: """Check arguments in a super(...) call.""" if ARG_STAR in e.call.arg_kinds: - self.chk.fail(messages.SUPER_VARARGS_NOT_SUPPORTED, e) + self.chk.fail(message_registry.SUPER_VARARGS_NOT_SUPPORTED, e) elif e.call.args and set(e.call.arg_kinds) != {ARG_POS}: - self.chk.fail(messages.SUPER_POSITIONAL_ARGS_REQUIRED, e) + self.chk.fail(message_registry.SUPER_POSITIONAL_ARGS_REQUIRED, e) elif len(e.call.args) == 1: - self.chk.fail(messages.SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED, e) + self.chk.fail(message_registry.SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED, e) elif len(e.call.args) > 2: - self.chk.fail(messages.TOO_MANY_ARGS_FOR_SUPER, e) + self.chk.fail(message_registry.TOO_MANY_ARGS_FOR_SUPER, e) elif self.chk.options.python_version[0] == 2 and len(e.call.args) == 0: - self.chk.fail(messages.TOO_FEW_ARGS_FOR_SUPER, e) + self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e) elif len(e.call.args) == 2: type_obj_type = self.accept(e.call.args[0]) instance_type = self.accept(e.call.args[1]) @@ -2926,7 +2926,7 @@ def check_super_arguments(self, e: SuperExpr) -> None: if not isinstance(item, Instance): # A complicated type object type. Too tricky, give up. # TODO: Do something more clever here. - self.chk.fail(messages.UNSUPPORTED_ARG_1_FOR_SUPER, e) + self.chk.fail(message_registry.UNSUPPORTED_ARG_1_FOR_SUPER, e) return type_info = item.type elif isinstance(type_obj_type, AnyType): @@ -2942,19 +2942,19 @@ def check_super_arguments(self, e: SuperExpr) -> None: if not isinstance(instance_type, (Instance, TupleType)): # Too tricky, give up. # TODO: Do something more clever here. - self.chk.fail(messages.UNSUPPORTED_ARG_2_FOR_SUPER, e) + self.chk.fail(message_registry.UNSUPPORTED_ARG_2_FOR_SUPER, e) return if isinstance(instance_type, TupleType): # Needed for named tuples and other Tuple[...] subclasses. instance_type = instance_type.fallback if type_info not in instance_type.type.mro: - self.chk.fail(messages.SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1, e) + self.chk.fail(message_registry.SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1, e) elif isinstance(instance_type, TypeType) or (isinstance(instance_type, FunctionLike) and instance_type.is_type_obj()): # TODO: Check whether this is a valid type object here. pass elif not isinstance(instance_type, AnyType): - self.chk.fail(messages.UNSUPPORTED_ARG_2_FOR_SUPER, e) + self.chk.fail(message_registry.UNSUPPORTED_ARG_2_FOR_SUPER, e) def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type: """Type check a super expression.""" @@ -2973,7 +2973,7 @@ def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type: if not self.chk.in_checked_function(): return AnyType(TypeOfAny.unannotated) if self.chk.scope.active_class() is not None: - self.chk.fail(messages.SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED, e) + self.chk.fail(message_registry.SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED, e) return AnyType(TypeOfAny.from_error) method = self.chk.scope.top_function() assert method is not None @@ -2981,7 +2981,7 @@ def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type: # super() in a function with empty args is an error; we # need something in declared_self. if not args: - self.chk.fail(messages.SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED, e) + self.chk.fail(message_registry.SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED, e) return AnyType(TypeOfAny.from_error) declared_self = args[0].variable.type or fill_typevars(e.info) return analyze_member_access(name=e.name, @@ -3006,7 +3006,7 @@ def visit_slice_expr(self, e: SliceExpr) -> Type: if index: t = self.accept(index) self.chk.check_subtype(t, expected, - index, messages.INVALID_SLICE_INDEX) + index, message_registry.INVALID_SLICE_INDEX) return self.named_type('builtins.slice') def visit_list_comprehension(self, e: ListComprehension) -> Type: @@ -3277,11 +3277,11 @@ def visit_yield_expr(self, e: YieldExpr) -> Type: if e.expr is None: if (not isinstance(expected_item_type, (NoneTyp, AnyType)) and self.chk.in_checked_function()): - self.chk.fail(messages.YIELD_VALUE_EXPECTED, e) + self.chk.fail(message_registry.YIELD_VALUE_EXPECTED, e) else: actual_item_type = self.accept(e.expr, expected_item_type) self.chk.check_subtype(actual_item_type, expected_item_type, e, - messages.INCOMPATIBLE_TYPES_IN_YIELD, + message_registry.INCOMPATIBLE_TYPES_IN_YIELD, 'actual type', 'expected type') return self.chk.get_generator_receive_type(return_type, False) @@ -3292,7 +3292,8 @@ def visit_await_expr(self, e: AwaitExpr) -> Type: actual_type = self.accept(e.expr, expected_type) if isinstance(actual_type, AnyType): return AnyType(TypeOfAny.from_another_any, source_any=actual_type) - return self.check_awaitable_expr(actual_type, e, messages.INCOMPATIBLE_TYPES_IN_AWAIT) + 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: """Check the argument to `await` and extract the type of value. @@ -3337,8 +3338,8 @@ def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = Fals self.chk.msg.yield_from_invalid_operand_type(subexpr_type, e) iter_type = AnyType(TypeOfAny.from_error) else: - iter_type = self.check_awaitable_expr(subexpr_type, e, - messages.INCOMPATIBLE_TYPES_IN_YIELD_FROM) + iter_type = self.check_awaitable_expr( + subexpr_type, e, message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM) # Check that the iterator's item type matches the type yielded by the Generator function # containing this `yield from` expression. @@ -3346,8 +3347,8 @@ def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = Fals actual_item_type = self.chk.get_generator_yield_type(iter_type, False) self.chk.check_subtype(actual_item_type, expected_item_type, e, - messages.INCOMPATIBLE_TYPES_IN_YIELD_FROM, - 'actual type', 'expected type') + message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM, + 'actual type', 'expected type') # Determine the type of the entire yield from expression. if (isinstance(iter_type, Instance) and diff --git a/mypy/checkmember.py b/mypy/checkmember.py index c0bed7810308..14491f74b8ca 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -18,7 +18,7 @@ from mypy.typevars import fill_typevars from mypy.plugin import AttributeContext from mypy.typeanal import set_any_tvars -from mypy import messages +from mypy import message_registry from mypy import subtypes from mypy import meet @@ -147,7 +147,7 @@ def analyze_instance_member_access(name: str, if name == '__init__' and not mx.is_super: # Accessing __init__ in statically typed code would compromise # type safety unless used via super(). - mx.msg.fail(messages.CANNOT_ACCESS_INIT, mx.context) + mx.msg.fail(message_registry.CANNOT_ACCESS_INIT, mx.context) return AnyType(TypeOfAny.from_error) # The base object has an instance type. @@ -405,7 +405,7 @@ def analyze_descriptor_access(instance_type: Type, dunder_get = descriptor_type.type.get_method('__get__') if dunder_get is None: - msg.fail(messages.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) + msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) return AnyType(TypeOfAny.from_error) function = function_type(dunder_get, builtin_type('builtins.function')) @@ -432,7 +432,7 @@ def analyze_descriptor_access(instance_type: Type, return inferred_dunder_get_type if not isinstance(inferred_dunder_get_type, CallableType): - msg.fail(messages.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) + msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context) return AnyType(TypeOfAny.from_error) return inferred_dunder_get_type.ret_type @@ -586,12 +586,12 @@ def analyze_class_attribute_access(itype: Instance, if is_method: mx.msg.cant_assign_to_method(mx.context) if isinstance(node.node, TypeInfo): - mx.msg.fail(messages.CANNOT_ASSIGN_TO_TYPE, mx.context) + mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context) # If a final attribute was declared on `self` in `__init__`, then it # can't be accessed on the class object. if node.implicit and isinstance(node.node, Var) and node.node.is_final: - mx.msg.fail(messages.CANNOT_ACCESS_FINAL_INSTANCE_ATTR + mx.msg.fail(message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR .format(node.node.name()), mx.context) # An assignment to final attribute on class object is also always an error, @@ -609,7 +609,7 @@ def analyze_class_attribute_access(itype: Instance, assert isinstance(symnode, Var) return mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode, mx.context) if not is_method and (isinstance(t, TypeVarType) or get_type_vars(t)): - mx.msg.fail(messages.GENERIC_INSTANCE_VAR_CLASS_ACCESS, mx.context) + mx.msg.fail(message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS, mx.context) is_classmethod = ((is_decorated and cast(Decorator, node.node).func.is_class) or (isinstance(node.node, FuncBase) and node.node.is_class)) result = add_class_tvars(t, itype, is_classmethod, mx.builtin_type, mx.original_type) @@ -622,7 +622,7 @@ def analyze_class_attribute_access(itype: Instance, return AnyType(TypeOfAny.special_form) if isinstance(node.node, TypeVarExpr): - mx.msg.fail(messages.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format( + mx.msg.fail(message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format( itype.type.name(), name), mx.context) return AnyType(TypeOfAny.from_error) diff --git a/mypy/checkstrformat.py b/mypy/checkstrformat.py index 6ec0548c87e7..de24f9add742 100644 --- a/mypy/checkstrformat.py +++ b/mypy/checkstrformat.py @@ -17,7 +17,7 @@ import mypy.checker import mypy.checkexpr from typing_extensions import Final -from mypy import messages +from mypy import message_registry from mypy.messages import MessageBuilder FormatStringExpr = Union[StrExpr, BytesExpr, UnicodeExpr] @@ -192,7 +192,7 @@ def check_mapping_str_interpolation(self, specifiers: List[ConversionSpecifier], if expected_type is None: return self.chk.check_subtype(rep_type, expected_type, replacements, - messages.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, + message_registry.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, 'expression has type', 'placeholder with key \'%s\' has type' % specifier.key) else: @@ -201,7 +201,7 @@ def check_mapping_str_interpolation(self, specifiers: List[ConversionSpecifier], dict_type = self.chk.named_generic_type('builtins.dict', [any_type, any_type]) self.chk.check_subtype(rep_type, dict_type, replacements, - messages.FORMAT_REQUIRES_MAPPING, + message_registry.FORMAT_REQUIRES_MAPPING, 'expression has type', 'expected type for mapping is') def build_replacement_checkers(self, specifiers: List[ConversionSpecifier], @@ -268,7 +268,7 @@ def checkers_for_regular_type(self, type: str, def check_type(type: Type) -> None: assert expected_type is not None self.chk.check_subtype(type, expected_type, context, - messages.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, + message_registry.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, 'expression has type', 'placeholder has type') def check_expr(expr: Expression) -> None: @@ -290,7 +290,7 @@ def checkers_for_c_type(self, type: str, def check_type(type: Type) -> None: assert expected_type is not None self.chk.check_subtype(type, expected_type, context, - messages.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, + message_registry.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION, 'expression has type', 'placeholder has type') def check_expr(expr: Expression) -> None: diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 690cbe9ee6d2..82e8c65c4a6d 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -34,7 +34,7 @@ TypeOfAny, Instance, RawExpressionType, ) from mypy import defaults -from mypy import messages +from mypy import message_registry from mypy.errors import Errors from mypy.options import Options @@ -404,7 +404,7 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], isinstance(func_type_ast.argtypes[0], ast3_Ellipsis)): if n.returns: # PEP 484 disallows both type annotations and type comments - self.fail(messages.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) + self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) arg_types = [a.type_annotation if a.type_annotation is not None else AnyType(TypeOfAny.unannotated) @@ -412,7 +412,7 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], else: # PEP 484 disallows both type annotations and type comments if n.returns or any(a.type_annotation is not None for a in args): - self.fail(messages.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) + self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) translated_args = (TypeConverter(self.errors, line=lineno) .translate_expr_list(func_type_ast.argtypes)) arg_types = [a if a is not None else AnyType(TypeOfAny.unannotated) @@ -540,7 +540,7 @@ def make_argument(self, arg: ast3.arg, default: Optional[ast3.expr], kind: int, annotation = arg.annotation type_comment = arg.type_comment if annotation is not None and type_comment is not None: - self.fail(messages.DUPLICATE_TYPE_SIGNATURES, arg.lineno, arg.col_offset) + self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, arg.lineno, arg.col_offset) arg_type = None if annotation is not None: arg_type = TypeConverter(self.errors, line=arg.lineno).visit(annotation) diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py index 8100c316ea30..46b1bd457c51 100644 --- a/mypy/fastparse2.py +++ b/mypy/fastparse2.py @@ -43,7 +43,7 @@ from mypy.types import ( Type, CallableType, AnyType, UnboundType, EllipsisType, TypeOfAny, Instance, ) -from mypy import messages +from mypy import message_registry from mypy.errors import Errors from mypy.fastparse import TypeConverter, parse_type_comment, bytes_to_human_readable_repr from mypy.options import Options @@ -351,7 +351,7 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement: else: # PEP 484 disallows both type annotations and type comments if any(a.type_annotation is not None for a in args): - self.fail(messages.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) + self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) arg_types = [a if a is not None else AnyType(TypeOfAny.unannotated) for a in converter.translate_expr_list(func_type_ast.argtypes)] return_type = converter.visit(func_type_ast.returns) diff --git a/mypy/message_registry.py b/mypy/message_registry.py new file mode 100644 index 000000000000..7279ea20dca5 --- /dev/null +++ b/mypy/message_registry.py @@ -0,0 +1,139 @@ +"""Message constants for generating error messages during type checking. + +Literal messages should be defined as constants in this module so they won't get out of sync +if used in more than one place, and so that they can be easily introspected. These messages are +ultimately consumed by messages.MessageBuilder.fail(). For more non-trivial message generation, +add a method to MessageBuilder and call this instead. +""" + +MYPY = False +if MYPY: + from typing_extensions import Final + + +# Type checker error message constants -- + +NO_RETURN_VALUE_EXPECTED = 'No return value expected' # type: Final +MISSING_RETURN_STATEMENT = 'Missing return statement' # type: Final +INVALID_IMPLICIT_RETURN = 'Implicit return in function which does not return' # type: Final +INCOMPATIBLE_RETURN_VALUE_TYPE = 'Incompatible return value type' # type: Final +RETURN_VALUE_EXPECTED = 'Return value expected' # type: Final +NO_RETURN_EXPECTED = 'Return statement in function which does not return' # type: Final +INVALID_EXCEPTION = 'Exception must be derived from BaseException' # type: Final +INVALID_EXCEPTION_TYPE = 'Exception type must be derived from BaseException' # type: Final +RETURN_IN_ASYNC_GENERATOR = "'return' with value in async generator is not allowed" # type: Final +INVALID_RETURN_TYPE_FOR_GENERATOR = \ + 'The return type of a generator function should be "Generator"' \ + ' or one of its supertypes' # type: Final +INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR = \ + 'The return type of an async generator function should be "AsyncGenerator" or one of its ' \ + 'supertypes' # type: Final +INVALID_GENERATOR_RETURN_ITEM_TYPE = \ + 'The return type of a generator function must be None in' \ + ' its third type parameter in Python 2' # type: Final +YIELD_VALUE_EXPECTED = 'Yield value expected' # type: Final +INCOMPATIBLE_TYPES = 'Incompatible types' # type: Final +INCOMPATIBLE_TYPES_IN_ASSIGNMENT = 'Incompatible types in assignment' # type: Final +INCOMPATIBLE_REDEFINITION = 'Incompatible redefinition' # type: Final +INCOMPATIBLE_TYPES_IN_AWAIT = 'Incompatible types in "await"' # type: Final +INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER = \ + 'Incompatible types in "async with" for "__aenter__"' # type: Final +INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT = \ + 'Incompatible types in "async with" for "__aexit__"' # type: Final +INCOMPATIBLE_TYPES_IN_ASYNC_FOR = 'Incompatible types in "async for"' # type: Final + +INCOMPATIBLE_TYPES_IN_YIELD = 'Incompatible types in "yield"' # type: Final +INCOMPATIBLE_TYPES_IN_YIELD_FROM = 'Incompatible types in "yield from"' # type: Final +INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION = \ + 'Incompatible types in string interpolation' # type: Final +MUST_HAVE_NONE_RETURN_TYPE = 'The return type of "{}" must be None' # type: Final +INVALID_TUPLE_INDEX_TYPE = 'Invalid tuple index type' # type: Final +TUPLE_INDEX_OUT_OF_RANGE = 'Tuple index out of range' # type: Final +INVALID_SLICE_INDEX = 'Slice index must be an integer or None' # type: Final +CANNOT_INFER_LAMBDA_TYPE = 'Cannot infer type of lambda' # type: Final +CANNOT_ACCESS_INIT = 'Cannot access "__init__" directly' # type: Final +CANNOT_ASSIGN_TO_METHOD = 'Cannot assign to a method' # type: Final +CANNOT_ASSIGN_TO_TYPE = 'Cannot assign to a type' # type: Final +INCONSISTENT_ABSTRACT_OVERLOAD = \ + 'Overloaded method has both abstract and non-abstract variants' # type: Final +MULTIPLE_OVERLOADS_REQUIRED = 'Single overload definition, multiple required' # type: Final +READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE = \ + 'Read-only property cannot override read-write property' # type: Final +FORMAT_REQUIRES_MAPPING = 'Format requires a mapping' # type: Final +RETURN_TYPE_CANNOT_BE_CONTRAVARIANT = \ + "Cannot use a contravariant type variable as return type" # type: Final +FUNCTION_PARAMETER_CANNOT_BE_COVARIANT = \ + "Cannot use a covariant type variable as a parameter" # type: Final +INCOMPATIBLE_IMPORT_OF = "Incompatible import of" # type: Final +FUNCTION_TYPE_EXPECTED = "Function is missing a type annotation" # type: Final +ONLY_CLASS_APPLICATION = "Type application is only supported for generic classes" # type: Final +RETURN_TYPE_EXPECTED = "Function is missing a return type annotation" # type: Final +ARGUMENT_TYPE_EXPECTED = \ + "Function is missing a type annotation for one or more arguments" # type: Final +KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE = \ + 'Keyword argument only valid with "str" key type in call to "dict"' # type: Final +ALL_MUST_BE_SEQ_STR = 'Type of __all__ must be {}, not {}' # type: Final +INVALID_TYPEDDICT_ARGS = \ + 'Expected keyword arguments, {...}, or dict(...) in TypedDict constructor' # type: Final +TYPEDDICT_KEY_MUST_BE_STRING_LITERAL = \ + 'Expected TypedDict key to be string literal' # type: Final +MALFORMED_ASSERT = 'Assertion is always true, perhaps remove parentheses?' # type: Final +DUPLICATE_TYPE_SIGNATURES = 'Function has duplicate type signatures' # type: Final +DESCRIPTOR_SET_NOT_CALLABLE = "{}.__set__ is not callable" # type: Final +DESCRIPTOR_GET_NOT_CALLABLE = "{}.__get__ is not callable" # type: Final +MODULE_LEVEL_GETATTRIBUTE = '__getattribute__ is not valid at the module level' # type: Final + +# Generic +GENERIC_INSTANCE_VAR_CLASS_ACCESS = \ + 'Access to generic instance variables via class is ambiguous' # type: Final +BARE_GENERIC = 'Missing type parameters for generic type' # type: Final +IMPLICIT_GENERIC_ANY_BUILTIN = \ + 'Implicit generic "Any". Use "{}" and specify generic parameters' # type: Final + +# TypeVar +INCOMPATIBLE_TYPEVAR_VALUE = 'Value of type variable "{}" of {} cannot be {}' # type: Final +CANNOT_USE_TYPEVAR_AS_EXPRESSION = \ + 'Type variable "{}.{}" cannot be used as an expression' # type: Final + +# Super +TOO_MANY_ARGS_FOR_SUPER = 'Too many arguments for "super"' # type: Final +TOO_FEW_ARGS_FOR_SUPER = 'Too few arguments for "super"' # type: Final +SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED = '"super" with a single argument not supported' # type: Final +UNSUPPORTED_ARG_1_FOR_SUPER = 'Unsupported argument 1 for "super"' # type: Final +UNSUPPORTED_ARG_2_FOR_SUPER = 'Unsupported argument 2 for "super"' # type: Final +SUPER_VARARGS_NOT_SUPPORTED = 'Varargs not supported with "super"' # type: Final +SUPER_POSITIONAL_ARGS_REQUIRED = '"super" only accepts positional arguments' # type: Final +SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1 = \ + 'Argument 2 for "super" not an instance of argument 1' # type: Final +SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED = \ + 'super() outside of a method is not supported' # type: Final +SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED = \ + 'super() requires one or more positional arguments in enclosing function' # type: Final + +# Self-type +MISSING_OR_INVALID_SELF_TYPE = \ + "Self argument missing for a non-static method (or an invalid type for self)" # type: Final +ERASED_SELF_TYPE_NOT_SUPERTYPE = \ + 'The erased type of self "{}" is not a supertype of its class "{}"' # type: Final +INVALID_SELF_TYPE_OR_EXTRA_ARG = \ + "Invalid type for self, or extra argument type in function annotation" # type: Final + +# Final +CANNOT_INHERIT_FROM_FINAL = 'Cannot inherit from final class "{}"' # type: Final +DEPENDENT_FINAL_IN_CLASS_BODY = \ + "Final name declared in class body cannot depend on type variables" # type: Final +CANNOT_ACCESS_FINAL_INSTANCE_ATTR = \ + 'Cannot access final instance attribute "{}" on class object' # type: Final + +# ClassVar +CANNOT_OVERRIDE_INSTANCE_VAR = \ + 'Cannot override instance variable (previously declared on base class "{}") with class ' \ + 'variable' # type: Final +CANNOT_OVERRIDE_CLASS_VAR = \ + 'Cannot override class variable (previously declared on base class "{}") with instance ' \ + 'variable' # type: Final + +# Protocol +RUNTIME_PROTOCOL_EXPECTED = \ + 'Only @runtime protocols can be used with instance and class checks' # type: Final +CANNOT_INSTANTIATE_PROTOCOL = 'Cannot instantiate protocol class "{}"' # type: Final diff --git a/mypy/messages.py b/mypy/messages.py index 6ef15e356d9f..1cff185574c7 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -1,10 +1,9 @@ -"""Facilities and constants for generating error messages during type checking. +"""Facilities for generating error messages during type checking. Don't add any non-trivial message construction logic to the type checker, as it can compromise clarity and make messages less -consistent. Add such logic to this module instead. Literal messages used -in multiple places should also be defined as constants in this module so -they won't get out of sync. +consistent. Add such logic to this module instead. Literal messages, including those +with format args, should be defined as constants in mypy.message_registry. Historically we tried to avoid all message string literals in the type checker but we are moving away from this convention. @@ -30,138 +29,12 @@ ReturnStmt, NameExpr, Var, CONTRAVARIANT, COVARIANT, SymbolNode, CallExpr ) +from mypy import message_registry MYPY = False if MYPY: from typing_extensions import Final -# Type checker error message constants -- - -NO_RETURN_VALUE_EXPECTED = 'No return value expected' # type: Final -MISSING_RETURN_STATEMENT = 'Missing return statement' # type: Final -INVALID_IMPLICIT_RETURN = 'Implicit return in function which does not return' # type: Final -INCOMPATIBLE_RETURN_VALUE_TYPE = 'Incompatible return value type' # type: Final -RETURN_VALUE_EXPECTED = 'Return value expected' # type: Final -NO_RETURN_EXPECTED = 'Return statement in function which does not return' # type: Final -INVALID_EXCEPTION = 'Exception must be derived from BaseException' # type: Final -INVALID_EXCEPTION_TYPE = 'Exception type must be derived from BaseException' # type: Final -RETURN_IN_ASYNC_GENERATOR = "'return' with value in async generator is not allowed" # type: Final -INVALID_RETURN_TYPE_FOR_GENERATOR = \ - 'The return type of a generator function should be "Generator"' \ - ' or one of its supertypes' # type: Final -INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR = \ - 'The return type of an async generator function should be "AsyncGenerator" or one of its ' \ - 'supertypes' # type: Final -INVALID_GENERATOR_RETURN_ITEM_TYPE = \ - 'The return type of a generator function must be None in' \ - ' its third type parameter in Python 2' # type: Final -YIELD_VALUE_EXPECTED = 'Yield value expected' # type: Final -INCOMPATIBLE_TYPES = 'Incompatible types' # type: Final -INCOMPATIBLE_TYPES_IN_ASSIGNMENT = 'Incompatible types in assignment' # type: Final -INCOMPATIBLE_REDEFINITION = 'Incompatible redefinition' # type: Final -INCOMPATIBLE_TYPES_IN_AWAIT = 'Incompatible types in "await"' # type: Final -INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER = \ - 'Incompatible types in "async with" for "__aenter__"' # type: Final -INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT = \ - 'Incompatible types in "async with" for "__aexit__"' # type: Final -INCOMPATIBLE_TYPES_IN_ASYNC_FOR = 'Incompatible types in "async for"' # type: Final - -INCOMPATIBLE_TYPES_IN_YIELD = 'Incompatible types in "yield"' # type: Final -INCOMPATIBLE_TYPES_IN_YIELD_FROM = 'Incompatible types in "yield from"' # type: Final -INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION = \ - 'Incompatible types in string interpolation' # type: Final -MUST_HAVE_NONE_RETURN_TYPE = 'The return type of "{}" must be None' # type: Final -INVALID_TUPLE_INDEX_TYPE = 'Invalid tuple index type' # type: Final -TUPLE_INDEX_OUT_OF_RANGE = 'Tuple index out of range' # type: Final -INVALID_SLICE_INDEX = 'Slice index must be an integer or None' # type: Final -CANNOT_INFER_LAMBDA_TYPE = 'Cannot infer type of lambda' # type: Final -CANNOT_ACCESS_INIT = 'Cannot access "__init__" directly' # type: Final -CANNOT_ASSIGN_TO_METHOD = 'Cannot assign to a method' # type: Final -CANNOT_ASSIGN_TO_TYPE = 'Cannot assign to a type' # type: Final -INCONSISTENT_ABSTRACT_OVERLOAD = \ - 'Overloaded method has both abstract and non-abstract variants' # type: Final -MULTIPLE_OVERLOADS_REQUIRED = 'Single overload definition, multiple required' # type: Final -READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE = \ - 'Read-only property cannot override read-write property' # type: Final -FORMAT_REQUIRES_MAPPING = 'Format requires a mapping' # type: Final -RETURN_TYPE_CANNOT_BE_CONTRAVARIANT = \ - "Cannot use a contravariant type variable as return type" # type: Final -FUNCTION_PARAMETER_CANNOT_BE_COVARIANT = \ - "Cannot use a covariant type variable as a parameter" # type: Final -INCOMPATIBLE_IMPORT_OF = "Incompatible import of" # type: Final -FUNCTION_TYPE_EXPECTED = "Function is missing a type annotation" # type: Final -ONLY_CLASS_APPLICATION = "Type application is only supported for generic classes" # type: Final -RETURN_TYPE_EXPECTED = "Function is missing a return type annotation" # type: Final -ARGUMENT_TYPE_EXPECTED = \ - "Function is missing a type annotation for one or more arguments" # type: Final -KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE = \ - 'Keyword argument only valid with "str" key type in call to "dict"' # type: Final -ALL_MUST_BE_SEQ_STR = 'Type of __all__ must be {}, not {}' # type: Final -INVALID_TYPEDDICT_ARGS = \ - 'Expected keyword arguments, {...}, or dict(...) in TypedDict constructor' # type: Final -TYPEDDICT_KEY_MUST_BE_STRING_LITERAL = \ - 'Expected TypedDict key to be string literal' # type: Final -MALFORMED_ASSERT = 'Assertion is always true, perhaps remove parentheses?' # type: Final -DUPLICATE_TYPE_SIGNATURES = 'Function has duplicate type signatures' # type: Final -DESCRIPTOR_SET_NOT_CALLABLE = "{}.__set__ is not callable" # type: Final -DESCRIPTOR_GET_NOT_CALLABLE = "{}.__get__ is not callable" # type: Final -MODULE_LEVEL_GETATTRIBUTE = '__getattribute__ is not valid at the module level' # type: Final - -# Generic -GENERIC_INSTANCE_VAR_CLASS_ACCESS = \ - 'Access to generic instance variables via class is ambiguous' # type: Final -BARE_GENERIC = 'Missing type parameters for generic type' # type: Final -IMPLICIT_GENERIC_ANY_BUILTIN = \ - 'Implicit generic "Any". Use "{}" and specify generic parameters' # type: Final - -# TypeVar -INCOMPATIBLE_TYPEVAR_VALUE = 'Value of type variable "{}" of {} cannot be {}' # type: Final -CANNOT_USE_TYPEVAR_AS_EXPRESSION = \ - 'Type variable "{}.{}" cannot be used as an expression' # type: Final - -# Super -TOO_MANY_ARGS_FOR_SUPER = 'Too many arguments for "super"' # type: Final -TOO_FEW_ARGS_FOR_SUPER = 'Too few arguments for "super"' # type: Final -SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED = '"super" with a single argument not supported' # type: Final -UNSUPPORTED_ARG_1_FOR_SUPER = 'Unsupported argument 1 for "super"' # type: Final -UNSUPPORTED_ARG_2_FOR_SUPER = 'Unsupported argument 2 for "super"' # type: Final -SUPER_VARARGS_NOT_SUPPORTED = 'Varargs not supported with "super"' # type: Final -SUPER_POSITIONAL_ARGS_REQUIRED = '"super" only accepts positional arguments' # type: Final -SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1 = \ - 'Argument 2 for "super" not an instance of argument 1' # type: Final -SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED = \ - 'super() outside of a method is not supported' # type: Final -SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED = \ - 'super() requires one or more positional arguments in enclosing function' # type: Final - -# Self-type -MISSING_OR_INVALID_SELF_TYPE = \ - "Self argument missing for a non-static method (or an invalid type for self)" # type: Final -ERASED_SELF_TYPE_NOT_SUPERTYPE = \ - 'The erased type of self "{}" is not a supertype of its class "{}"' # type: Final -INVALID_SELF_TYPE_OR_EXTRA_ARG = \ - "Invalid type for self, or extra argument type in function annotation" # type: Final - -# Final -CANNOT_INHERIT_FROM_FINAL = 'Cannot inherit from final class "{}"' # type: Final -DEPENDENT_FINAL_IN_CLASS_BODY = \ - "Final name declared in class body cannot depend on type variables" # type: Final -CANNOT_ACCESS_FINAL_INSTANCE_ATTR = \ - 'Cannot access final instance attribute "{}" on class object' # type: Final - -# ClassVar -CANNOT_OVERRIDE_INSTANCE_VAR = \ - 'Cannot override instance variable (previously declared on base class "{}") with class ' \ - 'variable' # type: Final -CANNOT_OVERRIDE_CLASS_VAR = \ - 'Cannot override class variable (previously declared on base class "{}") with instance ' \ - 'variable' # type: Final - -# Protocol -RUNTIME_PROTOCOL_EXPECTED = \ - 'Only @runtime protocols can be used with instance and class checks' # type: Final -CANNOT_INSTANTIATE_PROTOCOL = 'Cannot instantiate protocol class "{}"' # type: Final - ARG_CONSTRUCTOR_NAMES = { ARG_POS: "Arg", @@ -647,7 +520,7 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type: msg = '{} (expression has type {}, target has type {})' arg_type_str, callee_type_str = self.format_distinctly(arg_type, callee.arg_types[n - 1]) - self.fail(msg.format(INCOMPATIBLE_TYPES_IN_ASSIGNMENT, + self.fail(msg.format(message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT, arg_type_str, callee_type_str), context) return @@ -1061,7 +934,7 @@ def base_class_definitions_incompatible(self, name: str, base1: TypeInfo, name, base1.name(), base2.name()), context) def cant_assign_to_method(self, context: Context) -> None: - self.fail(CANNOT_ASSIGN_TO_METHOD, context) + self.fail(message_registry.CANNOT_ASSIGN_TO_METHOD, context) def cant_assign_to_classvar(self, name: str, context: Context) -> None: self.fail('Cannot assign to class variable "%s" via instance' % name, context) @@ -1097,9 +970,8 @@ def incompatible_typevar_value(self, typ: Type, typevar_name: str, context: Context) -> None: - self.fail(INCOMPATIBLE_TYPEVAR_VALUE.format(typevar_name, - callable_name(callee) or 'function', - self.format(typ)), + self.fail(message_registry.INCOMPATIBLE_TYPEVAR_VALUE + .format(typevar_name, callable_name(callee) or 'function', self.format(typ)), context) def overload_inconsistently_applies_decorator(self, decorator: str, context: Context) -> None: diff --git a/mypy/plugins/default.py b/mypy/plugins/default.py index a4b2eb745c52..92d3d10f9111 100644 --- a/mypy/plugins/default.py +++ b/mypy/plugins/default.py @@ -1,7 +1,7 @@ from functools import partial from typing import Callable, Optional -from mypy import messages +from mypy import message_registry from mypy.nodes import StrExpr, IntExpr, DictExpr, UnaryExpr from mypy.plugin import ( Plugin, FunctionContext, MethodContext, MethodSigContext, AttributeContext, ClassDefContext @@ -230,7 +230,7 @@ def typed_dict_pop_callback(ctx: MethodContext) -> Type: and len(ctx.arg_types[0]) == 1): key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0]) if key is None: - ctx.api.fail(messages.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) + ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) return AnyType(TypeOfAny.from_error) if key in ctx.type.required_keys: @@ -276,7 +276,7 @@ def typed_dict_setdefault_callback(ctx: MethodContext) -> Type: and len(ctx.arg_types[0]) == 1): key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0]) if key is None: - ctx.api.fail(messages.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) + ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) return AnyType(TypeOfAny.from_error) value_type = ctx.type.items.get(key) @@ -301,7 +301,7 @@ def typed_dict_delitem_callback(ctx: MethodContext) -> Type: and len(ctx.arg_types[0]) == 1): key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0]) if key is None: - ctx.api.fail(messages.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) + ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) return AnyType(TypeOfAny.from_error) if key in ctx.type.required_keys: diff --git a/mypy/semanal.py b/mypy/semanal.py index e2bcf0f70ab2..3304590c1b90 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -62,7 +62,8 @@ from mypy.typevars import fill_typevars from mypy.visitor import NodeVisitor from mypy.errors import Errors, report_internal_error -from mypy.messages import CANNOT_ASSIGN_TO_TYPE, MessageBuilder +from mypy.messages import MessageBuilder +from mypy import message_registry from mypy.types import ( FunctionLike, UnboundType, TypeVarDef, TupleType, UnionType, StarType, function_type, CallableType, Overloaded, Instance, Type, AnyType, LiteralType, LiteralValue, @@ -2259,7 +2260,7 @@ def check_lvalue_validity(self, node: Union[Expression, SymbolNode, None], if isinstance(node, TypeVarExpr): self.fail('Invalid assignment target', ctx) elif isinstance(node, TypeInfo): - self.fail(CANNOT_ASSIGN_TO_TYPE, ctx) + self.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, ctx) def store_declared_types(self, lvalue: Lvalue, typ: Type) -> None: if isinstance(typ, StarType) and not isinstance(lvalue, StarExpr): diff --git a/mypy/semanal_pass3.py b/mypy/semanal_pass3.py index 3862d84e1039..f31742a503b9 100644 --- a/mypy/semanal_pass3.py +++ b/mypy/semanal_pass3.py @@ -12,7 +12,7 @@ from collections import OrderedDict from typing import Dict, List, Callable, Optional, Union, cast, Tuple -from mypy import messages, state +from mypy import message_registry, state from mypy.nodes import ( Node, Expression, MypyFile, FuncDef, Decorator, RefExpr, Context, TypeInfo, ClassDef, Block, TypedDictExpr, NamedTupleExpr, AssignmentStmt, IndexExpr, TypeAliasExpr, NameExpr, @@ -501,7 +501,7 @@ def check_for_omitted_generics(self, typ: Type) -> None: for t in collect_any_types(typ): if t.type_of_any == TypeOfAny.from_omitted_generics: - self.fail(messages.BARE_GENERIC, t) + self.fail(message_registry.BARE_GENERIC, t) def lookup_qualified(self, name: str, ctx: Context, suppress_errors: bool = False) -> Optional[SymbolTableNode]: @@ -780,5 +780,5 @@ def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: s else: class_name = '"{}"'.format(type.name()) actual_type_name = '"{}"'.format(actual.type.name()) - self.fail(messages.INCOMPATIBLE_TYPEVAR_VALUE.format( + self.fail(message_registry.INCOMPATIBLE_TYPEVAR_VALUE.format( arg_name, class_name, actual_type_name), context) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index f6b36782b231..d141ccd6e7ed 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -29,7 +29,7 @@ from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError from mypy.plugin import Plugin, TypeAnalyzerPluginInterface, AnalyzeTypeContext from mypy.semanal_shared import SemanticAnalyzerCoreInterface -from mypy import nodes, messages +from mypy import nodes, message_registry MYPY = False if MYPY: @@ -273,7 +273,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt if len(t.args) == 0 and not t.empty_tuple_index: # Bare 'Tuple' is same as 'tuple' if self.options.disallow_any_generics and not self.is_typeshed_stub: - self.fail(messages.BARE_GENERIC, t) + self.fail(message_registry.BARE_GENERIC, t) return self.named_type('builtins.tuple', line=t.line, column=t.column) if len(t.args) == 2 and isinstance(t.args[1], EllipsisType): # Tuple[T, ...] (uniform, variable-length tuple) @@ -341,7 +341,7 @@ def analyze_unbound_type_with_type_info(self, t: UnboundType, info: TypeInfo) -> # in the third pass. if not self.is_typeshed_stub and info.fullname() in nongen_builtins: alternative = nongen_builtins[info.fullname()] - self.fail(messages.IMPLICIT_GENERIC_ANY_BUILTIN.format(alternative), t) + self.fail(message_registry.IMPLICIT_GENERIC_ANY_BUILTIN.format(alternative), t) any_type = AnyType(TypeOfAny.from_error, line=t.line) else: any_type = AnyType(TypeOfAny.from_omitted_generics, line=t.line)