##// END OF EJS Templates
import-checker: parse python code from .t files
timeless -
r28922:4ec62a08 default
parent child Browse files
Show More
@@ -5,6 +5,7 from __future__ import absolute_import,
5 import ast
5 import ast
6 import collections
6 import collections
7 import os
7 import os
8 import re
8 import sys
9 import sys
9
10
10 # Import a minimal set of stdlib modules needed for list_stdlib_modules()
11 # Import a minimal set of stdlib modules needed for list_stdlib_modules()
@@ -568,10 +569,97 def find_cycles(imports):
568 def _cycle_sortkey(c):
569 def _cycle_sortkey(c):
569 return len(c), c
570 return len(c), c
570
571
572 def embedded(f, modname, src):
573 """Extract embedded python code
574
575 >>> def test(fn, lines):
576 ... for s, m, f, l in embedded(fn, "example", lines):
577 ... print("%s %s %s" % (m, f, l))
578 ... print(repr(s))
579 >>> lines = [
580 ... 'comment',
581 ... ' >>> from __future__ import print_function',
582 ... " >>> ' multiline",
583 ... " ... string'",
584 ... ' ',
585 ... 'comment',
586 ... ' $ cat > foo.py <<EOF',
587 ... ' > from __future__ import print_function',
588 ... ' > EOF',
589 ... ]
590 >>> test("example.t", lines)
591 example[2] doctest.py 2
592 "from __future__ import print_function\\n' multiline\\nstring'\\n"
593 example[7] foo.py 7
594 'from __future__ import print_function\\n'
595 """
596 inlinepython = 0
597 shpython = 0
598 script = []
599 prefix = 6
600 t = ''
601 n = 0
602 for l in src:
603 n += 1
604 if not l.endswith(b'\n'):
605 l += b'\n'
606 if l.startswith(b' >>> '): # python inlines
607 if shpython:
608 print("%s:%d: Parse Error" % (f, n))
609 if not inlinepython:
610 # We've just entered a Python block.
611 inlinepython = n
612 t = 'doctest.py'
613 script.append(l[prefix:])
614 continue
615 if l.startswith(b' ... '): # python inlines
616 script.append(l[prefix:])
617 continue
618 cat = re.search(r"\$ \s*cat\s*>\s*(\S+\.py)\s*<<\s*EOF", l)
619 if cat:
620 if inlinepython:
621 yield ''.join(script), ("%s[%d]" %
622 (modname, inlinepython)), t, inlinepython
623 script = []
624 inlinepython = 0
625 shpython = n
626 t = cat.group(1)
627 continue
628 if shpython and l.startswith(b' > '): # sh continuation
629 if l == b' > EOF\n':
630 yield ''.join(script), ("%s[%d]" %
631 (modname, shpython)), t, shpython
632 script = []
633 shpython = 0
634 else:
635 script.append(l[4:])
636 continue
637 if inlinepython and l == b' \n':
638 yield ''.join(script), ("%s[%d]" %
639 (modname, inlinepython)), t, inlinepython
640 script = []
641 inlinepython = 0
642 continue
643
571 def sources(f, modname):
644 def sources(f, modname):
645 """Yields possibly multiple sources from a filepath
646
647 input: filepath, modulename
648 yields: script(string), modulename, filepath, linenumber
649
650 For embedded scripts, the modulename and filepath will be different
651 from the function arguments. linenumber is an offset relative to
652 the input file.
653 """
654 py = False
572 if f.endswith('.py'):
655 if f.endswith('.py'):
573 with open(f) as src:
656 with open(f) as src:
574 yield src.read(), modname
657 yield src.read(), modname, f, 0
658 py = True
659 if py or f.endswith('.t'):
660 with open(f) as src:
661 for script, modname, t, line in embedded(f, modname, src):
662 yield script, modname, t, line
575
663
576 def main(argv):
664 def main(argv):
577 if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2):
665 if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2):
@@ -587,18 +675,18 def main(argv):
587 modname = dotted_name_of_path(source_path, trimpure=True)
675 modname = dotted_name_of_path(source_path, trimpure=True)
588 localmods[modname] = source_path
676 localmods[modname] = source_path
589 for localmodname, source_path in sorted(localmods.items()):
677 for localmodname, source_path in sorted(localmods.items()):
590 for src, modname in sources(source_path, localmodname):
678 for src, modname, name, line in sources(source_path, localmodname):
591 try:
679 try:
592 used_imports[modname] = sorted(
680 used_imports[modname] = sorted(
593 imported_modules(src, modname, source_path, localmods,
681 imported_modules(src, modname, name, localmods,
594 ignore_nested=True))
682 ignore_nested=True))
595 for error, lineno in verify_import_convention(modname, src,
683 for error, lineno in verify_import_convention(modname, src,
596 localmods):
684 localmods):
597 any_errors = True
685 any_errors = True
598 print('%s:%d: %s' % (source_path, lineno, error))
686 print('%s:%d: %s' % (source_path, lineno + line, error))
599 except SyntaxError as e:
687 except SyntaxError as e:
600 print('%s:%d: SyntaxError: %s' %
688 print('%s:%d: SyntaxError: %s' %
601 (source_path, e.lineno, e))
689 (source_path, e.lineno + line, e))
602 cycles = find_cycles(used_imports)
690 cycles = find_cycles(used_imports)
603 if cycles:
691 if cycles:
604 firstmods = set()
692 firstmods = set()
General Comments 0
You need to be logged in to leave comments. Login now