diff --git a/README.rst b/README.rst index 0ea120a..22cce27 100644 --- a/README.rst +++ b/README.rst @@ -325,6 +325,11 @@ MIT Change Log ---------- +Unreleased +~~~~~~~~~~ + +* B030: Fix crash on certain unusual except handlers (e.g. ``except a[0].b:``) + 23.3.12 ~~~~~~~~ diff --git a/bugbear.py b/bugbear.py index 7940120..a2a2298 100644 --- a/bugbear.py +++ b/bugbear.py @@ -250,15 +250,18 @@ def _check_redundant_excepthandlers(names, node): def _to_name_str(node): # Turn Name and Attribute nodes to strings, e.g "ValueError" or # "pkg.mod.error", handling any depth of attribute accesses. + # Return None for unrecognized nodes. if isinstance(node, ast.Name): return node.id if isinstance(node, ast.Call): return _to_name_str(node.func) - assert isinstance(node, ast.Attribute), f"Unexpected node type: {type(node)}" - try: - return _to_name_str(node.value) + "." + node.attr - except AttributeError: - return _to_name_str(node.value) + elif isinstance(node, ast.Attribute): + inner = _to_name_str(node.value) + if inner is None: + return None + return f"{inner}.{node.attr}" + else: + return None def names_from_assignments(assign_target): @@ -345,19 +348,22 @@ def visit_ExceptHandler(self, node): self.generic_visit(node) return handlers = _flatten_excepthandler(node.type) - good_handlers = [] + names = [] bad_handlers = [] ignored_handlers = [] for handler in handlers: if isinstance(handler, (ast.Name, ast.Attribute)): - good_handlers.append(handler) + name = _to_name_str(handler) + if name is None: + ignored_handlers.append(handler) + else: + names.append(name) elif isinstance(handler, (ast.Call, ast.Starred)): ignored_handlers.append(handler) else: bad_handlers.append(handler) if bad_handlers: self.errors.append(B030(node.lineno, node.col_offset)) - names = [_to_name_str(e) for e in good_handlers] if len(names) == 0 and not bad_handlers and not ignored_handlers: self.errors.append(B029(node.lineno, node.col_offset)) elif ( diff --git a/tests/b030.py b/tests/b030.py index 34c4b79..f90b2cd 100644 --- a/tests/b030.py +++ b/tests/b030.py @@ -32,3 +32,9 @@ def what_to_catch(): pass except what_to_catch(): # ok pass + + +try: + pass +except a.b[1].c: # ok + pass