Advertisement
Guest User

CH

a guest
Feb 15th, 2010
4,151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.09 KB | None | 0 0
  1.     import os
  2.     import re
  3.     import sys
  4.  
  5.     from subprocess import Popen, PIPE
  6.  
  7.  
  8.     class LintRunner(object):
  9.         """ Base class provides common functionality to run
  10.              python code checkers. """
  11.  
  12.         sane_default_ignore_codes = set([])
  13.         command = None
  14.         output_matcher = None
  15.  
  16.         #flymake: ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
  17.         #or in non-retardate: r'(.*) at ([^ \n]) line ([0-9])[,.\n]'
  18.         output_format = "%(level)s %(error_type)s%(error_number)s:" \
  19.                         "%(description)s at %(filename)s line %(line_number)s."
  20.  
  21.         def __init__(self, virtualenv=None, ignore_codes=(),
  22.                      use_sane_defaults=True):
  23.             if virtualenv:
  24.                 # This is the least we can get away with (hopefully).
  25.                 self.env = {'VIRTUAL_ENV': virtualenv,
  26.                             'PATH': virtualenv + '/bin:' + os.environ['PATH']}
  27.             else:
  28.                 self.env = None
  29.  
  30.             self.virtualenv = virtualenv
  31.             self.ignore_codes = set(ignore_codes)
  32.             self.use_sane_defaults = use_sane_defaults
  33.  
  34.         @property
  35.         def operative_ignore_codes(self):
  36.             if self.use_sane_defaults:
  37.                 return self.ignore_codes ^ self.sane_default_ignore_codes
  38.             else:
  39.                 return self.ignore_codes
  40.  
  41.         @property
  42.         def run_flags(self):
  43.             return ()
  44.  
  45.         @classmethod
  46.         def fixup_data(cls, line, data):
  47.             return data
  48.  
  49.         @classmethod
  50.         def process_output(cls, line):
  51.             m = cls.output_matcher.match(line)
  52.             if m:
  53.                 fixed_data = dict.fromkeys(('level', 'error_type',
  54.                                             'error_number', 'description',
  55.                                             'filename', 'line_number'),
  56.                                            '')
  57.                 fixed_data.update(cls.fixup_data(line, m.groupdict()))
  58.                 print cls.output_format % fixed_data
  59.  
  60.         def run(self, filename):
  61.             args = [self.command]
  62.             args.extend(self.run_flags)
  63.             args.append(filename)
  64.  
  65.             process = Popen(args, stdout=PIPE, stderr=PIPE, env=self.env)
  66.  
  67.             for line in process.stdout:
  68.                 self.process_output(line)
  69.  
  70.  
  71.     class PylintRunner(LintRunner):
  72.         """ Run pylint, producing flymake readable output.
  73.  
  74.        The raw output looks like:
  75.          render.py:49: [C0301] Line too long (82/80)
  76.          render.py:1: [C0111] Missing docstring
  77.          render.py:3: [E0611] No name 'Response' in module 'werkzeug'
  78.          render.py:32: [C0111, render] Missing docstring """
  79.  
  80.         output_matcher = re.compile(
  81.             r'(?P<filename>[^:]+):'
  82.             r'(?P<line_number>\d+):'
  83.             r'\s*\[(?P<error_type>[WECR])(?P<error_number>[^,]+),'
  84.             r'\s*(?P<context>[^\]]+)\]'
  85.             r'\s*(?P<description>.*)$')
  86.  
  87.         command = 'pylint'
  88.         sane_default_ignore_codes = set([
  89.             "C0103",  # Naming convention
  90.             "C0111",  # Missing Docstring
  91.             "E1002",  # Use super on old-style class
  92.             "W0232",  # No __init__
  93.             #"I0011",  # Warning locally suppressed using disable-msg
  94.             #"I0012",  # Warning locally suppressed using disable-msg
  95.             #"W0511",  # FIXME/TODO
  96.             #"W0142",  # *args or **kwargs magic.
  97.             "R0904",  # Too many public methods
  98.             "R0903",  # Too few public methods        
  99.             "R0201",  # Method could be a function
  100.             ])
  101.  
  102.         @classmethod
  103.         def fixup_data(cls, line, data):
  104.             if data['error_type'].startswith('E'):
  105.                 data['level'] = 'ERROR'
  106.             else:
  107.                 data['level'] = 'WARNING'
  108.             return data
  109.  
  110.         @property
  111.         def run_flags(self):
  112.             return ('--output-format', 'parseable',
  113.                     '--include-ids', 'y',
  114.                     '--reports', 'n',
  115.                     '--disable-msg=' + ','.join(self.operative_ignore_codes))
  116.  
  117.  
  118.     class PycheckerRunner(LintRunner):
  119.         """ Run pychecker, producing flymake readable output.
  120.  
  121.        The raw output looks like:
  122.          render.py:49: Parameter (maptype) not used
  123.          render.py:49: Parameter (markers) not used
  124.          render.py:49: Parameter (size) not used
  125.          render.py:49: Parameter (zoom) not used """
  126.  
  127.         command = 'pychecker'
  128.  
  129.         output_matcher = re.compile(
  130.             r'(?P<filename>[^:]+):'
  131.             r'(?P<line_number>\d+):'
  132.             r'\s+(?P<description>.*)$')
  133.  
  134.         @classmethod
  135.         def fixup_data(cls, line, data):
  136.             #XXX: doesn't seem to give the level
  137.             data['level'] = 'WARNING'
  138.             return data
  139.  
  140.         @property
  141.         def run_flags(self):
  142.             return '--no-deprecated', '-0186', '--only', '-#0'
  143.  
  144.  
  145.     class Pep8Runner(LintRunner):
  146.         """ Run pep8.py, producing flymake readable output.
  147.  
  148.        The raw output looks like:
  149.          spiders/structs.py:3:80: E501 line too long (80 characters)
  150.          spiders/structs.py:7:1: W291 trailing whitespace
  151.          spiders/structs.py:25:33: W602 deprecated form of raising exception
  152.          spiders/structs.py:51:9: E301 expected 1 blank line, found 0 """
  153.  
  154.         command = 'pep8.py'
  155.         # sane_default_ignore_codes = set([
  156.         #     'RW29', 'W391',
  157.         #     'W291', 'WO232'])
  158.  
  159.         output_matcher = re.compile(
  160.             r'(?P<filename>[^:]+):'
  161.             r'(?P<line_number>[^:]+):'
  162.             r'[^:]+:'
  163.             r' (?P<error_number>\w+) '
  164.             r'(?P<description>.+)$')
  165.  
  166.         @classmethod
  167.         def fixup_data(cls, line, data):
  168.             if 'W' in data['error_number']:
  169.                 data['level'] = 'WARNING'
  170.             else:
  171.                 data['level'] = 'ERROR'
  172.  
  173.             return data
  174.  
  175.         @property
  176.         def run_flags(self):
  177.             return '--repeat', '--ignore=' + ','.join(self.ignore_codes)
  178.  
  179.  
  180.     if __name__ == '__main__':
  181.         from optparse import OptionParser
  182.         parser = OptionParser()
  183.         parser.add_option("-e", "--virtualenv",
  184.                           dest="virtualenv",
  185.                           default=None,
  186.                           help="virtualenv directory")
  187.         parser.add_option("-i", "--ignore_codes",
  188.                           dest="ignore_codes",
  189.                           default=(),
  190.                           help="error codes to ignore")
  191.         options, args = parser.parse_args()
  192.  
  193.         pylint = PylintRunner(virtualenv=options.virtualenv,
  194.                               ignore_codes=options.ignore_codes)
  195.         pylint.run(args[0])
  196.  
  197.         pychecker = PycheckerRunner(virtualenv=options.virtualenv,
  198.                                     ignore_codes=options.ignore_codes)
  199.         pychecker.run(args[0])
  200.  
  201.         pep8 = Pep8Runner(virtualenv=options.virtualenv,
  202.                           ignore_codes=options.ignore_codes)
  203.         pep8.run(args[0])
  204.         sys.exit()
  205.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement