Improve logging/printed output

Add in a verbose mode that uses logging to output more
information when available. Also adjusts the output to
show which checks had which errors (which is useful to
know and is useful in general) as well as show the total
number of errors accumulated (and the specific break
downs).

Change-Id: Ia965aa7c7c3576230668217aa09cf61dc4ecd303
This commit is contained in:
Joshua Harlow 2014-08-16 18:10:55 -07:00
parent 8ea62aff22
commit 0499ba81bd
2 changed files with 63 additions and 9 deletions

View File

@ -31,14 +31,18 @@ What is checked:
import argparse
import collections
import logging
import os
import sys
LOG = logging.getLogger(__name__)
if __name__ == '__main__':
# Only useful for when running directly (for dev/debugging).
sys.path.insert(0, os.path.abspath(os.getcwd()))
sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.getcwd())))
import six
from six.moves import configparser
from stevedore import extension
@ -97,6 +101,10 @@ def extract_config(args):
cfg['sphinx'] = parser.getboolean("doc8", "sphinx")
except (configparser.NoSectionError, configparser.NoOptionError):
pass
try:
cfg['verbose'] = parser.getboolean("doc8", "verbose")
except (configparser.NoSectionError, configparser.NoOptionError):
pass
try:
extensions = parser.get("doc8", "extensions")
extensions = extensions.split(",")
@ -127,6 +135,15 @@ def fetch_checks(cfg):
return base + addons
def setup_logging(verbose):
if verbose:
level = logging.DEBUG
else:
level = logging.ERROR
logging.basicConfig(level=level,
format='%(levelname)s: %(message)s', stream=sys.stdout)
def main():
parser = argparse.ArgumentParser(
prog='doc8',
@ -164,6 +181,8 @@ def main():
help="check file extensions of the given type"
" (default: %s)" % ", ".join(FILE_PATTERNS),
default=[])
parser.add_argument("-v", "--verbose", dest="verbose", action='store_true',
help="run in verbose mode", default=False)
args = vars(parser.parse_args())
args['ignore'] = merge_sets(args['ignore'])
cfg = extract_config(args)
@ -174,21 +193,33 @@ def main():
args.update(cfg)
if not args.get('extension'):
args['extension'] = list(FILE_PATTERNS)
setup_logging(args.get('verbose'))
files = collections.deque()
ignored_paths = []
for path in args.pop('ignore_path', []):
ignored_paths.append(os.path.normpath(path))
print("Scanning...")
for filename in utils.find_files(args.pop('paths', []),
args.pop('extension', []),
ignored_paths):
files.append(file_parser.parse(filename))
ignoreables = frozenset(args.pop('ignore', []))
errors = 0
error_counts = {}
while files:
f = files.popleft()
if args.get('verbose'):
print("Validating %s" % f)
for c in fetch_checks(args):
try:
# http://legacy.python.org/dev/peps/pep-3155/
check_name = c.__class__.__qualname__
except AttributeError:
check_name = ".".join([c.__class__.__module__,
c.__class__.__name__])
if args.get('verbose'):
print(" Running check '%s'" % check_name)
error_counts.setdefault(check_name, 0)
try:
reports = set(c.REPORTS)
except AttributeError:
@ -196,22 +227,40 @@ def main():
else:
reports = reports - ignoreables
if not reports:
LOG.debug("Skipping check '%s', determined to only"
" check ignoreable codes", check_name)
continue
if isinstance(c, checks.ContentCheck):
for line_num, code, message in c.report_iter(f):
print('%s:%s: %s %s'
% (f.filename, line_num, code, message))
errors += 1
if args.get('verbose'):
print(' - %s:%s: %s %s'
% (f.filename, line_num, code, message))
else:
print('%s:%s: %s %s'
% (f.filename, line_num, code, message))
error_counts[check_name] += 1
elif isinstance(c, checks.LineCheck):
for line_num, line in enumerate(f.lines_iter(), 1):
for code, message in c.report_iter(line):
print('%s:%s: %s %s'
% (f.filename, line_num, code, message))
errors += 1
if args.get('verbose'):
print(' - %s:%s: %s %s'
% (f.filename, line_num, code, message))
else:
print('%s:%s: %s %s'
% (f.filename, line_num, code, message))
error_counts[check_name] += 1
else:
raise TypeError("Unknown check type: %s, %s"
% (type(c), c))
if errors:
total_errors = sum(six.itervalues(error_counts))
print("=" * 8)
print("Total accumulated errors = %s" % total_errors)
if error_counts:
print("Detailed error counts:")
for check_name in sorted(six.iterkeys(error_counts)):
check_errors = error_counts[check_name]
print(" - %s = %s" % (check_name, check_errors))
if total_errors:
return 1
else:
return 0

View File

@ -99,6 +99,11 @@ class ParsedFile(object):
encoding=self.encoding)
return self._content
def __str__(self):
return "%s (%s, %s chars, %s lines)" % (
self.filename, self.encoding, len(self.contents),
len(list(self.lines_iter())))
def parse(filename, encoding="utf8"):
if not os.path.isfile(filename):