cinap_lenrekadd hg and python4bb9e2215 years agoHistory
167 lines · 3.8 KB · Python
RawDownload
#! /usr/bin/env python # pdeps## Find dependencies between a bunch of Python modules.## Usage:#       pdeps file1.py file2.py ...## Output:# Four tables separated by lines like '--- Closure ---':# 1) Direct dependencies, listing which module imports which other modules# 2) The inverse of (1)# 3) Indirect dependencies, or the closure of the above# 4) The inverse of (3)## To do:# - command line options to select output type# - option to automatically scan the Python library for referenced modules# - option to limit output to particular modules  import sysimport reimport os  # Main program#def main():    args = sys.argv[1:]    if not args:        print 'usage: pdeps file.py file.py ...'        return 2    #    table = {}    for arg in args:        process(arg, table)    #    print '--- Uses ---'    printresults(table)    #    print '--- Used By ---'    inv = inverse(table)    printresults(inv)    #    print '--- Closure of Uses ---'    reach = closure(table)    printresults(reach)    #    print '--- Closure of Used By ---'    invreach = inverse(reach)    printresults(invreach)    #    return 0  # Compiled regular expressions to search for import statements#m_import = re.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+')m_from = re.compile('^[ \t]*import[ \t]+([^#]+)')  # Collect data from one file#def process(filename, table):    fp = open(filename, 'r')    mod = os.path.basename(filename)    if mod[-3:] == '.py':        mod = mod[:-3]    table[mod] = list = []    while 1:        line = fp.readline()        if not line: break        while line[-1:] == '\\':            nextline = fp.readline()            if not nextline: break            line = line[:-1] + nextline        if m_import.match(line) >= 0:            (a, b), (a1, b1) = m_import.regs[:2]        elif m_from.match(line) >= 0:            (a, b), (a1, b1) = m_from.regs[:2]        else: continue        words = line[a1:b1].split(',')        # print '#', line, words        for word in words:            word = word.strip()            if word not in list:                list.append(word)  # Compute closure (this is in fact totally general)#def closure(table):    modules = table.keys()    #    # Initialize reach with a copy of table    #    reach = {}    for mod in modules:        reach[mod] = table[mod][:]    #    # Iterate until no more change    #    change = 1    while change:        change = 0        for mod in modules:            for mo in reach[mod]:                if mo in modules:                    for m in reach[mo]:                        if m not in reach[mod]:                            reach[mod].append(m)                            change = 1    #    return reach  # Invert a table (this is again totally general).# All keys of the original table are made keys of the inverse,# so there may be empty lists in the inverse.#def inverse(table):    inv = {}    for key in table.keys():        if not inv.has_key(key):            inv[key] = []        for item in table[key]:            store(inv, item, key)    return inv  # Store "item" in "dict" under "key".# The dictionary maps keys to lists of items.# If there is no list for the key yet, it is created.#def store(dict, key, item):    if dict.has_key(key):        dict[key].append(item)    else:        dict[key] = [item]  # Tabulate results neatly#def printresults(table):    modules = table.keys()    maxlen = 0    for mod in modules: maxlen = max(maxlen, len(mod))    modules.sort()    for mod in modules:        list = table[mod]        list.sort()        print mod.ljust(maxlen), ':',        if mod in list:            print '(*)',        for ref in list:            print ref,        print  # Call main and honor exit statusif __name__ == '__main__':    try:        sys.exit(main())    except KeyboardInterrupt:        sys.exit(1)