Colin Watson has proposed merging ~cjwatson/launchpad:remove-findimports into launchpad:master.
Commit message: Remove utilities/findimports.py Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/406491 It's just a lightly-modified old version of the `findimports` module on PyPI; we could upgrade it to a more current version and gain Python 3 support, but it isn't used by anything in our tree, so it doesn't seem worth the effort. If you need it then you should just install it from PyPI. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:remove-findimports into launchpad:master.
diff --git a/utilities/findimports.py b/utilities/findimports.py deleted file mode 100755 index 90367ed..0000000 --- a/utilities/findimports.py +++ /dev/null @@ -1,361 +0,0 @@ -#!/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 <[email protected]> - -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()) -
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : [email protected] Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp

