Repository: python/mypy

Issue:
Ignoring a specific error code still outputs "notes" and returns exit status 1
Here's a minimal repro:

```python
from datetime import datetime
from typing import Optional

a: Optional[datetime] = None
b = datetime.now()

def some_function() -> None:
    if a <= b:
        pass
```

Running mypy on that file with `--show-error-codes` and `--pretty` outputs:

```
mypy_test.py:8: error: Unsupported operand types for >= ("datetime" and "None")  [operator]
        if a <= b:
           ^
mypy_test.py:8: note: Left operand is of type "Optional[datetime]"
```

If I add `# type: ignore` on the `if a <= b:` line, there is no error output, as expected.

However, if I use `# type: ignore[operator]` instead, the output is:

```
mypy_test.py:8: note: Left operand is of type "Optional[datetime]"
```

This also gives an exit status of `1`, making it seem like it returned an error.

As one step more, if I also add the `--show-error-context` flag, output is now:

```
mypy_test.py: note: In function "some_function":
mypy_test.py:8: note: Left operand is of type "Optional[datetime]"
```


Discussion:
This is known issue, although I can't find it now. Another example is the note about `defined here`, which is especially annoying IMO.

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -1472,8 +1472,8 @@ def check_overload_call(self,
                                  callable_name=callable_name,
                                  object_type=object_type)
         if union_interrupted:
-            self.chk.msg.note("Not all union combinations were tried"
-                              " because there are too many unions", context)
+            self.chk.fail("Not all union combinations were tried"
+                          " because there are too many unions", context)
         return result
 
     def plausible_overload_call_targets(self,
diff --git a/mypy/messages.py b/mypy/messages.py
--- a/mypy/messages.py
+++ b/mypy/messages.py
@@ -575,7 +575,7 @@ def unexpected_keyword_argument(self, callee: CallableType, name: str,
             if not fname:  # an alias to function with a different name
                 fname = 'Called function'
             self.note('{} defined here'.format(fname), callee.definition,
-                      file=module.path, origin=context)
+                      file=module.path, origin=context, code=codes.CALL_ARG)
 
     def duplicate_argument_value(self, callee: CallableType, index: int,
                                  context: Context) -> None:
@@ -926,10 +926,11 @@ def overloaded_signatures_ret_specific(self, index: int, context: Context) -> No
                   'of signature {}'.format(index), context)
 
     def warn_both_operands_are_from_unions(self, context: Context) -> None:
-        self.note('Both left and right operands are unions', context)
+        self.note('Both left and right operands are unions', context, code=codes.OPERATOR)
 
     def warn_operand_was_from_union(self, side: str, original: Type, context: Context) -> None:
-        self.note('{} operand is of type {}'.format(side, format_type(original)), context)
+        self.note('{} operand is of type {}'.format(side, format_type(original)), context,
+                  code=codes.OPERATOR)
 
     def operator_method_signatures_overlap(
             self, reverse_class: TypeInfo, reverse_method: str, forward_class: Type,


Test patch:
diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test
--- a/test-data/unit/check-errorcodes.test
+++ b/test-data/unit/check-errorcodes.test
@@ -1,4 +1,4 @@
--- Tests for error codes
+-- Tests for error codes and ignoring errors using error codes
 --
 -- These implicitly use --show-error-codes.
 
@@ -657,6 +657,29 @@ def g(self: A) -> None: pass
 
 A.f = g  # E: Cannot assign to a method  [assignment]
 
+[case testErrorCodeDefinedHereNoteIgnore]
+import m
+m.f(kw=1)  # type: ignore[call-arg]
+[file m.py]
+def f() -> None: pass
+
+[case testErrorCodeUnionNoteIgnore]
+from typing import Union
+
+class Foo:
+    def __add__(self, x: Foo) -> Foo: pass
+    def __radd__(self, x: Foo) -> Foo: pass
+
+class Bar:
+    def __add__(self, x: Bar) -> Bar: pass
+    def __radd__(self, x: Bar) -> Bar: pass
+
+a: Union[Foo, Bar]
+
+a + a  # type: ignore[operator]
+a + Foo()  # type: ignore[operator]
+Foo() + a  # type: ignore[operator]
+
 [case testErrorCodeTypeIgnoreMisspelled1]
 x = y  # type: ignored[foo]
 xx = y  # type: ignored [foo]
diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test
--- a/test-data/unit/check-overloading.test
+++ b/test-data/unit/check-overloading.test
@@ -4563,7 +4563,7 @@ def f(*args):
 x: Union[int, str]
 f(x, x, x, x, x, x, x, x)
 [out]
-main:11: note: Not all union combinations were tried because there are too many unions
+main:11: error: Not all union combinations were tried because there are too many unions
 main:11: error: Argument 1 to "f" has incompatible type "Union[int, str]"; expected "int"
 main:11: error: Argument 2 to "f" has incompatible type "Union[int, str]"; expected "int"
 main:11: error: Argument 3 to "f" has incompatible type "Union[int, str]"; expected "int"