Last active
December 12, 2015 05:38
-
-
Save durden/4723305 to your computer and use it in GitHub Desktop.
Hack attempt at building something that searches module for a given term to determine where to import it from.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import argparse | |
import inspect | |
import logging | |
import pydoc | |
import pkgutil | |
import sys | |
log = logging.getLogger("import_searcher") | |
# Don't search these modules | |
# Including pyuic because it has argument parsing on import and could print | |
# misleading error messages due to missing arguments. Authors didn't properly | |
# wrap their parsing in a method.. :) | |
IGNORE_MODULES = ['PyQt4.uic.pyuic'] | |
def _parse_args(): | |
parser = argparse.ArgumentParser( | |
description='Search module for specific module/class/attribute', | |
prog='import_searcher') | |
parser.add_argument('-m', '--module', action='store', dest='search_module', | |
required=False, default='PyQt4', | |
help='Module to search within') | |
parser.add_argument('-s', '--search_term', action='store', | |
dest='search_term', required=True, | |
help='Term to search for') | |
levels = ['critical', 'debug', 'info', 'warning', 'error'] | |
parser.add_argument('-l', '--log-level', action="store", dest="level", | |
default='warning', choices=levels) | |
args = vars(parser.parse_args()) | |
# FIXME: This option doesn't work yet. Need to figure out how to get pydoc | |
# to find and print help... | |
#parser.add_argument('-p', '--show-pydoc-help', action='store_true', | |
#dest='show_pydoc_help', required=False, default=False, | |
#help='Show pydoc help on found objects') | |
args['show_pydoc_help'] = False | |
# Get a standard log level from logging module base on given string | |
level = getattr(logging, args['level'].upper(), logging.WARNING) | |
args['level'] = level | |
return args | |
def _try_safeimport(name): | |
"""Try a pydoc.safeimport on name and log errors""" | |
try: | |
obj = pydoc.safeimport(name) | |
except pydoc.ErrorDuringImport as err: | |
log.debug('Error importing: %s' % (err.filename)) | |
log.debug(' %s %s' % (err.exc.__name__, err.value)) | |
raise err | |
return obj | |
def _object_to_string(obj): | |
"""Turn object into a friendly string with preference for __name__""" | |
try: | |
obj_name = obj.__name__ | |
except AttributeError: | |
obj_name = str(obj) | |
return obj_name | |
def _search_module_and_class(obj, search_term, show_pydoc_help): | |
"""Search given object recursively for search_term""" | |
for k, v in inspect.getmembers(obj, inspect.isclass or inspect.ismodule): | |
# User searching for class or module directly | |
if search_term in str(v): | |
obj_name = _object_to_string(obj) | |
value_name = _object_to_string(v) | |
print 'Class/module: %s' % ('.'.join([obj_name, value_name])) | |
# Search attributes | |
for ck, cv in inspect.getmembers(v): | |
if search_term in ck: | |
obj_name = _object_to_string(obj) | |
class_or_module_name = _object_to_string(v) | |
full_location = '.'.join([obj_name, class_or_module_name, ck]) | |
print 'Attribute: %s = %s' % (full_location, cv) | |
if show_pydoc_help: | |
pydoc.help(full_location) | |
def search(name, search_term, show_pydoc_help=False): | |
"""Search recursively for search_term in object imported from 'name'""" | |
if name in IGNORE_MODULES: | |
return | |
try: | |
obj = _try_safeimport(name) | |
except pydoc.ErrorDuringImport: | |
return | |
# See if we have a package or something else | |
try: | |
path = obj.__path__ | |
except AttributeError: | |
# Search module/class recursively | |
return _search_module_and_class(obj, search_term, show_pydoc_help) | |
# Search this package recursively | |
for i, m, ispkg in pkgutil.iter_modules(path): | |
search('.'.join([name, m]), search_term, show_pydoc_help) | |
def main(): | |
args = _parse_args() | |
handler = logging.StreamHandler(stream=sys.stdout) | |
log.addHandler(handler) | |
log.setLevel(args['level']) | |
search(args['search_module'], args['search_term'], args['show_pydoc_help']) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment