contrib: import-graph creates smaller, more readable graph

This commit is contained in:
Wojtek Porczyk 2016-04-27 17:51:18 +02:00
parent 26fabe53aa
commit 044aefe25a

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import itertools
import os import os
import re import re
import sys import sys
@ -8,15 +9,20 @@ re_import = re.compile(r'^import (.*?)$', re.M)
re_import_from = re.compile(r'^from (.*?) import .*?$', re.M) re_import_from = re.compile(r'^from (.*?) import .*?$', re.M)
class Import(object): class Import(object):
style = 'arrowhead="open", arrowtail="none"' defstyle = {'arrowhead': 'open', 'arrowtail':'none'}
def __init__(self, importing, imported):
def __init__(self, importing, imported, **kwargs):
self.importing = importing self.importing = importing
self.imported = imported self.imported = imported
self.style = self.defstyle.copy()
self.style.update(kwargs)
def __str__(self): def __str__(self):
return '{}"{}" -> "{}" [{}];'.format( return '{}"{}" -> "{}" [{}];'.format(
('#' if self.commented else ''), ('//' if self.commented else ''),
self.importing, self.imported, self.style) self.importing,
self.imported,
', '.join('{}="{}"'.format(*i) for i in self.style.items()))
def __eq__(self, other): def __eq__(self, other):
return (self.importing.name, self.imported.name) \ return (self.importing.name, self.imported.name) \
@ -27,13 +33,11 @@ class Import(object):
@property @property
def commented(self): def commented(self):
for i in (self.importing, self.imported): if self.style.get('color', '') != 'red':
if i.name.startswith('qubes.tests'): return True return True
if i.name.startswith('qubes.tools'): return True # for i in (self.importing, self.imported):
# if i.name.startswith('qubes.tests'): return True
# if i.name.startswith('qubes.tools'): return True
class ImportFrom(Import):
style = 'arrowhead="open", arrowtail="none", color="red"'
class Module(set): class Module(set):
@ -58,7 +62,13 @@ class Module(set):
imported = self.package[imported] imported = self.package[imported]
except KeyError: except KeyError:
continue continue
self.add(ImportFrom(self, imported)) self.add(Import(self, imported, style='dotted'))
def __getitem__(self, key):
for i in self:
if i.imported == key:
return i
raise KeyError(key)
@property @property
def name(self): def name(self):
@ -157,11 +167,14 @@ rankdir=BT
def main(): def main():
package = Package(sys.argv[1]) package = Package(sys.argv[1])
sys.stdout.write(str(package))
for cycle in package.find_cycles(): for cycle in package.find_cycles():
for i in range(len(cycle) - 1):
edge = cycle[i][cycle[i+1]]
edge.style['color'] = 'red'
sys.stderr.write(' -> '.join(str(module) for module in cycle) + '\n') sys.stderr.write(' -> '.join(str(module) for module in cycle) + '\n')
sys.stdout.write(str(package))
if __name__ == '__main__': if __name__ == '__main__':
main() main()