Commits

Anonymous committed e054779

Closes #93591: Correctly emit W0623 on multiple assignment of unpackable exceptions

eg for code like

try:
...
except AnyException as (here, there):
...

Instead of warning about redefining tuple, recurse into the tuple and check all names.

Comments (0)

Files changed (5)

 ====================
 
 	--
+    * #93591: Correctly emit warnings about clobbered variable names when an
+      except handler contains a tuple of names instead of a single name.
+      (patch by tmarek@google.com)
 
     * #7394: W0212 (access to protected member) not emited on assigments
     (patch by lothiraldan@gmail.com)

checkers/utils.py

 
 COMP_NODE_TYPES = astng.ListComp, astng.SetComp, astng.DictComp, astng.GenExpr
 
+
 def is_inside_except(node):
-    """Returns true if node is directly inside an exception handler"""
-    return isinstance(node.parent, astng.ExceptHandler)
+    """Returns true if node is inside the name of an except handler."""
+    current = node
+    while current and not isinstance(current.parent, astng.ExceptHandler):
+        current = current.parent
+    
+    return current and current is current.parent.name
+
+
+def get_all_elements(node):
+    """Recursively returns all atoms in nested lists and tuples."""
+    if isinstance(node, (astng.Tuple, astng.List)):
+        for child in node.elts:
+            for e in get_all_elements(child):
+                yield e
+    else:
+        yield node
 
 
 def clobber_in_except(node):
     """
     if isinstance(node, astng.AssAttr):
         return (True, (node.attrname, 'object %r' % (node.expr.name,)))
-    elif node is not None:
+    elif isinstance(node, astng.AssName):
         name = node.name
         if is_builtin(name):
             return (True, (name, 'builtins'))

checkers/variables.py

 from pylint.checkers import BaseChecker
 from pylint.checkers.utils import (PYMETHODS, is_ancestor_name, is_builtin,
      is_defined_before, is_error, is_func_default, is_func_decorator,
-     assign_parent, check_messages, is_inside_except, clobber_in_except)
+     assign_parent, check_messages, is_inside_except, clobber_in_except,
+     get_all_elements)
 
 
 def in_for_else_branch(parent, stmt):
                 self.add_message('W0631', args=name, node=node)
 
     def visit_excepthandler(self, node):
-        clobbering, args = clobber_in_except(node.name)
-        if clobbering:
-            self.add_message('W0623', args=args, node=node)
+        for name in get_all_elements(node.name):
+            clobbering, args = clobber_in_except(name)
+            if clobbering:
+                self.add_message('W0623', args=args, node=name)
 
     def visit_assname(self, node):
         if isinstance(node.ass_type(), astng.AugAssign):
             self.visit_name(node)
-
+          
     def visit_delname(self, node):
         self.visit_name(node)
 

test/input/func_w0623.py

     print exc5
 except MyOtherError, exc5: # this is fine
     print exc5
+
+def new_style():
+    """Some exceptions can be unpacked."""
+    try:
+        pass
+    except IOError as (errno, message): # this is fine
+        print errno, message
+    except IOError as (new_style, tuple): # W0623 twice
+        print new_style, tuple
+        

test/messages/func_w0623.txt

 W: 45: Redefining name 'RuntimeError' from object 'exceptions' in exception handler
 W: 47: Redefining name 'OSError' from builtins in exception handler
 W: 49: Redefining name 'MyOtherError' from outer scope (line 36) in exception handler
+W: 73:new_style: Redefining name 'new_style' from outer scope (line 67) in exception handler
+W: 73:new_style: Redefining name 'tuple' from builtins in exception handler
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.