542 def find_cycles(imports): |
542 def find_cycles(imports): |
543 """Find cycles in an already-loaded import graph. |
543 """Find cycles in an already-loaded import graph. |
544 |
544 |
545 All module names recorded in `imports` should be absolute one. |
545 All module names recorded in `imports` should be absolute one. |
546 |
546 |
|
547 >>> from __future__ import print_function |
547 >>> imports = {'top.foo': ['top.bar', 'os.path', 'top.qux'], |
548 >>> imports = {'top.foo': ['top.bar', 'os.path', 'top.qux'], |
548 ... 'top.bar': ['top.baz', 'sys'], |
549 ... 'top.bar': ['top.baz', 'sys'], |
549 ... 'top.baz': ['top.foo'], |
550 ... 'top.baz': ['top.foo'], |
550 ... 'top.qux': ['top.foo']} |
551 ... 'top.qux': ['top.foo']} |
551 >>> print '\\n'.join(sorted(find_cycles(imports))) |
552 >>> print('\\n'.join(sorted(find_cycles(imports)))) |
552 top.bar -> top.baz -> top.foo -> top.bar |
553 top.bar -> top.baz -> top.foo -> top.bar |
553 top.foo -> top.qux -> top.foo |
554 top.foo -> top.qux -> top.foo |
554 """ |
555 """ |
555 cycles = set() |
556 cycles = set() |
556 for mod in sorted(imports.iterkeys()): |
557 for mod in sorted(imports.iterkeys()): |
582 src = f.read() |
583 src = f.read() |
583 used_imports[modname] = sorted( |
584 used_imports[modname] = sorted( |
584 imported_modules(src, modname, localmods, ignore_nested=True)) |
585 imported_modules(src, modname, localmods, ignore_nested=True)) |
585 for error, lineno in verify_import_convention(modname, src, localmods): |
586 for error, lineno in verify_import_convention(modname, src, localmods): |
586 any_errors = True |
587 any_errors = True |
587 print '%s:%d: %s' % (source_path, lineno, error) |
588 print('%s:%d: %s' % (source_path, lineno, error)) |
588 f.close() |
589 f.close() |
589 cycles = find_cycles(used_imports) |
590 cycles = find_cycles(used_imports) |
590 if cycles: |
591 if cycles: |
591 firstmods = set() |
592 firstmods = set() |
592 for c in sorted(cycles, key=_cycle_sortkey): |
593 for c in sorted(cycles, key=_cycle_sortkey): |
594 # As a rough cut, ignore any cycle that starts with the |
595 # As a rough cut, ignore any cycle that starts with the |
595 # same module as some other cycle. Otherwise we see lots |
596 # same module as some other cycle. Otherwise we see lots |
596 # of cycles that are effectively duplicates. |
597 # of cycles that are effectively duplicates. |
597 if first in firstmods: |
598 if first in firstmods: |
598 continue |
599 continue |
599 print 'Import cycle:', c |
600 print('Import cycle:', c) |
600 firstmods.add(first) |
601 firstmods.add(first) |
601 any_errors = True |
602 any_errors = True |
602 return any_errors != 0 |
603 return any_errors != 0 |
603 |
604 |
604 if __name__ == '__main__': |
605 if __name__ == '__main__': |