From 6a8d68c61a0de2f0cbcb9a33393abf97da7517eb Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 21 Mar 2019 15:15:44 -0700 Subject: [PATCH 1/4] Turn all warnings and bare notes into errors This means that all diagnostics are errors, which maybe have some notes "attached" to them. This makes sense, since all diagnostics cause an error exit code. Fixes #6574. --- mypy/build.py | 6 +++--- mypy/checker.py | 8 ++------ mypy/checkmember.py | 1 - mypy/errors.py | 4 ++-- mypy/messages.py | 9 ++------- test-data/unit/check-fastparse.test | 6 +++--- test-data/unit/check-flags.test | 4 ++-- test-data/unit/check-incremental.test | 4 ++-- test-data/unit/check-modules.test | 4 ++-- test-data/unit/check-warnings.test | 16 ++++++++-------- test-data/unit/cmdline.test | 6 +++--- test-data/unit/daemon.test | 2 +- test-data/unit/fine-grained-modules.test | 10 +++++----- 13 files changed, 35 insertions(+), 45 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index 8f90ce545e5f..ca14ebe75d24 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -2180,7 +2180,7 @@ def generate_unused_ignore_notes(self) -> None: # those errors to avoid spuriously flagging them as unused ignores. if self.meta: self.verify_dependencies(suppressed_only=True) - self.manager.errors.generate_unused_ignore_notes(self.xpath) + self.manager.errors.generate_unused_ignore_errors(self.xpath) # Module import and diagnostic glue @@ -2376,7 +2376,7 @@ def skipping_module(manager: BuildManager, line: int, caller_state: Optional[Sta manager.errors.set_file(caller_state.xpath, caller_state.id) manager.errors.report(line, 0, "Import of '%s' ignored" % (id,), - severity='note') + severity='error') manager.errors.report(line, 0, "(Using --follow-imports=error, module not passed on command line)", severity='note', only_once=True) @@ -2392,7 +2392,7 @@ def skipping_ancestor(manager: BuildManager, id: str, path: str, ancestor_for: ' manager.errors.set_import_context([]) manager.errors.set_file(ancestor_for.xpath, ancestor_for.id) manager.errors.report(-1, -1, "Ancestor package '%s' ignored" % (id,), - severity='note', only_once=True) + severity='error', only_once=True) manager.errors.report(-1, -1, "(Using --follow-imports=error, submodule passed on command line)", severity='note', only_once=True) diff --git a/mypy/checker.py b/mypy/checker.py index 83dc2ead9035..ea69176b5f87 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -951,7 +951,7 @@ 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(message_registry.INVALID_IMPLICIT_RETURN, defn) + self.msg.fail(message_registry.INVALID_IMPLICIT_RETURN, defn) else: self.msg.fail(message_registry.MISSING_RETURN_STATEMENT, defn) @@ -2793,7 +2793,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(message_registry.MALFORMED_ASSERT, s) + self.fail(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) @@ -3747,10 +3747,6 @@ def fail(self, msg: str, context: Context) -> None: """Produce an error message.""" self.msg.fail(msg, context) - def warn(self, msg: str, context: Context) -> None: - """Produce a warning message.""" - self.msg.warn(msg, context) - def note(self, msg: str, context: Context, offset: int = 0) -> None: """Produce a note.""" self.msg.note(msg, context, offset=offset) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 2117194e7fba..887c4fd94a18 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -328,7 +328,6 @@ def analyze_member_var_access(name: str, # independently of types. if mx.is_lvalue and not mx.chk.get_final_context(): check_final_member(name, info, mx.msg, mx.context) - return analyze_var(name, v, itype, info, mx, implicit=implicit) elif isinstance(v, FuncDef): assert False, "Did not expect a function" diff --git a/mypy/errors.py b/mypy/errors.py index 0053e3ec08c4..19f8c5632dc4 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -299,13 +299,13 @@ def clear_errors_in_targets(self, path: str, targets: Set[str]) -> None: self.only_once_messages.remove(info.message) self.error_info_map[path] = new_errors - def generate_unused_ignore_notes(self, file: str) -> None: + def generate_unused_ignore_errors(self, file: str) -> None: ignored_lines = self.ignored_lines[file] if not self.is_typeshed_file(file) and file not in self.ignored_files: for line in ignored_lines - self.used_ignored_lines[file]: # Don't use report since add_error_info will ignore the error! info = ErrorInfo(self.import_context(), file, self.current_module(), None, - None, line, -1, 'note', "unused 'type: ignore' comment", + None, line, -1, 'error', "unused 'type: ignore' comment", False, False) self._add_error_info(file, info) diff --git a/mypy/messages.py b/mypy/messages.py index 80c5eaa665ec..425c6aad5bf7 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -135,11 +135,6 @@ def note_multiline(self, messages: str, context: Context, file: Optional[str] = self.report(msg, context, 'note', file=file, origin=origin, offset=offset) - def warn(self, msg: str, context: Context, file: Optional[str] = None, - origin: Optional[Context] = None) -> None: - """Report a warning message (unless disabled).""" - self.report(msg, context, 'warning', file=file, origin=origin) - def quote_type_string(self, type_string: str) -> str: """Quotes a type representation for use in messages.""" no_quote_regex = r'^<(tuple|union): \d+ items>$' @@ -1065,7 +1060,7 @@ def unsupported_type_type(self, item: Type, context: Context) -> None: self.fail('Unsupported type Type[{}]'.format(self.format(item)), context) def redundant_cast(self, typ: Type, context: Context) -> None: - self.note('Redundant cast to {}'.format(self.format(typ)), context) + self.fail('Redundant cast to {}'.format(self.format(typ)), context) def unimported_type_becomes_any(self, prefix: str, typ: Type, ctx: Context) -> None: self.fail("{} becomes {} due to an unfollowed import".format(prefix, self.format(typ)), @@ -1156,7 +1151,7 @@ def disallowed_any_type(self, typ: Type, context: Context) -> None: def incorrectly_returning_any(self, typ: Type, context: Context) -> None: message = 'Returning Any from function declared to return {}'.format( self.format(typ)) - self.warn(message, context) + self.fail(message, context) def untyped_decorated_function(self, typ: Type, context: Context) -> None: if isinstance(typ, AnyType): diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test index 46e2fe6835ce..6acdbdbf65e1 100644 --- a/test-data/unit/check-fastparse.test +++ b/test-data/unit/check-fastparse.test @@ -319,10 +319,10 @@ def g(): # E: Type signature has too many arguments [case testFastParseMalformedAssert] assert 1, 2 -assert (1, 2) # W: Assertion is always true, perhaps remove parentheses? -assert (1, 2), 3 # W: Assertion is always true, perhaps remove parentheses? +assert (1, 2) # E: Assertion is always true, perhaps remove parentheses? +assert (1, 2), 3 # E: Assertion is always true, perhaps remove parentheses? assert () -assert (1,) # W: Assertion is always true, perhaps remove parentheses? +assert (1,) # E: Assertion is always true, perhaps remove parentheses? [case testFastParseAssertMessage] diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 4061ce976caa..5e186bb940b0 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -286,7 +286,7 @@ def f() -> NoReturn: # flags: --warn-no-return from mypy_extensions import NoReturn -def f() -> NoReturn: # N: Implicit return in function which does not return +def f() -> NoReturn: # E: Implicit return in function which does not return non_trivial_function = 1 [builtins fixtures/dict.pyi] @@ -432,7 +432,7 @@ x + "" [file mod.py] deliberate syntax error [out] -main:2: note: Import of 'mod' ignored +main:2: error: Import of 'mod' ignored main:2: note: (Using --follow-imports=error, module not passed on command line) [case testIgnoreMissingImportsFalse] diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index fe8973d4f9ba..b5d1db7b9194 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -1783,10 +1783,10 @@ import a [file a.py.2] // [out1] -main:2: note: Import of 'a' ignored +main:2: error: Import of 'a' ignored main:2: note: (Using --follow-imports=error, module not passed on command line) [out2] -main:2: note: Import of 'a' ignored +main:2: error: Import of 'a' ignored main:2: note: (Using --follow-imports=error, module not passed on command line) [case testIncrementalFollowImportsVariable] diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 170cbf5b64de..d0356fa58878 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -992,7 +992,7 @@ import mod [file mod.py] [builtins fixtures/module.pyi] [out] -tmp/main.py:1: note: Import of 'mod' ignored +tmp/main.py:1: error: Import of 'mod' ignored tmp/main.py:1: note: (Using --follow-imports=error, module not passed on command line) [case testAncestorSuppressedWhileAlmostSilent] @@ -1002,7 +1002,7 @@ tmp/main.py:1: note: (Using --follow-imports=error, module not passed on command [file foo/__init__.py] [builtins fixtures/module.pyi] [out] -tmp/foo/bar.py: note: Ancestor package 'foo' ignored +tmp/foo/bar.py: error: Ancestor package 'foo' ignored tmp/foo/bar.py: note: (Using --follow-imports=error, submodule passed on command line) [case testStubImportNonStubWhileSilent] diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test index c3c8a824846b..99b611529980 100644 --- a/test-data/unit/check-warnings.test +++ b/test-data/unit/check-warnings.test @@ -10,7 +10,7 @@ a = 1 b = cast(str, a) c = cast(int, a) [out] -main:5: note: Redundant cast to "int" +main:5: error: Redundant cast to "int" [case testRedundantCastWithIsinstance] # flags: --warn-redundant-casts @@ -20,7 +20,7 @@ if isinstance(x, str): cast(str, x) [builtins fixtures/isinstance.pyi] [out] -main:5: note: Redundant cast to "str" +main:5: error: Redundant cast to "str" [case testCastToSuperclassNotRedundant] # flags: --warn-redundant-casts @@ -45,7 +45,7 @@ a = 1 if int(): a = 'a' # type: ignore if int(): - a = 2 # type: ignore # N: unused 'type: ignore' comment + a = 2 # type: ignore # E: unused 'type: ignore' comment if int(): a = 'b' # E: Incompatible types in assignment (expression has type "str", variable has type "int") @@ -57,8 +57,8 @@ from m import * # type: ignore [file m.py] pass [out] -main:3: note: unused 'type: ignore' comment -main:4: note: unused 'type: ignore' comment +main:3: error: unused 'type: ignore' comment +main:4: error: unused 'type: ignore' comment -- No return @@ -144,7 +144,7 @@ from typing import Any def g() -> Any: pass def f() -> int: return g() [out] -main:4: warning: Returning Any from function declared to return "int" +main:4: error: Returning Any from function declared to return "int" [case testReturnAnyForNotImplementedInBinaryMagicMethods] # flags: --warn-return-any @@ -159,7 +159,7 @@ class A: def some(self) -> bool: return NotImplemented [builtins fixtures/notimplemented.pyi] [out] -main:3: warning: Returning Any from function declared to return "bool" +main:3: error: Returning Any from function declared to return "bool" [case testReturnAnyFromTypedFunctionWithSpecificFormatting] # flags: --warn-return-any @@ -174,7 +174,7 @@ typ = Tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, def g() -> Any: pass def f() -> typ: return g() [out] -main:11: warning: Returning Any from function declared to return +main:11: error: Returning Any from function declared to return [case testReturnAnySilencedFromTypedFunction] # flags: --warn-return-any diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index ccf0dc41adcb..dab387430f83 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -385,7 +385,7 @@ follow_imports = error [file a.py] / # No error reported [out] -main.py:1: note: Import of 'a' ignored +main.py:1: error: Import of 'a' ignored main.py:1: note: (Using --follow-imports=error, module not passed on command line) main.py:2: error: Revealed type is 'Any' main.py:4: error: Revealed type is 'Any' @@ -423,7 +423,7 @@ bla bla bla bla [out] normal.py:2: error: Unsupported operand types for + ("int" and "str") -main.py:4: note: Import of 'error' ignored +main.py:4: error: Import of 'error' ignored main.py:4: note: (Using --follow-imports=error, module not passed on command line) main.py:5: error: Revealed type is 'builtins.int' main.py:6: error: Revealed type is 'builtins.int' @@ -1114,7 +1114,7 @@ follow_imports_for_stubs = True import math math.frobnicate() [out] -main.py:1: note: Import of 'math' ignored +main.py:1: error: Import of 'math' ignored main.py:1: note: (Using --follow-imports=error, module not passed on command line) [case testFollowImportStubs2] diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index bdca4824954a..96eded2c68f2 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -110,7 +110,7 @@ Daemon started $ dmypy check foo.py bar.py $ dmypy recheck $ dmypy recheck --update foo.py --remove bar.py sir_not_appearing_in_this_film.py -foo.py:1: note: Import of 'bar' ignored +foo.py:1: error: Import of 'bar' ignored foo.py:1: note: (Using --follow-imports=error, module not passed on command line) == Return code: 1 $ dmypy recheck --update bar.py diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 688c9e36920d..aa7c32d27427 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -1822,10 +1822,10 @@ x = 1 [file c.py.2] x = '2' [out] -a.py:2: note: Import of 'b' ignored +a.py:2: error: Import of 'b' ignored a.py:2: note: (Using --follow-imports=error, module not passed on command line) == -a.py:2: note: Import of 'b' ignored +a.py:2: error: Import of 'b' ignored a.py:2: note: (Using --follow-imports=error, module not passed on command line) [case testErrorButDontIgnore2] @@ -1842,7 +1842,7 @@ x = 1 x = '2' [out] == -a.py:2: note: Import of 'b' ignored +a.py:2: error: Import of 'b' ignored a.py:2: note: (Using --follow-imports=error, module not passed on command line) -- TODO: This test fails because p.b does not depend on p (#4847) @@ -1862,7 +1862,7 @@ x = 1 x = '2' [out] == -p/b.py: note: Ancestor package 'p' ignored +p/b.py: error: Ancestor package 'p' ignored p/b.py: note: (Using --follow-imports=error, submodule passed on command line) [case testErrorButDontIgnore4] @@ -1880,7 +1880,7 @@ x = 1 [delete z.py.2] [out] == -p/b.py: note: Ancestor package 'p' ignored +p/b.py: error: Ancestor package 'p' ignored p/b.py: note: (Using --follow-imports=error, submodule passed on command line) p/b.py:1: error: Cannot find module named 'z' p/b.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports From cfe9acbf278009104ad93f1ce4aeb928547db279 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 11 Apr 2019 11:46:02 -0700 Subject: [PATCH 2/4] Comment tweaks --- mypy/errors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/errors.py b/mypy/errors.py index 19f8c5632dc4..2a7cdb0e8a38 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -42,7 +42,7 @@ class ErrorInfo: # The column number related to this error with file. column = 0 # -1 if unknown - # Either 'error', 'note', or 'warning'. + # Either 'error' or 'note' severity = '' # The error message. @@ -240,7 +240,7 @@ def report(self, line: line number of error message: message to report blocker: if True, don't continue analysis after this error - severity: 'error', 'note' or 'warning' + severity: 'error' or 'note' file: if non-None, override current file as context only_once: if True, only report this exact message once per build origin_line: if non-None, override current context as origin From c213314b62a97ffa85234fc455bd23b8de97fd61 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 11 Apr 2019 11:46:47 -0700 Subject: [PATCH 3/4] restore newline --- mypy/checkmember.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 887c4fd94a18..2117194e7fba 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -328,6 +328,7 @@ def analyze_member_var_access(name: str, # independently of types. if mx.is_lvalue and not mx.chk.get_final_context(): check_final_member(name, info, mx.msg, mx.context) + return analyze_var(name, v, itype, info, mx, implicit=implicit) elif isinstance(v, FuncDef): assert False, "Did not expect a function" From 42b57d298a9e1c8e8621e2afcac76fe30ed9958b Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Thu, 11 Apr 2019 12:16:15 -0700 Subject: [PATCH 4/4] fix 3.8 tests --- test-data/unit/check-38.test | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test-data/unit/check-38.test b/test-data/unit/check-38.test index c4c9a154f661..2cbd0f95e172 100644 --- a/test-data/unit/check-38.test +++ b/test-data/unit/check-38.test @@ -56,24 +56,24 @@ def g(x: int): ... [case testIgnoreScopeUnused1] # flags: --warn-unused-ignores -( # type: ignore # N: unused 'type: ignore' comment +( # type: ignore # E: unused 'type: ignore' comment "IGNORE" # type: ignore - + # type: ignore # N: unused 'type: ignore' comment - 0 # type: ignore # N: unused 'type: ignore' comment -) # type: ignore # N: unused 'type: ignore' comment + + # type: ignore # E: unused 'type: ignore' comment + 0 # type: ignore # E: unused 'type: ignore' comment +) # type: ignore # E: unused 'type: ignore' comment [case testIgnoreScopeUnused2] # flags: --warn-unused-ignores -( # type: ignore # N: unused 'type: ignore' comment +( # type: ignore # E: unused 'type: ignore' comment "IGNORE" - # type: ignore - 0 # type: ignore # N: unused 'type: ignore' comment -) # type: ignore # N: unused 'type: ignore' comment + 0 # type: ignore # E: unused 'type: ignore' comment +) # type: ignore # E: unused 'type: ignore' comment [case testIgnoreScopeUnused3] # flags: --warn-unused-ignores -( # type: ignore # N: unused 'type: ignore' comment +( # type: ignore # E: unused 'type: ignore' comment "IGNORE" / 0 # type: ignore -) # type: ignore # N: unused 'type: ignore' comment +) # type: ignore # E: unused 'type: ignore' comment