Skip to content

Migrate remaining failure messages to mypy.messages (part1: mypy.checker) #6118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 15 additions & 23 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
# valid overloads.
return None
if len(defn.items) == 1:
self.fail('Single overload definition, multiple required', defn)
self.fail(messages.MULTIPLE_OVERLOADS_REQUIRED, defn)

if defn.is_property:
# HACK: Infer the type of the property.
Expand Down Expand Up @@ -882,16 +882,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 = ("Invalid type for self, or extra argument type "
"in function annotation")
msg = messages.INVALID_SELF_TYPE_OR_EXTRA_ARG
note = '(Hint: typically annotations omit the type for self)'
else:
msg = ("The erased type of self '{}' "
"is not a supertype of its class '{}'"
).format(erased, ref_type)
msg = messages.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
erased, ref_type)
else:
msg = ("Self argument missing for a non-static method "
"(or an invalid type for self)")
msg = messages.MISSING_OR_INVALID_SELF_TYPE
self.fail(msg, defn)
if note:
self.note(note, defn)
Expand Down Expand Up @@ -1221,7 +1218,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('__getattribute__ is not valid at the module level', context)
self.msg.fail(messages.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
Expand Down Expand Up @@ -1527,7 +1524,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('Cannot inherit from final class "{}"'.format(base.name()), defn)
self.fail(messages.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()
Expand Down Expand Up @@ -1720,7 +1717,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("Final name declared in class body cannot depend on type variables", s)
self.fail(messages.DEPENDENT_FINAL_IN_CLASS_BODY, s)

def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type: bool = True,
new_syntax: bool = False) -> None:
Expand Down Expand Up @@ -1961,14 +1958,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('Cannot override instance variable '
'(previously declared on base class "%s") '
'with class variable' % base.name(), node)
self.fail(messages.CANNOT_OVERRIDE_INSTANCE_VAR.format(base.name()), node)
return False
elif not node.is_classvar and base_node.is_classvar:
self.fail('Cannot override class variable '
'(previously declared on base class "%s") '
'with instance variable' % base.name(), node)
self.fail(messages.CANNOT_OVERRIDE_CLASS_VAR.format(base.name()), node)
return False
return True

Expand Down Expand Up @@ -2527,7 +2520,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("{}.__set__ is not callable".format(attribute_type), context)
self.msg.fail(messages.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'))
Expand All @@ -2549,9 +2542,8 @@ def check_member_assignment(self, instance_type: Type, attribute_type: Type,
dunder_set_type, [TempNode(instance_type), TempNode(AnyType(TypeOfAny.special_form))],
[nodes.ARG_POS, nodes.ARG_POS], context)

if not isinstance(inferred_dunder_set_type, CallableType):
self.fail("__set__ is not callable", context)
return AnyType(TypeOfAny.from_error), get_type, True
# should be handled by get_method above
assert isinstance(inferred_dunder_set_type, CallableType)

if len(inferred_dunder_set_type.arg_types) < 2:
# A message already will have been recorded in check_call
Expand Down Expand Up @@ -2660,7 +2652,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
allow_none_return=allow_none_func_call)

if defn.is_async_generator:
self.fail("'return' with value in async generator is not allowed", s)
self.fail(messages.RETURN_IN_ASYNC_GENERATOR, s)
return
# Returning a value of type Any is always fine.
if isinstance(typ, AnyType):
Expand Down Expand Up @@ -3022,7 +3014,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('Single overload definition, multiple required', e)
self.fail(messages.MULTIPLE_OVERLOADS_REQUIRED, e)
continue
dec = self.expr_checker.accept(d)
temp = self.temp_node(sig)
Expand Down
29 changes: 13 additions & 16 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,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('Only @runtime protocols can be used with'
' instance and class checks', e)
self.chk.fail(messages.RUNTIME_PROTOCOL_EXPECTED, e)

def check_protocol_issubclass(self, e: CallExpr) -> None:
for expr in mypy.checker.flatten(e.args[1]):
Expand Down Expand Up @@ -745,7 +744,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('Cannot instantiate protocol class "{}"'
self.chk.fail(messages.CANNOT_INSTANTIATE_PROTOCOL
.format(callee.type_object().name()), context)

formal_to_actual = map_actuals_to_formals(
Expand Down Expand Up @@ -2852,15 +2851,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('Varargs not supported with "super"', e)
self.chk.fail(messages.SUPER_VARARGS_NOT_SUPPORTED, e)
elif e.call.args and set(e.call.arg_kinds) != {ARG_POS}:
self.chk.fail('"super" only accepts positional arguments', e)
self.chk.fail(messages.SUPER_POSITIONAL_ARGS_REQUIRED, e)
elif len(e.call.args) == 1:
self.chk.fail('"super" with a single argument not supported', e)
self.chk.fail(messages.SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED, e)
elif len(e.call.args) > 2:
self.chk.fail('Too many arguments for "super"', e)
self.chk.fail(messages.TOO_MANY_ARGS_FOR_SUPER, e)
elif self.chk.options.python_version[0] == 2 and len(e.call.args) == 0:
self.chk.fail('Too few arguments for "super"', e)
self.chk.fail(messages.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 @@ -2876,7 +2875,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('Unsupported argument 1 for "super"', e)
self.chk.fail(messages.UNSUPPORTED_ARG_1_FOR_SUPER, e)
return
type_info = item.type
elif isinstance(type_obj_type, AnyType):
Expand All @@ -2892,19 +2891,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_ARGUMENT_2_FOR_SUPER, e)
self.chk.fail(messages.UNSUPPORTED_ARG_2_FOR_SUPER, e)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this constant because I wanted to standardize all of them on the shorthand "ARG" for argument, since the constants can get fairly lengthy.

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('Argument 2 for "super" not an instance of argument 1', e)
self.chk.fail(messages.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_ARGUMENT_2_FOR_SUPER, e)
self.chk.fail(messages.UNSUPPORTED_ARG_2_FOR_SUPER, e)

def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type:
"""Type check a super expression."""
Expand All @@ -2923,17 +2922,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('super() outside of a method is not supported', e)
self.chk.fail(messages.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(
'super() requires one or more positional arguments in '
'enclosing function', e)
self.chk.fail(messages.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 Down
10 changes: 5 additions & 5 deletions mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ def analyze_descriptor_access(instance_type: Type,
dunder_get = descriptor_type.type.get_method('__get__')

if dunder_get is None:
msg.fail("{}.__get__ is not callable".format(descriptor_type), context)
msg.fail(messages.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context)
return AnyType(TypeOfAny.from_error)

function = function_type(dunder_get, builtin_type('builtins.function'))
Expand All @@ -427,7 +427,7 @@ def analyze_descriptor_access(instance_type: Type,
return inferred_dunder_get_type

if not isinstance(inferred_dunder_get_type, CallableType):
msg.fail("{}.__get__ is not callable".format(descriptor_type), context)
msg.fail(messages.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context)
return AnyType(TypeOfAny.from_error)

return inferred_dunder_get_type.ret_type
Expand Down Expand Up @@ -586,8 +586,8 @@ def analyze_class_attribute_access(itype: Instance,
# 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('Cannot access final instance '
'attribute "{}" on class object'.format(node.node.name()), mx.context)
mx.msg.fail(messages.CANNOT_ACCESS_FINAL_INSTANCE_ATTR
.format(node.node.name()), mx.context)

# An assignment to final attribute on class object is also always an error,
# independently of types.
Expand Down Expand Up @@ -617,7 +617,7 @@ def analyze_class_attribute_access(itype: Instance,
return AnyType(TypeOfAny.special_form)

if isinstance(node.node, TypeVarExpr):
mx.msg.fail('Type variable "{}.{}" cannot be used as an expression'.format(
mx.msg.fail(messages.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format(
itype.type.name(), name), mx.context)
return AnyType(TypeOfAny.from_error)

Expand Down
61 changes: 57 additions & 4 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
if MYPY:
from typing_extensions import Final

# Constants that represent simple type checker error message, i.e. messages
# that do not have any parameters.
# Type checker error message constants --

NO_RETURN_VALUE_EXPECTED = 'No return value expected' # type: Final
MISSING_RETURN_STATEMENT = 'Missing return statement' # type: Final
Expand All @@ -45,6 +44,7 @@
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
Expand Down Expand Up @@ -80,6 +80,7 @@
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
Expand All @@ -102,13 +103,65 @@
'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
'Implicit generic "Any". Use "{}" and specify generic parameters' # type: Final

# TypeVar
INCOMPATIBLE_TYPEVAR_VALUE = 'Value of type variable "{}" of {} cannot be {}' # type: Final
UNSUPPORTED_ARGUMENT_2_FOR_SUPER = 'Unsupported argument 2 for "super"' # 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",
Expand Down
6 changes: 3 additions & 3 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4193,9 +4193,9 @@ TTA = TypeVar('TTA', bound='Type[A]')
TM = TypeVar('TM', bound='M')

class M(type):
def g1(cls: 'Type[A]') -> A: pass # E: The erased type of self 'Type[__main__.A]' is not a supertype of its class '__main__.M'
def g2(cls: Type[TA]) -> TA: pass # E: The erased type of self 'Type[__main__.A]' is not a supertype of its class '__main__.M'
def g3(cls: TTA) -> TTA: pass # E: The erased type of self 'Type[__main__.A]' is not a supertype of its class '__main__.M'
def g1(cls: 'Type[A]') -> A: pass # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "__main__.M"
def g2(cls: Type[TA]) -> TA: pass # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "__main__.M"
def g3(cls: TTA) -> TTA: pass # E: The erased type of self "Type[__main__.A]" is not a supertype of its class "__main__.M"
def g4(cls: TM) -> TM: pass
m: M

Expand Down
Loading