Skip to content

Instantly share code, notes, and snippets.

@rubik
Created April 20, 2011 10:38
Show Gist options
  • Save rubik/930964 to your computer and use it in GitHub Desktop.
Save rubik/930964 to your computer and use it in GitHub Desktop.
Bad modules detector (modules imported but not used)
import re
import os
import ast
import glob
import collections
class ImportVisitor(ast.NodeVisitor):
def __init__(self):
self.imports = []
self.modules = collections.defaultdict(list)
def visit_Import(self, node):
for name in node.names:
self.imports.append(name.asname or name.name)
def visit_ImportFrom(self, node):
for name in node.names:
self.modules[node.module].append(name.asname or name.name)
def parse_string(code):
visitor = ImportVisitor()
visitor.visit(ast.parse(code))
return visitor.imports, visitor.modules
def parse_file(name):
with open(name) as f:
code = f.read()
return parse_string(code)
def check_file(path):
i, m = parse_file(path)
with open(path) as f:
code = f.read()
single_badmods = []
badmods = collections.defaultdict(list)
for mod in i:
r = re.compile(r'{0}\.'.format(mod))
if not r.search(code):
single_badmods.append(mod)
for mod, objs in m.iteritems():
for obj in objs:
if obj == '*':
print 'Warning: importing all objects from {0}; cannot check'.format(mod)
continue
r = re.compile(r'{0}[\.|(]?'.format(obj))
if len(r.findall(code)) < 2:
badmods[mod].append(obj)
return single_badmods, badmods
def format_result(filename, results):
r1 = '\n'.join('\t{0} not used'.format(mod) for mod in results[0])
r2 = '\n'.join('\t{0} not used (from {1})'.format(obj, package) for package, objs in results[1].iteritems() for obj in objs)
if r1 or r2:
result = '{0}:\n' \
'{1}\n' \
'{2}'.format(filename, r1 or '', r2 or '')
elif not r1 and not r2:
result = '{0}: OK'.format(filename)
return result
def scan(path):
return format_result(os.path.basename(path), check_file(path))
def main():
import argparse
parser = argparse.ArgumentParser(prog='badmo')
parser.add_argument('-d', '--dir', default='.', metavar='<path>', help='Set the directory to scan')
parser.add_argument('-f', '--file', metavar='<path>', help='Scan a single file only')
args = parser.parse_args()
if args.file:
print 'Scanning {0}'.format(args.file)
print scan(args.file)
if args.dir != '.' or not args.file:
files = []
path = os.path.abspath(args.dir)
files.extend(glob.glob(os.path.join(path, '*.py')))
print ('\n' if args.file else '') + 'Scanning {0}'.format(path)
for file in sorted(files):
print scan(file)
if __name__ == '__main__':
main()
from setuptools import setup
setup(name='badmo.py',
version='0.1',
author='Michele Lacchia',
author_email='[email protected]',
summary='Bad modules detector',
platform='any',
provides=['badmo'],
py_modules=['badmo'],
install_requires=['argparse>=1.1'],
entry_points={
'console_scripts': [
'badmo = badmo:main'
]
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment