| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | 
							- #!/usr/bin/env python
 
- from __future__ import absolute_import
 
- from __future__ import with_statement
 
- import os
 
- import pprint
 
- import re
 
- import sys
 
- from collections import defaultdict
 
- from itertools import starmap
 
- from unipath import Path
 
- RE_COMMENT = r'^\s*\#'
 
- RE_NOQA = r'.+?\#\s+noqa+'
 
- RE_MULTILINE_COMMENT_O = r'^\s*(?:\'\'\'|""").+?(?:\'\'\'|""")'
 
- RE_MULTILINE_COMMENT_S = r'^\s*(?:\'\'\'|""")'
 
- RE_MULTILINE_COMMENT_E = r'(?:^|.+?)(?:\'\'\'|""")'
 
- RE_WITH = r'(?:^|\s+)with\s+'
 
- RE_WITH_IMPORT = r'''from\s+ __future__\s+ import\s+ with_statement'''
 
- RE_PRINT = r'''(?:^|\s+)print\((?:"|')(?:\W+?)?[A-Z0-9:]{2,}'''
 
- RE_ABS_IMPORT = r'''from\s+ __future__\s+ import\s+ absolute_import'''
 
- acc = defaultdict(lambda: {"abs": False, "print": False})
 
- def compile(regex):
 
-     return re.compile(regex, re.VERBOSE)
 
- class FlakePP(object):
 
-     re_comment = compile(RE_COMMENT)
 
-     re_ml_comment_o = compile(RE_MULTILINE_COMMENT_O)
 
-     re_ml_comment_s = compile(RE_MULTILINE_COMMENT_S)
 
-     re_ml_comment_e = compile(RE_MULTILINE_COMMENT_E)
 
-     re_abs_import = compile(RE_ABS_IMPORT)
 
-     re_print = compile(RE_PRINT)
 
-     re_with_import = compile(RE_WITH_IMPORT)
 
-     re_with = compile(RE_WITH)
 
-     re_noqa = compile(RE_NOQA)
 
-     map = {"abs": False, "print": False,
 
-             "with": False, "with-used": False}
 
-     def __init__(self, verbose=False):
 
-         self.verbose = verbose
 
-         self.steps = (("abs", self.re_abs_import),
 
-                       ("with", self.re_with_import),
 
-                       ("with-used", self.re_with),
 
-                       ("print", self.re_print))
 
-     def analyze_fh(self, fh):
 
-         steps = self.steps
 
-         filename = fh.name
 
-         acc = dict(self.map)
 
-         index = 0
 
-         errors = [0]
 
-         def error(fmt, **kwargs):
 
-             errors[0] += 1
 
-             self.announce(fmt, **dict(kwargs, filename=filename))
 
-         for index, line in enumerate(self.strip_comments(fh)):
 
-             for key, pattern in self.steps:
 
-                 if pattern.match(line):
 
-                     acc[key] = True
 
-         if index:
 
-             if not acc["abs"]:
 
-                 error("%(filename)s: missing abs import")
 
-             if acc["with-used"] and not acc["with"]:
 
-                 error("%(filename)s: missing with import")
 
-             if acc["print"]:
 
-                 error("%(filename)s: left over print statement")
 
-         return filename, errors[0], acc
 
-     def analyze_file(self, filename):
 
-         with open(filename) as fh:
 
-             return self.analyze_fh(fh)
 
-     def analyze_tree(self, dir):
 
-         for dirpath, _, filenames in os.walk(dir):
 
-             for path in (Path(dirpath, f) for f in filenames):
 
-                 if path.endswith(".py"):
 
-                     yield self.analyze_file(path)
 
-     def analyze(self, *paths):
 
-         for path in map(Path, paths):
 
-             if path.isdir():
 
-                 for res in self.analyze_tree(path):
 
-                     yield res
 
-             else:
 
-                 yield self.analyze_file(path)
 
-     def strip_comments(self, fh):
 
-         re_comment = self.re_comment
 
-         re_ml_comment_o = self.re_ml_comment_o
 
-         re_ml_comment_s = self.re_ml_comment_s
 
-         re_ml_comment_e = self.re_ml_comment_e
 
-         re_noqa = self.re_noqa
 
-         in_ml = False
 
-         for line in fh.readlines():
 
-             if in_ml:
 
-                 if re_ml_comment_e.match(line):
 
-                     in_ml = False
 
-             else:
 
-                 if re_noqa.match(line) or re_ml_comment_o.match(line):
 
-                     pass
 
-                 elif re_ml_comment_s.match(line):
 
-                     in_ml = True
 
-                 elif re_comment.match(line):
 
-                     pass
 
-                 else:
 
-                     yield line
 
-     def announce(self, fmt, **kwargs):
 
-         sys.stderr.write((fmt + "\n") % kwargs)
 
- def main(argv=sys.argv, exitcode=0):
 
-     for _, errors, _ in FlakePP(verbose=True).analyze(*argv[1:]):
 
-         if errors:
 
-             exitcode = 1
 
-     return exitcode
 
- if __name__ == "__main__":
 
-     sys.exit(main())
 
 
  |