← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~twom/launchpad:lint-e701 into launchpad:master

 

Tom Wardill has proposed merging ~twom/launchpad:lint-e701 into launchpad:master.

Commit message:
Remove E701 lint violations

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/406625
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:lint-e701 into launchpad:master.
diff --git a/utilities/findimports.py b/utilities/findimports.py
new file mode 100755
index 0000000..8276094
--- /dev/null
+++ b/utilities/findimports.py
@@ -0,0 +1,366 @@
+<<<<<<< utilities/findimports.py
+=======
+#!/usr/bin/python2
+#
+# Copyright 2009 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""
+FindImports is a script that processes Python module dependencies.  Currently
+it can be used for finding unused imports and graphing module dependencies
+(with graphviz).  FindImports requires Python 2.3.
+
+Syntax: findimports.py [options] [filename|dirname ...]
+
+Options:
+  -h, --help        This help message
+
+  -i, --imports     Print dependency graph (default action).
+  -d, --dot         Print dependency graph in dot format.
+  -n, --names       Print dependency graph with all imported names.
+
+  -u, --unused      Print unused imports.
+  -a, --all         Print all unused imports (use together with -u).
+
+Copyright (c) 2003, 2004 Marius Gedminas <marius@xxxxxx>
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+Ave, Cambridge, MA 02139, USA.
+"""
+
+from __future__ import absolute_import, print_function
+
+import compiler
+from compiler.visitor import ASTVisitor
+import getopt
+import linecache
+import os
+import sys
+
+import six
+
+
+class ImportFinder(ASTVisitor):
+    """AST visitor that collects all imported names in its imports attribute.
+
+    For example, the following import statements in the AST tree
+
+       import a, b.c, d as e
+       from q.w.e import x, y as foo, z
+       from woof import *
+
+    will cause imports to contain
+
+       a
+       b.c
+       d
+       q.w.e.x
+       q.w.e.y
+       q.w.e.z
+       woof.*
+    """
+
+    def __init__(self):
+        self.imports = []
+
+    def visitImport(self, node):
+        for name, imported_as in node.names:
+            self.imports.append(name)
+
+    def visitFrom(self, node):
+        for name, imported_as in node.names:
+            self.imports.append('%s.%s' % (node.modname, name))
+
+
+class UnusedName(object):
+
+    def __init__(self, name, lineno):
+        self.name = name
+        self.lineno = lineno
+
+
+class ImportFinderAndNametracker(ImportFinder):
+    """ImportFinder that also keeps track on used names."""
+
+    def __init__(self):
+        ImportFinder.__init__(self)
+        self.unused_names = {}
+
+    def visitImport(self, node):
+        ImportFinder.visitImport(self, node)
+        for name, imported_as in node.names:
+            if not imported_as:
+                imported_as = name
+            if imported_as != "*":
+                self.unused_names[imported_as] = UnusedName(imported_as,
+                                                            node.lineno)
+
+    def visitFrom(self, node):
+        ImportFinder.visitFrom(self, node)
+        for name, imported_as in node.names:
+            if not imported_as:
+                imported_as = name
+            if imported_as != "*":
+                self.unused_names[imported_as] = UnusedName(imported_as,
+                                                            node.lineno)
+
+    def visitName(self, node):
+        if node.name in self.unused_names:
+            del self.unused_names[node.name]
+
+    def visitGetattr(self, node):
+        full_name = [node.attrname]
+        parent = node.expr
+        while isinstance(parent, compiler.ast.Getattr):
+            full_name.append(parent.attrname)
+            parent = parent.expr
+        if isinstance(parent, compiler.ast.Name):
+            full_name.append(parent.name)
+            full_name.reverse()
+            name = ""
+            for part in full_name:
+                if name:
+                    name = '%s.%s' % (name, part)
+                else:
+                    name += part
+                if name in self.unused_names:
+                    del self.unused_names[name]
+        for c in node.getChildNodes():
+            self.visit(c)
+
+
+def find_imports(filename):
+    """Find all imported names in a given file."""
+    ast = compiler.parseFile(filename)
+    visitor = ImportFinder()
+    compiler.walk(ast, visitor)
+    return visitor.imports
+
+def find_imports_and_track_names(filename):
+    """Find all imported names in a given file."""
+    ast = compiler.parseFile(filename)
+    visitor = ImportFinderAndNametracker()
+    compiler.walk(ast, visitor)
+    return visitor.imports, visitor.unused_names
+
+
+class Module(object):
+
+    def __init__(self, modname, filename):
+        self.modname = modname
+        self.filename = filename
+
+
+class ModuleGraph(object):
+
+    trackUnusedNames = False
+    all_unused = False
+
+    def __init__(self):
+        self.modules = {}
+        self.path = sys.path
+        self._module_cache = {}
+        self._warned_about = set()
+
+    def parsePathname(self, pathname):
+        if os.path.isdir(pathname):
+            for root, dirs, files in os.walk(pathname):
+                for fn in files:
+                    # ignore emacsish junk
+                    if fn.endswith('.py') and not fn.startswith('.#'):
+                        self.parseFile(os.path.join(root, fn))
+        else:
+            self.parseFile(pathname)
+
+    def parseFile(self, filename):
+        modname = self.filenameToModname(filename)
+        module = Module(modname, filename)
+        self.modules[modname] = module
+        if self.trackUnusedNames:
+            module.imported_names, module.unused_names = \
+                    find_imports_and_track_names(filename)
+        else:
+            module.imported_names = find_imports(filename)
+            module.unused_names = None
+        dir = os.path.dirname(filename)
+        module.imports = set([self.findModuleOfName(name, filename, dir)
+                              for name in module.imported_names])
+
+    def filenameToModname(self, filename):
+        for ext in ('.py', '.so', '.dll'):
+            if filename.endswith(ext):
+                break
+        else:
+            print(
+                "%s: unknown file name extension" % filename, file=sys.stderr)
+        longest_prefix_len = 0
+        filename = os.path.abspath(filename)
+        for prefix in self.path:
+            prefix = os.path.abspath(prefix)
+            if (filename.startswith(prefix)
+                and len(prefix) > longest_prefix_len):
+                longest_prefix_len = len(prefix)
+        filename = filename[longest_prefix_len:-len('.py')]
+        if filename.startswith(os.path.sep):
+            filename = filename[len(os.path.sep):]
+        modname = ".".join(filename.split(os.path.sep))
+        return modname
+
+    def findModuleOfName(self, dotted_name, filename, extrapath=None):
+        if dotted_name.endswith('.*'):
+            return dotted_name[:-2]
+        name = dotted_name
+        while name:
+            candidate = self.isModule(name, extrapath)
+            if candidate:
+                return candidate
+            candidate = self.isPackage(name, extrapath)
+            if candidate:
+                return candidate
+            name = name[:name.rfind('.')]
+        if dotted_name not in self._warned_about:
+            print(
+                "%s: could not find %s" % (filename, dotted_name),
+                file=sys.stderr)
+            self._warned_about.add(dotted_name)
+        return dotted_name
+
+    def isModule(self, dotted_name, extrapath=None):
+        try:
+            return self._module_cache[(dotted_name, extrapath)]
+        except KeyError:
+            pass
+        if dotted_name in sys.modules:
+            return dotted_name
+        filename = dotted_name.replace('.', os.path.sep)
+        if extrapath:
+            for ext in ('.py', '.so', '.dll'):
+                candidate = os.path.join(extrapath, filename) + ext
+                if os.path.exists(candidate):
+                    modname = self.filenameToModname(candidate)
+                    self._module_cache[(dotted_name, extrapath)] = modname
+                    return modname
+        try:
+            return self._module_cache[(dotted_name, None)]
+        except KeyError:
+            pass
+        for dir in self.path:
+            for ext in ('.py', '.so', '.dll'):
+                candidate = os.path.join(dir, filename) + ext
+                if os.path.exists(candidate):
+                    modname = self.filenameToModname(candidate)
+                    self._module_cache[(dotted_name, extrapath)] = modname
+                    self._module_cache[(dotted_name, None)] = modname
+                    return modname
+        return None
+
+    def isPackage(self, dotted_name, extrapath=None):
+        candidate = self.isModule(dotted_name + '.__init__', extrapath)
+        if candidate:
+            candidate = candidate[:-len(".__init__")]
+        return candidate
+
+    def listModules(self):
+        modules = list(self.modules.items())
+        modules.sort()
+        return [module for name, module in modules]
+
+    def printImportedNames(self):
+        for module in self.listModules():
+            print("%s:" % module.modname)
+            print("  %s" % "\n  ".join(module.imported_names))
+
+    def printImports(self):
+        for module in self.listModules():
+            print("%s:" % module.modname)
+            imports = list(module.imports)
+            imports.sort()
+            print("  %s" % "\n  ".join(imports))
+
+    def printUnusedImports(self):
+        for module in self.listModules():
+            names = [(unused.lineno, unused.name)
+                     for unused in six.itervalues(module.unused_names)]
+            names.sort()
+            for lineno, name in names:
+                if not self.all_unused:
+                    line = linecache.getline(module.filename, lineno)
+                    if '#' in line:
+                        continue # assume there's a comment explaining why it
+                                 # is not used
+                print("%s:%s: %s not used" % (module.filename, lineno, name))
+
+    def printDot(self):
+        print("digraph ModuleDependencies {")
+        print("  node[shape=box];")
+        allNames = set()
+        nameDict = {}
+        for n, module in enumerate(self.listModules()):
+            module._dot_name = "mod%d" % n
+            nameDict[module.modname] = module._dot_name
+            print("  %s[label=\"%s\"];" % (module._dot_name, module.modname))
+            for name in module.imports:
+                if name not in self.modules:
+                    allNames.add(name)
+        print("  node[style=dotted];")
+        names = list(allNames)
+        names.sort()
+        for n, name in enumerate(names):
+            nameDict[name] = id = "extmod%d" % n
+            print("  %s[label=\"%s\"];" % (id, name))
+        for module in self.modules.values():
+            for other in module.imports:
+                print("  %s -> %s;" % (nameDict[module.modname],
+                                       nameDict[other]))
+        print("}")
+
+
+def main(argv=sys.argv):
+    progname = os.path.basename(argv[0])
+    helptext = __doc__.strip().replace('findimports.py', progname)
+    g = ModuleGraph()
+    action = g.printImports
+    try:
+        opts, args = getopt.getopt(argv[1:], 'duniah',
+                                   ['dot', 'unused', 'all', 'names', 'imports',
+                                    'help'])
+    except getopt.error as e:
+        print("%s: %s" % (progname, e), file=sys.stderr)
+        print("Try %s --help." % progname, file=sys.stderr)
+        return 1
+    for k, v in opts:
+        if k in ('-d', '--dot'):
+            action = g.printDot
+        elif k in ('-u', '--unused'):
+            action = g.printUnusedImports
+        elif k in ('-a', '--all'):
+            g.all_unused = True
+        elif k in ('-n', '--names'):
+            action = g.printImportedNames
+        elif k in ('-i', '--imports'):
+            action = g.printImports
+        elif k in ('-h', '--help'):
+            print(helptext)
+            return 0
+    g.trackUnusedNames = (action == g.printUnusedImports)
+    if not args:
+        args = ['.']
+    for fn in args:
+        g.parsePathname(fn)
+    action()
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
+
+>>>>>>> utilities/findimports.py