Repository: PyCQA/flake8-bugbear

Issue:
bugbear 21.4.1 + 21.4.2 fails with AttributeError
Newly updated bugbear 21.4.1 fails with AttributeError:
```
21:06:51 Traceback (most recent call last):
21:06:51   File "/usr/lib/python3.6/multiprocessing/pool.py", line 119, in worker
21:06:51     result = (True, func(*args, **kwds))
21:06:51   File "/usr/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
21:06:51     return list(map(*args))
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 676, in _run_checks
21:06:51     return checker.run_checks()
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 589, in run_checks
21:06:51     self.run_ast_checks()
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 494, in run_ast_checks
21:06:51     for (line_number, offset, text, _) in runner:
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 36, in run
21:06:51     visitor.visit(self.tree)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
21:06:51     super().visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
21:06:51     return visitor(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
21:06:51     self.visit(item)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
21:06:51     super().visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
21:06:51     return visitor(node)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 306, in visit_ClassDef
21:06:51     self.generic_visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
21:06:51     self.visit(item)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
21:06:51     super().visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
21:06:51     return visitor(node)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 302, in visit_FunctionDef
21:06:51     self.generic_visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
21:06:51     self.visit(item)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
21:06:51     super().visit(node)
21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
21:06:51     return visitor(node)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 321, in visit_With
21:06:51     self.check_for_b017(node)
21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 442, in check_for_b017
21:06:51     hasattr(item_context.func, "attr")
21:06:51 AttributeError: 'Name' object has no attribute 'func'
21:06:51 """
```
See https://integration.wikimedia.org/ci/job/pywikibot-core-tox-docker/14952/console

Discussion:

Patch:
diff --git a/bugbear.py b/bugbear.py
index 429ebd6..b881b8b 100644
--- a/bugbear.py
+++ b/bugbear.py
@@ -10,9 +10,10 @@ from functools import lru_cache, partial
 from keyword import iskeyword
 
 import attr
+
 import pycodestyle
 
-__version__ = "21.4.2"
+__version__ = "21.4.3"
 
 LOG = logging.getLogger("flake8.bugbear")
 
@@ -443,6 +444,7 @@ class BugBearVisitor(ast.NodeVisitor):
             and hasattr(item_context.func, "attr")  # noqa W503
             and item_context.func.attr == "assertRaises"  # noqa W503
             and len(item_context.args) == 1  # noqa W503
+            and isinstance(item_context.args[0], ast.Name)  # noqa W503
             and item_context.args[0].id == "Exception"  # noqa W503
             and not item.optional_vars  # noqa W503
         ):


Test patch:
diff --git a/tests/b017.py b/tests/b017.py
index e9b7430..21836a6 100644
--- a/tests/b017.py
+++ b/tests/b017.py
@@ -1,9 +1,9 @@
 """
 Should emit:
-B017 - on lines 10
+B017 - on lines 20
 """
 import unittest
-
+import asyncio
 
 CONSTANT = True
 
@@ -13,6 +13,10 @@ def something_else() -> None:
         print(i)
 
 
+class Foo:
+    pass
+
+
 class Foobar(unittest.TestCase):
     def evil_raises(self) -> None:
         with self.assertRaises(Exception):
@@ -26,3 +30,7 @@ class Foobar(unittest.TestCase):
     def regex_raises(self) -> None:
         with self.assertRaisesRegex(Exception, "Regex is good"):
             raise Exception("Regex is good")
+
+    def raises_with_absolute_reference(self):
+        with self.assertRaises(asyncio.CancelledError):
+            Foo()
diff --git a/tests/test_bugbear.py b/tests/test_bugbear.py
index 8bd279f..c6e31bb 100644
--- a/tests/test_bugbear.py
+++ b/tests/test_bugbear.py
@@ -210,7 +210,7 @@ class BugbearTestCase(unittest.TestCase):
         filename = Path(__file__).absolute().parent / "b017.py"
         bbc = BugBearChecker(filename=str(filename))
         errors = list(bbc.run())
-        expected = self.errors(B017(18, 8))
+        expected = self.errors(B017(22, 8))
         self.assertEqual(errors, expected)
 
     def test_b301_b302_b305(self):