Skip to content

Add option to tag known messages with an error code #6152

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

Closed
wants to merge 11 commits into from
3 changes: 2 additions & 1 deletion mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ def _build(sources: List[BuildSource],
reports = Reports(data_dir, options.report_dirs)

source_set = BuildSourceSet(sources)
errors = Errors(options.show_error_context, options.show_column_numbers)
errors = Errors(options.show_error_context, options.show_column_numbers,
options.show_error_codes)
plugin, snapshot = load_plugins(options, errors)

# Construct a build manager object to hold state during the build.
Expand Down
118 changes: 60 additions & 58 deletions mypy/checker.py

Large diffs are not rendered by default.

63 changes: 32 additions & 31 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(messages.ErrorCodes.RUNTIME_PROTOCOL_EXPECTED, e)

def check_protocol_issubclass(self, e: CallExpr) -> None:
for expr in mypy.checker.flatten(e.args[1]):
Expand All @@ -404,7 +404,7 @@ def check_protocol_issubclass(self, e: CallExpr) -> None:
tp.type_object().is_protocol):
attr_members = non_method_protocol_members(tp.type_object())
if attr_members:
self.chk.msg.report_non_method_protocol(tp.type_object(),
self.chk.msg.issubclass_on_non_method_protocol(tp.type_object(),
attr_members, e)

def check_typeddict_call(self, callee: TypedDictType,
Expand Down Expand Up @@ -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(messages.ErrorCodes.INVALID_TYPEDDICT_ARGS, context)
return AnyType(TypeOfAny.from_error)

def check_typeddict_call_with_dict(self, callee: TypedDictType,
Expand All @@ -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(messages.ErrorCodes.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, key_context)
return AnyType(TypeOfAny.from_error)
item_names.append(item_name_expr.value)

Expand All @@ -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=messages.ErrorCodes.INCOMPATIBLE_TYPES,
lvalue_name='TypedDict item "{}"'.format(item_name),
rvalue_name='expression')

Expand Down Expand Up @@ -720,7 +720,8 @@ def check_call(self,
arg_names, callable_node, arg_messages, callable_name,
object_type)
else:
return self.msg.not_callable(callee, context), AnyType(TypeOfAny.from_error)
return (self.msg.type_has_no_attr(callee, callee, '__call__', context),
AnyType(TypeOfAny.from_error))

def check_callable_call(self,
callee: CallableType,
Expand Down Expand Up @@ -757,7 +758,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(messages.ErrorCodes.CANNOT_INSTANTIATE_PROTOCOL
.format(callee.type_object().name()), context)

formal_to_actual = map_actuals_to_formals(
Expand Down Expand Up @@ -1005,7 +1006,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(messages.ErrorCodes.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE,
context)
else:
# In dynamically typed functions use implicit 'Any' types for
Expand Down Expand Up @@ -2402,7 +2403,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(messages.ErrorCodes.TUPLE_INDEX_OUT_OF_RANGE, e)
return AnyType(TypeOfAny.from_error)
else:
return self.nonliteral_tuple_index_helper(left_type, index)
Expand Down Expand Up @@ -2444,7 +2445,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,
messages.ErrorCodes.INVALID_TUPLE_INDEX_TYPE,
'actual type', 'expected type'):
return AnyType(TypeOfAny.from_error)
else:
Expand Down Expand Up @@ -2548,14 +2549,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(messages.ErrorCodes.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(messages.ErrorCodes.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)
Expand Down Expand Up @@ -2883,7 +2884,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(messages.ErrorCodes.CANNOT_INFER_LAMBDA_TYPE, e)
return None, None

return callable_ctx, callable_ctx
Expand All @@ -2897,15 +2898,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(messages.ErrorCodes.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(messages.ErrorCodes.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(messages.ErrorCodes.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(messages.ErrorCodes.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(messages.ErrorCodes.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])
Expand All @@ -2921,7 +2922,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(messages.ErrorCodes.UNSUPPORTED_ARG_1_FOR_SUPER, e)
return
type_info = item.type
elif isinstance(type_obj_type, AnyType):
Expand All @@ -2937,19 +2938,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(messages.ErrorCodes.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(messages.ErrorCodes.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(messages.ErrorCodes.UNSUPPORTED_ARG_2_FOR_SUPER, e)

def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type:
"""Type check a super expression."""
Expand All @@ -2968,15 +2969,15 @@ 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(messages.ErrorCodes.SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED, e)
return AnyType(TypeOfAny.from_error)
method = self.chk.scope.top_function()
assert method is not None
args = method.arguments
# 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(messages.ErrorCodes.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,
Expand All @@ -3001,7 +3002,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, messages.ErrorCodes.INVALID_SLICE_INDEX)
return self.named_type('builtins.slice')

def visit_list_comprehension(self, e: ListComprehension) -> Type:
Expand Down Expand Up @@ -3272,11 +3273,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(messages.ErrorCodes.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,
messages.ErrorCodes.INCOMPATIBLE_TYPES_IN_YIELD,
'actual type', 'expected type')
return self.chk.get_generator_receive_type(return_type, False)

Expand All @@ -3287,9 +3288,9 @@ 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, messages.ErrorCodes.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: messages.ErrorCodes) -> Type:
"""Check the argument to `await` and extract the type of value.

Also used by `async for` and `async with`.
Expand Down Expand Up @@ -3333,15 +3334,15 @@ def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = Fals
iter_type = AnyType(TypeOfAny.from_error)
else:
iter_type = self.check_awaitable_expr(subexpr_type, e,
messages.INCOMPATIBLE_TYPES_IN_YIELD_FROM)
messages.ErrorCodes.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.
expected_item_type = self.chk.get_generator_yield_type(return_type, False)
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,
messages.ErrorCodes.INCOMPATIBLE_TYPES_IN_YIELD_FROM,
'actual type', 'expected type')

# Determine the type of the entire yield from expression.
Expand Down
Loading