"""Index python module files' function and class definitions. $Author: Sholden $ $Date: 10/28/04 12:04p $ $Revision: 1 $ This code was placed in the public domain on 17 January, 2001 """ import sys, string, re, glob, os.path p = re.compile(r"([\t ]*)(def|class)\s*(\w+)\s*(.*):$") def slen(s, tlen=8): """Returns effective length of string, allowing for tabs of given length.""" r = 0 for c in s: if c == " ": r = r+1 elif c == "\t": r = ((r+tlen)/tlen)*tlen return r def process(filename): """Extract class, function and method definitions from a file. Returns a sortable list of references, each created by setof().""" lengths = [0] names = ["__main__"] types = ["builtin"] clen = 0 ll = open(filename).readlines() bname = os.path.basename(filename) r = [] for i in range(len(ll)): m = p.match(ll[i]) if m: s = slen(m.group(1)) if s > clen: clen = s types.append(None) names.append(None) elif s < clen: clen = s del types[-1] del names[-1] try: types[-1] = m.group(2) names[-1] = m.group(3) except KeyError: print "Impossible keyword:", m.group(2) r.append(setof(types, names, bname, i+1)) return r def setof(types, names, fn, i): """Produce a quintuple for a class/method/function reference. Value returned is (sort_name, name, type, line_number, filename).""" # print "###", types, types[-2:] if types[-2:] == ['class','def']: type = 'Method' name = '%s [%s]' % (names[-1], names[-2]) elif types[-1] == 'class': type = 'Class' name = names[-1] elif types[-1] == 'def': type = 'Function' name = names[-1] else: type = ' ???' name = names[-1] return (string.lower(name), name, type, i, fn) if len(sys.argv) == 1: print >> sys.stderr, """ Usage: python pyindex.py filespec [filespec ...] Wildcard file specifications are expanded """ sys.exit(-1) r = [] for pat in sys.argv[1:]: fn = glob.glob(pat) for f in fn: r = r + process(f) r.sort() for rr in r: print "%-8s %-40s %5d: %s" % (rr[2], rr[1], rr[3], rr[4])