SHARE
TWEET

CH

a guest Feb 15th, 2010 4,014 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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()
RAW Paste Data
Pastebin PRO Summer Special!
Get 60% OFF on Pastebin PRO accounts!
Top