-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Migrate core to use ErrorMessage class #12004
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
Changes from all commits
5da91cb
7eeefbe
8020024
2110701
ecc552c
88f2626
3752a6d
e3e2845
c5215ca
e4ead79
afd8f8d
a9d00e6
bbaa519
ea4fe57
cf4a8bd
ab6c756
a396e4d
a106d5c
0a42056
e2b9059
0039d3d
07dadfe
661b7e7
f2d0b3b
0fa39a0
6ea2f65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ | |
) | ||
from mypy import defaults | ||
from mypy import message_registry, errorcodes as codes | ||
from mypy.message_registry import ErrorMessage | ||
from mypy.errors import Errors | ||
from mypy.options import Options | ||
from mypy.reachability import infer_reachability_of_if_statement, mark_block_unreachable | ||
|
@@ -156,10 +157,6 @@ def ast3_parse(source: Union[str, bytes], filename: str, mode: str, | |
MISSING_FALLBACK: Final = FakeInfo("fallback can't be filled out until semanal") | ||
_dummy_fallback: Final = Instance(MISSING_FALLBACK, [], -1) | ||
|
||
TYPE_COMMENT_SYNTAX_ERROR: Final = "syntax error in type comment" | ||
|
||
INVALID_TYPE_IGNORE: Final = 'Invalid "type: ignore" comment' | ||
|
||
TYPE_IGNORE_PATTERN: Final = re.compile(r'[^#]*#\s*type:\s*ignore\s*(.*)') | ||
|
||
|
||
|
@@ -250,8 +247,8 @@ def parse_type_comment(type_comment: str, | |
except SyntaxError: | ||
if errors is not None: | ||
stripped_type = type_comment.split("#", 2)[0].strip() | ||
err_msg = '{} "{}"'.format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type) | ||
errors.report(line, column, err_msg, blocker=True, code=codes.SYNTAX) | ||
err_msg = message_registry.TYPE_COMMENT_SYNTAX_ERROR_VALUE.format(stripped_type) | ||
errors.report(line, column, err_msg.value, blocker=True, code=err_msg.code) | ||
return None, None | ||
else: | ||
raise | ||
|
@@ -263,7 +260,8 @@ def parse_type_comment(type_comment: str, | |
ignored: Optional[List[str]] = parse_type_ignore_tag(tag) | ||
if ignored is None: | ||
if errors is not None: | ||
errors.report(line, column, INVALID_TYPE_IGNORE, code=codes.SYNTAX) | ||
err_msg = message_registry.INVALID_TYPE_IGNORE | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we refactor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is doable, but from what I've seen that's not necessary. I could do that in a separate PR if it seems like a good to have. |
||
errors.report(line, column, err_msg.value, code=err_msg.code) | ||
else: | ||
raise SyntaxError | ||
else: | ||
|
@@ -341,21 +339,20 @@ def note(self, msg: str, line: int, column: int) -> None: | |
self.errors.report(line, column, msg, severity='note', code=codes.SYNTAX) | ||
|
||
def fail(self, | ||
msg: str, | ||
msg: ErrorMessage, | ||
line: int, | ||
column: int, | ||
blocker: bool = True, | ||
code: codes.ErrorCode = codes.SYNTAX) -> None: | ||
if blocker or not self.options.ignore_errors: | ||
self.errors.report(line, column, msg, blocker=blocker, code=code) | ||
self.errors.report(line, column, msg.value, blocker=blocker, code=msg.code) | ||
|
||
def fail_merge_overload(self, node: IfStmt) -> None: | ||
self.fail( | ||
"Condition can't be inferred, unable to merge overloads", | ||
message_registry.FAILED_TO_MERGE_OVERLOADS, | ||
line=node.line, | ||
column=node.column, | ||
blocker=False, | ||
code=codes.MISC, | ||
) | ||
|
||
def visit(self, node: Optional[AST]) -> Any: | ||
|
@@ -760,7 +757,7 @@ def visit_Module(self, mod: ast3.Module) -> MypyFile: | |
if parsed is not None: | ||
self.type_ignores[ti.lineno] = parsed | ||
else: | ||
self.fail(INVALID_TYPE_IGNORE, ti.lineno, -1) | ||
self.fail(message_registry.INVALID_TYPE_IGNORE, ti.lineno, -1) | ||
body = self.fix_function_overloads(self.translate_stmt_list(mod.body, ismodule=True)) | ||
return MypyFile(body, | ||
self.imports, | ||
|
@@ -833,7 +830,7 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], | |
arg_types.insert(0, AnyType(TypeOfAny.special_form)) | ||
except SyntaxError: | ||
stripped_type = n.type_comment.split("#", 2)[0].strip() | ||
err_msg = '{} "{}"'.format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type) | ||
err_msg = message_registry.TYPE_COMMENT_SYNTAX_ERROR_VALUE.format(stripped_type) | ||
self.fail(err_msg, lineno, n.col_offset) | ||
if n.type_comment and n.type_comment[0] not in ["(", "#"]: | ||
self.note('Suggestion: wrap argument types in parentheses', | ||
|
@@ -852,13 +849,12 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], | |
if any(arg_types) or return_type: | ||
if len(arg_types) != 1 and any(isinstance(t, EllipsisType) | ||
for t in arg_types): | ||
self.fail("Ellipses cannot accompany other argument types " | ||
"in function type signature", lineno, n.col_offset) | ||
self.fail(message_registry.ELLIPSIS_WITH_OTHER_TYPEARGS, lineno, n.col_offset) | ||
elif len(arg_types) > len(arg_kinds): | ||
self.fail('Type signature has too many arguments', lineno, n.col_offset, | ||
self.fail(message_registry.TYPE_SIGNATURE_TOO_MANY_ARGS, lineno, n.col_offset, | ||
blocker=False) | ||
elif len(arg_types) < len(arg_kinds): | ||
self.fail('Type signature has too few arguments', lineno, n.col_offset, | ||
self.fail(message_registry.TYPE_SIGNATURE_TOO_FEW_ARGS, lineno, n.col_offset, | ||
blocker=False) | ||
else: | ||
func_type = CallableType([a if a is not None else | ||
|
@@ -986,7 +982,7 @@ def make_argument(self, arg: ast3.arg, default: Optional[ast3.expr], kind: ArgKi | |
|
||
return Argument(Var(arg.arg), arg_type, self.visit(default), kind, pos_only) | ||
|
||
def fail_arg(self, msg: str, arg: ast3.arg) -> None: | ||
def fail_arg(self, msg: ErrorMessage, arg: ast3.arg) -> None: | ||
self.fail(msg, arg.lineno, arg.col_offset) | ||
|
||
# ClassDef(identifier name, | ||
|
@@ -1687,9 +1683,9 @@ def parent(self) -> Optional[AST]: | |
return None | ||
return self.node_stack[-2] | ||
|
||
def fail(self, msg: str, line: int, column: int) -> None: | ||
def fail(self, msg: ErrorMessage, line: int, column: int) -> None: | ||
if self.errors: | ||
self.errors.report(line, column, msg, blocker=True, code=codes.SYNTAX) | ||
self.errors.report(line, column, msg.value, blocker=True, code=msg.code) | ||
|
||
def note(self, msg: str, line: int, column: int) -> None: | ||
if self.errors: | ||
|
@@ -1720,7 +1716,7 @@ def visit_Call(self, e: Call) -> Type: | |
note = "Suggestion: use {0}[...] instead of {0}(...)".format(constructor) | ||
return self.invalid_type(e, note=note) | ||
if not constructor: | ||
self.fail("Expected arg constructor name", e.lineno, e.col_offset) | ||
self.fail(message_registry.ARG_CONSTRUCTOR_NAME_EXPECTED, e.lineno, e.col_offset) | ||
|
||
name: Optional[str] = None | ||
default_type = AnyType(TypeOfAny.special_form) | ||
|
@@ -1733,25 +1729,25 @@ def visit_Call(self, e: Call) -> Type: | |
elif i == 1: | ||
name = self._extract_argument_name(arg) | ||
else: | ||
self.fail("Too many arguments for argument constructor", | ||
self.fail(message_registry.ARG_CONSTRUCTOR_TOO_MANY_ARGS, | ||
f.lineno, f.col_offset) | ||
for k in e.keywords: | ||
value = k.value | ||
if k.arg == "name": | ||
if name is not None: | ||
self.fail('"{}" gets multiple values for keyword argument "name"'.format( | ||
self.fail(message_registry.MULTIPLE_VALUES_FOR_NAME_KWARG.format( | ||
constructor), f.lineno, f.col_offset) | ||
name = self._extract_argument_name(value) | ||
elif k.arg == "type": | ||
if typ is not default_type: | ||
self.fail('"{}" gets multiple values for keyword argument "type"'.format( | ||
self.fail(message_registry.MULTIPLE_VALUES_FOR_TYPE_KWARG.format( | ||
constructor), f.lineno, f.col_offset) | ||
converted = self.visit(value) | ||
assert converted is not None | ||
typ = converted | ||
else: | ||
self.fail( | ||
'Unexpected argument "{}" for argument constructor'.format(k.arg), | ||
message_registry.ARG_CONSTRUCTOR_UNEXPECTED_ARG.format(k.arg), | ||
value.lineno, value.col_offset) | ||
return CallableArgument(typ, name, constructor, e.lineno, e.col_offset) | ||
|
||
|
@@ -1763,7 +1759,7 @@ def _extract_argument_name(self, n: ast3.expr) -> Optional[str]: | |
return n.s.strip() | ||
elif isinstance(n, NameConstant) and str(n.value) == 'None': | ||
return None | ||
self.fail('Expected string literal for argument name, got {}'.format( | ||
self.fail(message_registry.ARG_NAME_EXPECTED_STRING_LITERAL.format( | ||
type(n).__name__), self.line, 0) | ||
return None | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why some consts are
: Final = ErrorCode()
and some are: Final[ErrorCode] = ErrorCode()
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mypyc bug. It doesn't recognize just
Final
for some reason, it has to be told. The bug only shows up when that error code is used inside theErrorMessage
tuple, so to keep a minimal diff I'm only migrating the error codes that have been used in these PRs.Eventually as I make more PRs they will all become
Final[ErrorCode]