Commits

Ronny Pfannschmidt committed 913d0ad

correct the handling of creating functions in condition scopes in functions

  • Participants
  • Parent commits ceed6a1
  • Branches experimental

Comments (0)

Files changed (2)

pyflakes/checker.py

     def __init__(self):
         super(Scope, self).__init__()
 
-
+    def of_type(self, type):
+        return isinstance(self, type)
 
 class ClassScope(Scope):
     pass
     escapes = False
 
     def __init__(self, parent):
+        super(ConditionScope, self).__init__()
         self.parent = parent
 
     def __getitem__(self, key):
         return self.parent.globals
 
 
+    def of_type(self, type):
+        return self.parent.of_type(type) or isinstance(self, type)
 
 class ModuleScope(Scope):
     pass
 
             for scope in self.scopeStack[-2:0:-1]:
                 importStarred = importStarred or scope.importStarred
-                if not isinstance(scope, FunctionScope):
+                if not scope.of_type(FunctionScope):
                     continue
                 try:
                     scope[node.id].used = (self.scope, node.lineno)
                 for scope in valid_scopes[1:]:
                     scope.pop(name, None) # might not exist when body is ok
 
+        for scope in valid_scopes:
+            for key, binding in scope.items():
+                if key not in self.scope and not binding.used:
+                    # bubble up all unused variables
+                    # this should rather use the possible flowgraphs
+                    self.scope[key] = binding
+
 
         for stmt in node.orelse:
             self.handleNode(stmt, node)

pyflakes/test/test_scopes.py

             else:
                 print(etree)
             """)
+
+    def test_lotsa_local_scopes(self):
+        """code from mercurial that gave the condition code hickups"""
+        self.flakes("""
+        import os
+        short = _ = lambda x:x
+        import util
+        def makefilename(repo, pat, node,
+                         total=None, seqno=None,
+                         revwidth=None, pathname=None):
+            node_expander = {
+                'H': lambda: hex(node),
+                'R': lambda: str(repo.changelog.rev(node)),
+                'h': lambda: short(node),
+                }
+            expander = {
+                '%': lambda: '%',
+                'b': lambda: os.path.basename(repo.root),
+                }
+
+            try:
+                if node:
+                    expander.update(node_expander)
+                if node:
+                    expander['r'] = (lambda:
+                            str(repo.changelog.rev(node)).zfill(revwidth or 0))
+                if total is not None:
+                    expander['N'] = lambda: str(total)
+                if seqno is not None:
+                    expander['n'] = lambda: str(seqno)
+                if total is not None and seqno is not None:
+                    expander['n'] = lambda: str(seqno).zfill(len(str(total)))
+                if pathname is not None:
+                    expander['s'] = lambda: os.path.basename(pathname)
+                    expander['d'] = lambda: os.path.dirname(pathname) or '.'
+                    expander['p'] = lambda: pathname
+
+                newname = []
+                patlen = len(pat)
+                i = 0
+                while i < patlen:
+                    c = pat[i]
+                    if c == '%':
+                        i += 1
+                        c = pat[i]
+                        c = expander[c]()
+                    newname.append(c)
+                    i += 1
+                return ''.join(newname)
+            except KeyError, inst:
+                raise util.Abort(_("invalid format spec '%%%s' in output filename") %
+                                 inst.args[0])
+        """)