Repository: python/mypy

Issue:
Cannot ignore untyped exception with `as e` syntax
We are trying to utilize mypy in order to introduce strict type checking in our code. However, there are some libraries that we need to add `# type: ignore` that don't have any type stubs on. This works most of the time, but I believe we ran into some edge cases where this doesn't work.

Consider the following code (`test.py`):

```
import jsonschema  # type: ignore

schema = {
    "type": "object",
    "properties": {"price": {"type": "number"}, "name": {"type": "string"}},
}

try:
    jsonschema.validate(instance={"name": "Eggs", "price": 34.99}, schema=schema)  # type: ignore
except jsonschema.ValidationError as e:  # type: ignore
    print(str(e))  # type: ignore
```

Running mypy on above code:

```
$ mypy test.py --disallow-any-expr
test.py: error: Expression has type "Any"
Found 1 error in 1 file (checked 1 source file)
```

Results in the entire file having an `Any` expression without a line number representing where the issue is occuring.

However, if I don't use the exception `e`:

```
import jsonschema  # type: ignore

schema = {
    "type": "object",
    "properties": {"price": {"type": "number"}, "name": {"type": "string"}},
}

try:
    jsonschema.validate(instance={"name": "Eggs", "price": 34.99}, schema=schema)  # type: ignore
except jsonschema.ValidationError:  # type: ignore
    print("not used")
```

mypy with the strict flag will report success:

```
$ mypy test.py --disallow-any-expr
Success: no issues found in 1 source file
```

I have been trying to comb through the documentation and also github issues for something similar, but I haven't come across this specific use case or how to workaround it. I'm able to add a `type: ignore` to the top of the file, but then I lose type checking for the rest of the file. I guess another work around would also be to add a module to dump all of the non-mypy specific usage and then just ignore those files.

Is this currently expected behavior for this flag?

mypy version: **0.77**
python version: **3.7.5**




Discussion:

Resolving patch:
diff --git a/mypy/fastparse.py b/mypy/fastparse.py
--- a/mypy/fastparse.py
+++ b/mypy/fastparse.py
@@ -315,7 +315,7 @@ def visit(self, node: Optional[AST]) -> Any:
             self.visitor_cache[typeobj] = visitor
         return visitor(node)
 
-    def set_line(self, node: N, n: Union[ast3.expr, ast3.stmt]) -> N:
+    def set_line(self, node: N, n: Union[ast3.expr, ast3.stmt, ast3.ExceptHandler]) -> N:
         node.line = n.lineno
         node.column = n.col_offset
         node.end_line = getattr(n, "end_lineno", None) if isinstance(n, ast3.expr) else None
@@ -838,7 +838,9 @@ def visit_Raise(self, n: ast3.Raise) -> RaiseStmt:
 
     # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
     def visit_Try(self, n: ast3.Try) -> TryStmt:
-        vs = [NameExpr(h.name) if h.name is not None else None for h in n.handlers]
+        vs = [
+            self.set_line(NameExpr(h.name), h) if h.name is not None else None for h in n.handlers
+        ]
         types = [self.visit(h.type) for h in n.handlers]
         handlers = [self.as_required_block(h.body, h.lineno) for h in n.handlers]
 
diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py
--- a/mypy/fastparse2.py
+++ b/mypy/fastparse2.py
@@ -187,7 +187,7 @@ def visit(self, node: Optional[AST]) -> Any:  # same as in typed_ast stub
             self.visitor_cache[typeobj] = visitor
         return visitor(node)
 
-    def set_line(self, node: N, n: Union[ast27.expr, ast27.stmt]) -> N:
+    def set_line(self, node: N, n: Union[ast27.expr, ast27.stmt, ast27.ExceptHandler]) -> N:
         node.line = n.lineno
         node.column = n.col_offset
         return node
@@ -694,7 +694,7 @@ def try_handler(self,
             if item.name is None:
                 vs.append(None)
             elif isinstance(item.name, Name):
-                vs.append(NameExpr(item.name.id))
+                vs.append(self.set_line(NameExpr(item.name.id), item))
             else:
                 self.fail("Sorry, `except <expr>, <anything but a name>` is not supported",
                           item.lineno, item.col_offset)


Test patch: