[chirp_devel] [PATCH 03/11] Add pylint support to cpep8 scripts (#159)
Zachary T Welch
Sun Mar 8 16:54:17 PDT 2015
# HG changeset patch
# User Zachary T Welch <zach at mandolincreekfarm.com>
# Fake Node ID 56fbb6a0b29a1cbbc1c3a5feeb4ce501f4cedc6e
Add pylint support to cpep8 scripts (#159)
The patch extends the cpep8 scripts to include pylint. Like pep8, it
imports the appropriate pylint modules and runs the checks in the same
python process. It uses the pylintrc file that was updated in the last
patch to control its behavior.
By default, it only checks files from the manifest that do not appear in
its blacklist (tools/cpep8.lintful). If --all is given, it scans all of
the files in the manifest.
It adds the --no-pep8 and --no-pylint options to limit manual testing to
one set of tests or the other. The new --no-color option may be useful
when the output is not a terminal (e.g. Jenkins).
The cpep8.sh script overrides the pylint save-state directory, putting
the statistics into tools/cpep.pylint.d/. As with the virtualenv files,
that directory can be overridden by setting TMPDIR.
Finally, it changes the verbose option to counting, so the pylint
reports for files with no errors are printed only when that option
appears twice.
diff --git a/.hgignore b/.hgignore
index 140091a..58a8f45 100644
--- a/.hgignore
+++ b/.hgignore
@@ -5,4 +5,5 @@
dist
build/bdist
tools/cpep8.venv/
+tools/cpep8.pylint.d/
tests/logs/
diff --git a/tools/cpep8.manifest b/tools/cpep8.lintful
similarity index 94%
copy from tools/cpep8.manifest
copy to tools/cpep8.lintful
index afeef1d..efb64b6 100644
--- a/tools/cpep8.manifest
+++ b/tools/cpep8.lintful
@@ -1,3 +1,6 @@
+# cpep8.lintful: The list of files that do not meet pylint standards.
+# DO NOT ADD NEW FILES!! Instead, fix the code to be compliant.
+# Over time, this list should shrink and (eventually) be eliminated.
./chirp/__init__.py
./chirp/bandplan.py
./chirp/bandplan_au.py
diff --git a/tools/cpep8.py b/tools/cpep8.py
index 2bf55d0..655a17f 100755
--- a/tools/cpep8.py
+++ b/tools/cpep8.py
@@ -21,6 +21,8 @@ import os
import sys
import logging
import argparse
+from pylint import lint, reporters
+from pylint.reporters import text
import pep8
parser = argparse.ArgumentParser()
@@ -28,6 +30,12 @@ parser.add_argument("-a", "--all", action="store_true",
help="Check all files, ignoring blacklist")
parser.add_argument("-d", "--dir", action="store", default=".",
help="Root directory of source tree")
+parser.add_argument("--no-color", action="store_true",
+ help="Do not colorize output")
+parser.add_argument("--no-pep8", action="store_true",
+ help="Do not run pep8 checks")
+parser.add_argument("--no-pylint", action="store_true",
+ help="Do not run pylint checks")
parser.add_argument("-s", "--stats", action="store_true",
help="Only show statistics")
parser.add_argument("--strict", action="store_true",
@@ -36,7 +44,7 @@ parser.add_argument("-S", "--scan", action="store_true",
help="Scan for additional files")
parser.add_argument("-u", "--update", action="store_true",
help="Update manifest/blacklist files")
-parser.add_argument("-v", "--verbose", action="store_true",
+parser.add_argument("-v", "--verbose", action="count", default=0,
help="Display list of checked files")
parser.add_argument("files", metavar="file", nargs='*',
help="List of files to check (if none, check all)")
@@ -55,6 +63,8 @@ scriptdir = os.path.dirname(sys.argv[0])
manifest_filename = os.path.join(scriptdir, "cpep8.manifest")
blacklist_filename = os.path.join(scriptdir, "cpep8.blacklist")
exceptions_filename = os.path.join(scriptdir, "cpep8.exceptions")
+lintful_filename = os.path.join(scriptdir, "cpep8.lintful")
+pylintrc_filename = os.path.join(scriptdir, "cpep8.pylintrc")
manifest = []
if args.scan:
@@ -89,24 +99,93 @@ def get_exceptions(f):
ignore = None
return ignore
+
+class SmartReporter(reporters.BaseReporter):
+ """A pylint reporter that normally pipes output to /dev/null."""
+
+ def __init__(self, update):
+ reporters.BaseReporter.__init__(self)
+ self.update = update
+ self.stats = {}
+ self.msgs = {}
+ self.queue = []
+ self.reporter = args.no_color and \
+ text.TextReporter() or \
+ text.ColorizedTextReporter()
+
+ def on_set_current_module(self, module, path):
+ self.reporter.linter = self.linter
+ self.reporter.on_set_current_module(module, path)
+
+ def handle_message(self, msg):
+ msg_id = msg.msg_id
+ if msg_id not in self.stats:
+ self.stats[msg_id] = 0
+ self.stats[msg_id] += 1
+
+ if msg_id not in self.msgs:
+ self.msgs[msg_id] = msg.msg
+
+ self.queue.append(msg)
+
+ def add_message(self, dummy1, dummy2, dummy3):
+ pass
+
+ def _display(self, layout):
+ show_report = args.verbose > 1 or \
+ ((not self.update or args.verbose) and
+ len(self.queue) > 0)
+ if show_report:
+ for msg in self.queue:
+ self.reporter.handle_message(msg)
+ self.reporter.display_results(layout)
+ if args.stats:
+ for msgid in sorted(self.stats.keys()):
+ print "%d %s: %s" % \
+ (self.stats[msgid], msgid, self.msgs[msgid])
+
+
if args.update:
print "Starting update of %d files" % len(manifest)
bad = []
+ lintful = []
for f in manifest:
checker = pep8.StyleGuide(quiet=True, ignore=get_exceptions(f))
results = checker.check_files([f])
if results.total_errors:
bad.append(f)
+
+ cmdline = [f, '--rcfile=%s' % pylintrc_filename]
+ reporter = SmartReporter(True)
+ runner = lint.Run(cmdline, reporter=reporter, exit=False)
+ if runner.linter.msg_status > 0:
+ results.total_errors += 1
+ lintful.append(f)
+
print "%s: %s" % (results.total_errors and "FAIL" or "PASS", f)
- with file(blacklist_filename, "w") as fh:
- print >>fh, """\
-# cpep8.blacklist: The list of files that do not meet PEP8 standards.
+ do_not_edit = """\
# DO NOT ADD NEW FILES!! Instead, fix the code to be compliant.
# Over time, this list should shrink and (eventually) be eliminated."""
- print >>fh, "\n".join(sorted(bad))
+
+ print "Updating %s" % blacklist_filename
+ with file(blacklist_filename, "w") as fh:
+ print >>fh, """\
+# cpep8.blacklist: The list of files that do not meet PEP8 standards."""
+ print >>fh, do_not_edit
+ if len(bad) > 0:
+ print >>fh, "\n".join(sorted(bad))
+
+ print "Updating %s" % lintful_filename
+ with file(lintful_filename, "w") as fh:
+ print >>fh, """\
+# cpep8.lintful: The list of files that do not meet pylint standards."""
+ print >>fh, do_not_edit
+ if len(lintful) > 0:
+ print >>fh, "\n".join(sorted(lintful))
if args.scan:
+ print "Updating %s" % manifest_filename
with file(manifest_filename, "w") as fh:
print >>fh, "\n".join(sorted(manifest))
sys.exit(0)
@@ -116,17 +195,22 @@ if args.files:
# read the blacklisted source files
blacklist = file_to_lines(blacklist_filename)
+lintful = file_to_lines(lintful_filename)
check_list = []
+lint_list = []
for f in manifest:
- if args.all or f not in blacklist:
+ if not args.no_pep8 and (args.all or f not in blacklist):
check_list.append(f)
+ if not args.no_pylint and (args.all or f not in lintful):
+ lint_list.append(f)
check_list = sorted(check_list)
+lint_list = sorted(lint_list)
total_errors = 0
for f in check_list:
if args.verbose:
- print "Checking %s" % f
+ print "pep8: checking %s" % f
checker = pep8.Checker(f, quiet=args.stats, ignore=get_exceptions(f))
results = checker.check_all()
@@ -134,4 +218,13 @@ for f in check_list:
checker.report.print_statistics()
total_errors += results
+for f in lint_list:
+ if args.verbose:
+ print "pylint: checking %s" % f
+ cmdline = [f, '--rcfile=%s' % pylintrc_filename]
+ reporter = SmartReporter(False)
+ runner = lint.Run(cmdline, reporter=reporter, exit=False)
+ if runner.linter.msg_status > 0:
+ total_errors += 1
+
sys.exit(total_errors and 1 or 0)
diff --git a/tools/cpep8.sh b/tools/cpep8.sh
index 89fd9ac..938c1c6 100755
--- a/tools/cpep8.sh
+++ b/tools/cpep8.sh
@@ -2,9 +2,11 @@
# Runs cpep.py with the proper verion of the pep8 library.
PEP8_VERSION="1.6.2"
+PYLINT_VERSION="1.4.1"
TOOLS_DIR="$(dirname $0)"
VENV="${TMPDIR:-${TOOLS_DIR}}/cpep8.venv"
+export PYLINTHOME="${TMPDIR:-${TOOLS_DIR}}/cpep8.pylint.d"
virtualenv="$(which virtualenv)"
if [ ! -x "$virtualenv" ]; then
@@ -13,9 +15,15 @@ if [ ! -x "$virtualenv" ]; then
fi
if [ ! -d "$VENV" ]; then
virtualenv "$VENV"
+ source ${VENV}/bin/activate
+ mkdir -p ${VENV}/logs
+ pip install pep8==${PEP8_VERSION} >${VENV}/logs/pep8.log 2>&1
+ pip install pylint==${PYLINT_VERSION} >${VENV}/logs/pylint.log 2>&1
+ pip install pyserial >${VENV}/logs/pyserial.log 2>&1
+ pip install pygtk >${VENV}/logs/pygtk.log 2>&1
+else
+ source ${VENV}/bin/activate
fi
-source ${VENV}/bin/activate
-pip install pep8==${PEP8_VERSION} >${VENV}/pep8.log 2>&1
${TOOLS_DIR}/cpep8.py "$@"
deactivate
More information about the chirp_devel
mailing list