PageRenderTime 53ms CodeModel.GetById 20ms app.highlight 12ms RepoModel.GetById 19ms app.codeStats 0ms

/Tools/scripts/pdeps.py

http://unladen-swallow.googlecode.com/
Python | 167 lines | 97 code | 19 blank | 51 comment | 44 complexity | effdbd5d0c43249ba34f702696d0858c MD5 | raw file
  1#! /usr/bin/env python
  2
  3# pdeps
  4#
  5# Find dependencies between a bunch of Python modules.
  6#
  7# Usage:
  8#       pdeps file1.py file2.py ...
  9#
 10# Output:
 11# Four tables separated by lines like '--- Closure ---':
 12# 1) Direct dependencies, listing which module imports which other modules
 13# 2) The inverse of (1)
 14# 3) Indirect dependencies, or the closure of the above
 15# 4) The inverse of (3)
 16#
 17# To do:
 18# - command line options to select output type
 19# - option to automatically scan the Python library for referenced modules
 20# - option to limit output to particular modules
 21
 22
 23import sys
 24import re
 25import os
 26
 27
 28# Main program
 29#
 30def main():
 31    args = sys.argv[1:]
 32    if not args:
 33        print 'usage: pdeps file.py file.py ...'
 34        return 2
 35    #
 36    table = {}
 37    for arg in args:
 38        process(arg, table)
 39    #
 40    print '--- Uses ---'
 41    printresults(table)
 42    #
 43    print '--- Used By ---'
 44    inv = inverse(table)
 45    printresults(inv)
 46    #
 47    print '--- Closure of Uses ---'
 48    reach = closure(table)
 49    printresults(reach)
 50    #
 51    print '--- Closure of Used By ---'
 52    invreach = inverse(reach)
 53    printresults(invreach)
 54    #
 55    return 0
 56
 57
 58# Compiled regular expressions to search for import statements
 59#
 60m_import = re.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+')
 61m_from = re.compile('^[ \t]*import[ \t]+([^#]+)')
 62
 63
 64# Collect data from one file
 65#
 66def process(filename, table):
 67    fp = open(filename, 'r')
 68    mod = os.path.basename(filename)
 69    if mod[-3:] == '.py':
 70        mod = mod[:-3]
 71    table[mod] = list = []
 72    while 1:
 73        line = fp.readline()
 74        if not line: break
 75        while line[-1:] == '\\':
 76            nextline = fp.readline()
 77            if not nextline: break
 78            line = line[:-1] + nextline
 79        if m_import.match(line) >= 0:
 80            (a, b), (a1, b1) = m_import.regs[:2]
 81        elif m_from.match(line) >= 0:
 82            (a, b), (a1, b1) = m_from.regs[:2]
 83        else: continue
 84        words = line[a1:b1].split(',')
 85        # print '#', line, words
 86        for word in words:
 87            word = word.strip()
 88            if word not in list:
 89                list.append(word)
 90
 91
 92# Compute closure (this is in fact totally general)
 93#
 94def closure(table):
 95    modules = table.keys()
 96    #
 97    # Initialize reach with a copy of table
 98    #
 99    reach = {}
100    for mod in modules:
101        reach[mod] = table[mod][:]
102    #
103    # Iterate until no more change
104    #
105    change = 1
106    while change:
107        change = 0
108        for mod in modules:
109            for mo in reach[mod]:
110                if mo in modules:
111                    for m in reach[mo]:
112                        if m not in reach[mod]:
113                            reach[mod].append(m)
114                            change = 1
115    #
116    return reach
117
118
119# Invert a table (this is again totally general).
120# All keys of the original table are made keys of the inverse,
121# so there may be empty lists in the inverse.
122#
123def inverse(table):
124    inv = {}
125    for key in table.keys():
126        if not inv.has_key(key):
127            inv[key] = []
128        for item in table[key]:
129            store(inv, item, key)
130    return inv
131
132
133# Store "item" in "dict" under "key".
134# The dictionary maps keys to lists of items.
135# If there is no list for the key yet, it is created.
136#
137def store(dict, key, item):
138    if dict.has_key(key):
139        dict[key].append(item)
140    else:
141        dict[key] = [item]
142
143
144# Tabulate results neatly
145#
146def printresults(table):
147    modules = table.keys()
148    maxlen = 0
149    for mod in modules: maxlen = max(maxlen, len(mod))
150    modules.sort()
151    for mod in modules:
152        list = table[mod]
153        list.sort()
154        print mod.ljust(maxlen), ':',
155        if mod in list:
156            print '(*)',
157        for ref in list:
158            print ref,
159        print
160
161
162# Call main and honor exit status
163if __name__ == '__main__':
164    try:
165        sys.exit(main())
166    except KeyboardInterrupt:
167        sys.exit(1)