| 
									
										
										
										
											1996-11-27 19:52:01 +00:00
										 |  |  | #! /usr/bin/env python | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # 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 sys | 
					
						
							| 
									
										
										
										
											1992-12-10 00:00:58 +00:00
										 |  |  | import regex | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | import string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # 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 | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											1992-12-10 00:00:58 +00:00
										 |  |  | m_import = regex.compile('^[ \t]*from[ \t]+\([^ \t]+\)[ \t]+') | 
					
						
							|  |  |  | m_from = regex.compile('^[ \t]*import[ \t]+\([^#]+\)') | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Collect data from one file | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def process(filename, table): | 
					
						
							|  |  |  | 	fp = open(filename, 'r') | 
					
						
							| 
									
										
										
										
											1992-12-10 00:00:58 +00:00
										 |  |  | 	mod = os.path.basename(filename) | 
					
						
							| 
									
										
										
										
											1992-01-01 19:35:13 +00:00
										 |  |  | 	if mod[-3:] == '.py': | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | 		mod = mod[:-3] | 
					
						
							|  |  |  | 	table[mod] = list = [] | 
					
						
							|  |  |  | 	while 1: | 
					
						
							|  |  |  | 		line = fp.readline() | 
					
						
							|  |  |  | 		if not line: break | 
					
						
							| 
									
										
										
										
											1992-01-01 19:35:13 +00:00
										 |  |  | 		while line[-1:] == '\\': | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | 			nextline = fp.readline() | 
					
						
							|  |  |  | 			if not nextline: break | 
					
						
							|  |  |  | 			line = line[:-1] + nextline | 
					
						
							| 
									
										
										
										
											1992-12-10 00:00:58 +00:00
										 |  |  | 		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 = string.splitfields(line[a1:b1], ',') | 
					
						
							|  |  |  | 		# print '#', line, words | 
					
						
							|  |  |  | 		for word in words: | 
					
						
							|  |  |  | 			word = string.strip(word) | 
					
						
							|  |  |  | 			if word not in list: | 
					
						
							|  |  |  | 				list.append(word) | 
					
						
							| 
									
										
										
										
											1991-06-04 20:36:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # 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 string.ljust(mod, maxlen), ':', | 
					
						
							|  |  |  | 		if mod in list: | 
					
						
							|  |  |  | 			print '(*)', | 
					
						
							|  |  |  | 		for ref in list: | 
					
						
							|  |  |  | 			print ref, | 
					
						
							|  |  |  | 		print | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Call main and honor exit status | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  | 	sys.exit(main()) | 
					
						
							|  |  |  | except KeyboardInterrupt: | 
					
						
							|  |  |  | 	sys.exit(1) |