Skip to content

Commit

Permalink
The final patch to wrap everything up
Browse files Browse the repository at this point in the history
  • Loading branch information
tushar-deepsource committed Jan 20, 2022
1 parent 826cc86 commit e178323
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 85 deletions.
15 changes: 3 additions & 12 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1897,12 +1897,7 @@ def check_init_subclass(self, defn: ClassDef) -> None:
def check_final_enum(self, defn: ClassDef, base: TypeInfo) -> None:
for sym in base.names.values():
if self.is_final_enum_value(sym):
self.fail(
'Cannot extend enum with existing members: "{}"'.format(
base.name,
),
defn,
)
self.fail(message_registry.ENUM_EXTEND_EXISTING_MEMBERS.format(base.name), defn)
break

def is_final_enum_value(self, sym: SymbolTableNode) -> bool:
Expand Down Expand Up @@ -5342,13 +5337,9 @@ 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: Union[str, ErrorMessage], context: Context, *,
code: Optional[ErrorCode] = None) -> None:
def fail(self, msg: ErrorMessage, context: Context) -> 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)
self.msg.fail(msg, context)

def note(self,
msg: str,
Expand Down
2 changes: 1 addition & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4094,7 +4094,7 @@ def visit_await_expr(self, e: AwaitExpr) -> Type:
return self.check_awaitable_expr(actual_type, e,
message_registry.INCOMPATIBLE_TYPES_IN_AWAIT)

def check_awaitable_expr(self, t: Type, ctx: Context, msg: Union[str, ErrorMessage]) -> Type:
def check_awaitable_expr(self, t: Type, ctx: Context, msg: ErrorMessage) -> Type:
"""Check the argument to `await` and extract the type of value.
Also used by `async for` and `async with`.
Expand Down
2 changes: 1 addition & 1 deletion mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ 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(message_registry.CANNOT_ASSIGN_TO_TYPE.value, 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.
Expand Down
4 changes: 3 additions & 1 deletion mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ def __str__(self) -> str:
TYPE_ARG: Final[ErrorCode] = ErrorCode(
"type-arg", "Check that generic type arguments are present", "General"
)
TYPE_VAR: Final = ErrorCode("type-var", "Check that type variable values are valid", "General")
TYPE_VAR: Final[ErrorCode] = ErrorCode(
"type-var", "Check that type variable values are valid", "General"
)
UNION_ATTR: Final[ErrorCode] = ErrorCode(
"union-attr", "Check that attribute exists in each item of a union", "General"
)
Expand Down
74 changes: 45 additions & 29 deletions mypy/message_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
return ErrorMessage(self.value.format(*args, **kwargs), code=self.code)


# Strings
INCOMPATIBLE_TYPES: Final = "Incompatible types"
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment"

# Invalid types
INVALID_TYPE_RAW_ENUM_VALUE: Final = ErrorMessage(
"Invalid type: try using Literal[{}.{}] instead?"
Expand Down Expand Up @@ -51,17 +55,15 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
" its third type parameter in Python 2"
)
YIELD_VALUE_EXPECTED: Final = ErrorMessage("Yield value expected")
INCOMPATIBLE_TYPES: Final = "Incompatible types"
INCOMPATIBLE_TYPES_IN_ASSIGNMENT: Final = "Incompatible types in assignment"
INCOMPATIBLE_TYPES_IN_AWAIT: Final = ErrorMessage('Incompatible types in "await"')
INCOMPATIBLE_REDEFINITION: Final = ErrorMessage("Incompatible redefinition")
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = (
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER: Final = ErrorMessage(
'Incompatible types in "async with" for "__aenter__"'
)
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT: Final = (
INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT: Final = ErrorMessage(
'Incompatible types in "async with" for "__aexit__"'
)
INCOMPATIBLE_TYPES_IN_ASYNC_FOR: Final = 'Incompatible types in "async for"'
INCOMPATIBLE_TYPES_IN_ASYNC_FOR: Final = ErrorMessage('Incompatible types in "async for"')

INCOMPATIBLE_TYPES_IN_YIELD: Final = ErrorMessage('Incompatible types in "yield"')
INCOMPATIBLE_TYPES_IN_YIELD_FROM: Final = ErrorMessage('Incompatible types in "yield from"')
Expand All @@ -72,7 +74,7 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
TUPLE_INDEX_OUT_OF_RANGE: Final = ErrorMessage("Tuple index out of range")
INVALID_SLICE_INDEX: Final = ErrorMessage("Slice index must be an integer or None")
CANNOT_INFER_LAMBDA_TYPE: Final = ErrorMessage("Cannot infer type of lambda")
CANNOT_ACCESS_INIT: Final = 'Cannot access "__init__" directly'
CANNOT_ACCESS_INIT: Final = ErrorMessage('Cannot access "__init__" directly')
NON_INSTANCE_NEW_TYPE: Final = ErrorMessage('"__new__" must return a class instance (got {})')
INVALID_NEW_TYPE: Final = ErrorMessage('Incompatible return type for "__new__"')
BAD_CONSTRUCTOR_TYPE: Final = ErrorMessage("Unsupported decorated constructor type")
Expand Down Expand Up @@ -118,7 +120,7 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
MALFORMED_ASSERT: Final = ErrorMessage("Assertion is always true, perhaps remove parentheses?")
DUPLICATE_TYPE_SIGNATURES: Final = ErrorMessage("Function has duplicate type signatures")
DESCRIPTOR_SET_NOT_CALLABLE: Final = ErrorMessage("{}.__set__ is not callable")
DESCRIPTOR_GET_NOT_CALLABLE: Final = "{}.__get__ is not callable"
DESCRIPTOR_GET_NOT_CALLABLE: Final = ErrorMessage("{}.__get__ is not callable")
MODULE_LEVEL_GETATTRIBUTE: Final = ErrorMessage(
"__getattribute__ is not valid at the module level"
)
Expand All @@ -140,29 +142,43 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
code=codes.TRUTHY_BOOL,
)
NOT_CALLABLE: Final = '{} not callable'
PYTHON2_PRINT_FILE_TYPE: Final = (
PYTHON2_PRINT_FILE_TYPE: Final = ErrorMessage(
'Argument "file" to "print" has incompatible type "{}"; expected "{}"'
)
ENUM_EXTEND_EXISTING_MEMBERS: Final = ErrorMessage(
'Cannot extend enum with existing members: "{}"'
)

# Generic
GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = (
GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = ErrorMessage(
"Access to generic instance variables via class is ambiguous"
)
GENERIC_CLASS_VAR_ACCESS: Final = "Access to generic class variables is ambiguous"
GENERIC_CLASS_VAR_ACCESS: Final = ErrorMessage("Access to generic class variables is ambiguous")
BARE_GENERIC: Final = ErrorMessage("Missing type parameters for generic type {}", codes.TYPE_ARG)
IMPLICIT_GENERIC_ANY_BUILTIN: Final = ErrorMessage(
'Implicit generic "Any". Use "{}" and specify generic parameters', codes.TYPE_ARG
)

# TypeVar
INCOMPATIBLE_TYPEVAR_VALUE: Final = 'Value of type variable "{}" of {} cannot be {}'
CANNOT_USE_TYPEVAR_AS_EXPRESSION: Final = 'Type variable "{}.{}" cannot be used as an expression'
INVALID_TYPEVAR_AS_TYPEARG: Final = 'Type variable "{}" not valid as type argument value for "{}"'
INVALID_TYPEVAR_ARG_BOUND: Final = 'Type argument {} of "{}" must be a subtype of {}'
INVALID_TYPEVAR_ARG_VALUE: Final = 'Invalid type argument value for "{}"'
INCOMPATIBLE_TYPEVAR_VALUE: Final = ErrorMessage(
'Value of type variable "{}" of {} cannot be {}', codes.TYPE_VAR
)
CANNOT_USE_TYPEVAR_AS_EXPRESSION: Final = ErrorMessage(
'Type variable "{}.{}" cannot be used as an expression'
)
INVALID_TYPEVAR_AS_TYPEARG: Final = ErrorMessage(
'Type variable "{}" not valid as type argument value for "{}"', codes.TYPE_VAR
)
INVALID_TYPEVAR_ARG_BOUND: Final = ErrorMessage(
'Type argument {} of "{}" must be a subtype of {}', codes.TYPE_VAR
)
INVALID_TYPEVAR_ARG_VALUE: Final = ErrorMessage(
'Invalid type argument value for "{}"', codes.TYPE_VAR
)
TYPEVAR_VARIANCE_DEF: Final = ErrorMessage('TypeVar "{}" may only be a literal bool')
TYPEVAR_BOUND_MUST_BE_TYPE: Final = ErrorMessage('TypeVar "bound" must be a type')
TYPEVAR_UNEXPECTED_ARGUMENT: Final = ErrorMessage('Unexpected argument to "TypeVar()"')
PARAMSPEC_INVALID_LOCATION: Final = ErrorMessage('Invalid location for ParamSpec "{}"')

# FastParse
TYPE_COMMENT_SYNTAX_ERROR_VALUE: Final = ErrorMessage(
Expand Down Expand Up @@ -1031,7 +1047,7 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
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_ATTR: Final = ErrorMessage(
'Cannot access final instance attribute "{}" on class object'
)
CANNOT_MAKE_DELETABLE_FINAL: Final = ErrorMessage("Deletable attribute cannot be final")
Expand Down Expand Up @@ -1062,19 +1078,23 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
TYPE_GUARD_POS_ARG_REQUIRED: Final = ErrorMessage("Type guard requires positional argument")

# Match Statement
MISSING_MATCH_ARGS: Final = 'Class "{}" doesn\'t define "__match_args__"'
OR_PATTERN_ALTERNATIVE_NAMES: Final = "Alternative patterns bind different names"
CLASS_PATTERN_GENERIC_TYPE_ALIAS: Final = (
MISSING_MATCH_ARGS: Final = ErrorMessage('Class "{}" doesn\'t define "__match_args__"')
OR_PATTERN_ALTERNATIVE_NAMES: Final = ErrorMessage("Alternative patterns bind different names")
CLASS_PATTERN_GENERIC_TYPE_ALIAS: Final = ErrorMessage(
"Class pattern class must not be a type alias with type parameters"
)
CLASS_PATTERN_TYPE_REQUIRED: Final = 'Expected type in class pattern; found "{}"'
CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS: Final = "Too many positional patterns for class pattern"
CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL: Final = (
CLASS_PATTERN_TYPE_REQUIRED: Final = ErrorMessage('Expected type in class pattern; found "{}"')
CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS: Final = ErrorMessage(
"Too many positional patterns for class pattern"
)
CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL: Final = ErrorMessage(
'Keyword "{}" already matches a positional pattern'
)
CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = 'Duplicate keyword pattern "{}"'
CLASS_PATTERN_UNKNOWN_KEYWORD: Final = 'Class "{}" has no attribute "{}"'
MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = 'Multiple assignments to name "{}" in pattern'
CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = ErrorMessage('Duplicate keyword pattern "{}"')
CLASS_PATTERN_UNKNOWN_KEYWORD: Final = ErrorMessage('Class "{}" has no attribute "{}"')
MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = ErrorMessage(
'Multiple assignments to name "{}" in pattern'
)

# Plugin: attrs
CANNOT_DETERMINE_INIT_TYPE: Final = ErrorMessage("Cannot determine __init__ type from converter")
Expand Down Expand Up @@ -1149,7 +1169,3 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":
"Never apply isinstance() to unexpanded types; use mypy.types.get_proper_type() first"
)
REDUNDANT_GET_PROPER_TYPE: Final = ErrorMessage("Redundant call to get_proper_type()")


# test-data/type_anal_hook.py
INVALID_SIGNAL_TYPE: Final = ErrorMessage('Invalid "Signal" type (expected "Signal[[t, ...]]")')
15 changes: 4 additions & 11 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,21 +190,14 @@ def report(self,
end_line=end_line, code=code, allow_dups=allow_dups)

def fail(self,
msg: Union[str, ErrorMessage],
msg: ErrorMessage,
context: Optional[Context],
*,
code: Optional[ErrorCode] = None,
file: Optional[str] = None,
origin: Optional[Context] = None,
allow_dups: bool = False) -> None:
"""Report an error message (unless disabled)."""
# TODO(tushar): Remove `str` support after full migration
if isinstance(msg, ErrorMessage):
self.report(msg.value, context, 'error', code=msg.code, file=file,
origin=origin, allow_dups=allow_dups)
return

self.report(msg, context, 'error', code=code, file=file,
self.report(msg.value, context, 'error', code=msg.code, file=file,
origin=origin, allow_dups=allow_dups)

def note(self,
Expand Down Expand Up @@ -365,7 +358,7 @@ def has_no_attr(self,
self.fail(
message_registry.TYPEVAR_UPPER_BOUND_HAS_NO_ATTRIBUTE.format(
typ_fmt, bound_fmt, original_type_fmt, member, extra),
context, code=codes.UNION_ATTR)
context)
return AnyType(TypeOfAny.from_error)

def unsupported_operand_types(self,
Expand Down Expand Up @@ -1059,7 +1052,7 @@ def incompatible_typevar_value(self,
context: Context) -> None:
self.fail(message_registry.INCOMPATIBLE_TYPEVAR_VALUE
.format(typevar_name, callable_name(callee) or 'function', format_type(typ)),
context, code=codes.TYPE_VAR) # TODO: migrate with TypeVar messages
context)

def dangerous_comparison(self, left: Type, right: Type, kind: str, ctx: Context) -> None:
left_str = 'element' if kind == 'container' else 'left operand'
Expand Down
11 changes: 3 additions & 8 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5118,23 +5118,18 @@ def in_checked_function(self) -> bool:
# no regular functions.
return True

# TODO(tushar): remove `str` type and `code` property from here
def fail(self,
msg: Union[str, ErrorMessage],
msg: ErrorMessage,
ctx: Context,
serious: bool = False,
*,
code: Optional[ErrorCode] = None,
blocker: bool = False) -> None:
if not serious and not self.in_checked_function():
return
# In case it's a bug and we don't really have context
assert ctx is not None, msg
if isinstance(msg, ErrorMessage):
self.errors.report(ctx.get_line(), ctx.get_column(), msg.value, code=msg.code,
blocker=blocker)
return
self.errors.report(ctx.get_line(), ctx.get_column(), msg, blocker=blocker, code=code)
self.errors.report(ctx.get_line(), ctx.get_column(), msg.value, code=msg.code,
blocker=blocker)

def note(self, msg: str, ctx: Context, code: Optional[ErrorCode] = None) -> None:
if not self.in_checked_function():
Expand Down
7 changes: 3 additions & 4 deletions mypy/semanal_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from abc import abstractmethod

from typing import Optional, List, Callable, Union
from typing import Optional, List, Callable
from typing_extensions import Final
from mypy_extensions import trait

Expand Down Expand Up @@ -45,10 +45,9 @@ def lookup_fully_qualified(self, name: str) -> SymbolTableNode:
def lookup_fully_qualified_or_none(self, name: str) -> Optional[SymbolTableNode]:
raise NotImplementedError

# TODO(tushar): remove `str` type and `code` property from here
@abstractmethod
def fail(self, msg: Union[str, ErrorMessage], ctx: Context, serious: bool = False, *,
blocker: bool = False, code: Optional[ErrorCode] = None) -> None:
def fail(self, msg: ErrorMessage, ctx: Context, serious: bool = False, *,
blocker: bool = False) -> None:
raise NotImplementedError

@abstractmethod
Expand Down
21 changes: 10 additions & 11 deletions mypy/semanal_typeargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
operations, including subtype checks.
"""

from typing import List, Optional, Set
from typing import List, Set

from mypy.nodes import TypeInfo, Context, MypyFile, FuncItem, ClassDef, Block, FakeInfo
from mypy.types import (
Expand All @@ -18,9 +18,9 @@
from mypy.errors import Errors
from mypy.scope import Scope
from mypy.options import Options
from mypy.errorcodes import ErrorCode
from mypy import message_registry, errorcodes as codes
from mypy import message_registry
from mypy.messages import format_type
from mypy.message_registry import ErrorMessage


class TypeArgumentAnalyzer(MixedTraverserVisitor):
Expand Down Expand Up @@ -74,7 +74,7 @@ def visit_instance(self, t: Instance) -> None:
if isinstance(tvar, TypeVarType):
if isinstance(arg, ParamSpecType):
# TODO: Better message
self.fail(f'Invalid location for ParamSpec "{arg.name}"', t)
self.fail(message_registry.PARAMSPEC_INVALID_LOCATION.format(arg.name), t)
continue
if tvar.values:
if isinstance(arg, TypeVarType):
Expand All @@ -83,7 +83,7 @@ def visit_instance(self, t: Instance) -> None:
self.fail(
message_registry.INVALID_TYPEVAR_AS_TYPEARG.format(
arg.name, info.name),
t, code=codes.TYPE_VAR)
t)
continue
else:
arg_values = [arg]
Expand All @@ -92,7 +92,7 @@ def visit_instance(self, t: Instance) -> None:
self.fail(
message_registry.INVALID_TYPEVAR_ARG_BOUND.format(
format_type(arg), info.name, format_type(tvar.upper_bound)),
t, code=codes.TYPE_VAR)
t)
super().visit_instance(t)

def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: str,
Expand All @@ -104,15 +104,14 @@ def check_type_var_values(self, type: TypeInfo, actuals: List[Type], arg_name: s
if len(actuals) > 1 or not isinstance(actual, Instance):
self.fail(
message_registry.INVALID_TYPEVAR_ARG_VALUE.format(type.name),
context, code=codes.TYPE_VAR)
context)
else:
class_name = '"{}"'.format(type.name)
actual_type_name = '"{}"'.format(actual.type.name)
self.fail(
message_registry.INCOMPATIBLE_TYPEVAR_VALUE.format(
arg_name, class_name, actual_type_name),
context,
code=codes.TYPE_VAR)
context)

def fail(self, msg: str, context: Context, *, code: Optional[ErrorCode] = None) -> None:
self.errors.report(context.get_line(), context.get_column(), msg, code=code)
def fail(self, msg: ErrorMessage, context: Context) -> None:
self.errors.report(context.get_line(), context.get_column(), msg.value, code=msg.code)
5 changes: 2 additions & 3 deletions mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from mypy.backports import OrderedDict

from typing import (
Callable, List, Optional, Set, Tuple, Iterator, TypeVar, Iterable, Sequence, Union
Callable, List, Optional, Set, Tuple, Iterator, TypeVar, Iterable, Sequence
)
from typing_extensions import Final
from mypy_extensions import DefaultNamedArg
Expand Down Expand Up @@ -927,8 +927,7 @@ def analyze_literal_param(self, idx: int, arg: Type, ctx: Context) -> Optional[L
def analyze_type(self, t: Type) -> Type:
return t.accept(self)

# TODO(tushar): remove `str` type and `code` property from here
def fail(self, msg: Union[str, ErrorMessage], ctx: Context) -> None:
def fail(self, msg: ErrorMessage, ctx: Context) -> None:
self.fail_func(msg, ctx)

def note(self, msg: str, ctx: Context, *, code: Optional[ErrorCode] = None) -> None:
Expand Down
Loading

0 comments on commit e178323

Please sign in to comment.