Add options to definitions.py to fetch referrers and to output dot

This commit is contained in:
Mark Haines 2015-12-01 14:29:42 +00:00
parent c91a05776f
commit f593a6e5f8

View File

@ -79,16 +79,16 @@ def defined_names(prefix, defs, names):
defined_names(prefix + name + ".", funcs, names) defined_names(prefix + name + ".", funcs, names)
def used_names(prefix, defs, names): def used_names(prefix, item, defs, names):
for name, funcs in defs.get('def', {}).items(): for name, funcs in defs.get('def', {}).items():
used_names(prefix + name + ".", funcs, names) used_names(prefix + name + ".", name, funcs, names)
for name, funcs in defs.get('class', {}).items(): for name, funcs in defs.get('class', {}).items():
used_names(prefix + name + ".", funcs, names) used_names(prefix + name + ".", name, funcs, names)
for used in defs.get('uses', ()): for used in defs.get('uses', ()):
if used in names: if used in names:
names[used].setdefault('used', []).append(prefix.rstrip('.')) names[used].setdefault('used', {}).setdefault(item, []).append(prefix.rstrip('.'))
if __name__ == '__main__': if __name__ == '__main__':
@ -109,6 +109,14 @@ if __name__ == '__main__':
"directories", nargs='+', metavar="DIR", "directories", nargs='+', metavar="DIR",
help="Directories to search for definitions" help="Directories to search for definitions"
) )
parser.add_argument(
"--referrers", default=0, type=int,
help="Include referrers up to the given depth"
)
parser.add_argument(
"--format", default="yaml",
help="Output format, one of 'yaml' or 'dot'"
)
args = parser.parse_args() args = parser.parse_args()
definitions = {} definitions = {}
@ -124,7 +132,7 @@ if __name__ == '__main__':
defined_names(filepath + ":", defs, names) defined_names(filepath + ":", defs, names)
for filepath, defs in definitions.items(): for filepath, defs in definitions.items():
used_names(filepath + ":", defs, names) used_names(filepath + ":", None, defs, names)
patterns = [re.compile(pattern) for pattern in args.pattern or ()] patterns = [re.compile(pattern) for pattern in args.pattern or ()]
ignore = [re.compile(pattern) for pattern in args.ignore or ()] ignore = [re.compile(pattern) for pattern in args.ignore or ()]
@ -139,4 +147,29 @@ if __name__ == '__main__':
continue continue
result[name] = definition result[name] = definition
referrer_depth = args.referrers
referrers = set()
while referrer_depth:
referrer_depth -= 1
for entry in result.values():
for used_by in entry["used"]:
referrers.add(used_by)
for name, definition in names.items():
if not name in referrers:
continue
if ignore and any(pattern.match(name) for pattern in ignore):
continue
result[name] = definition
if args.format == 'yaml':
yaml.dump(result, sys.stdout, default_flow_style=False) yaml.dump(result, sys.stdout, default_flow_style=False)
elif args.format == 'dot':
print "digraph {"
for name, entry in result.items():
print name
for used_by in entry.get("used", ()):
if used_by in result:
print used_by, "->", name
print "}"
else:
raise ValueError("Unknown format %r" % (args.format))