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:
parent
8ea62aff22
commit
0499ba81bd
67
doc8/main.py
67
doc8/main.py
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue