Allow checks to provide a extension matcher
When a check is for a rst file vs a plaintext file and is not interoperable this change allows that check to declare that it only knows how to scan certain files. It also fixes the max line checker to use a similar routine to differentiate between rst files and non rst files and uses a different routine based on this decision. Change-Id: I1e3e5f9f1631ed5babe2df17c987e8e872938a38
This commit is contained in:
parent
9b439777f4
commit
15ee57b572
@ -75,6 +75,7 @@ class CheckCarriageReturn(LineCheck):
|
|||||||
|
|
||||||
class CheckValidity(ContentCheck):
|
class CheckValidity(ContentCheck):
|
||||||
REPORTS = frozenset(["D000"])
|
REPORTS = frozenset(["D000"])
|
||||||
|
EXT_MATCHER = re.compile(r"(.*)[.]rst", re.I)
|
||||||
|
|
||||||
# Only used when running in sphinx mode.
|
# Only used when running in sphinx mode.
|
||||||
SPHINX_IGNORES_REGEX = [
|
SPHINX_IGNORES_REGEX = [
|
||||||
@ -107,6 +108,11 @@ class CheckValidity(ContentCheck):
|
|||||||
class CheckMaxLineLength(ContentCheck):
|
class CheckMaxLineLength(ContentCheck):
|
||||||
REPORTS = frozenset(["D001"])
|
REPORTS = frozenset(["D001"])
|
||||||
|
|
||||||
|
def __init__(self, cfg):
|
||||||
|
super(CheckMaxLineLength, self).__init__(cfg)
|
||||||
|
self._max_line_length = self._cfg['max_line_length']
|
||||||
|
self._allow_long_titles = self._cfg['allow_long_titles']
|
||||||
|
|
||||||
def _extract_node_lines(self, doc):
|
def _extract_node_lines(self, doc):
|
||||||
|
|
||||||
def extract_lines(node, start_line):
|
def extract_lines(node, start_line):
|
||||||
@ -185,10 +191,14 @@ class CheckMaxLineLength(ContentCheck):
|
|||||||
directives.append((i, find_directive_end(i, lines)))
|
directives.append((i, find_directive_end(i, lines)))
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def report_iter(self, parsed_file):
|
def _txt_checker(self, parsed_file):
|
||||||
doc = parsed_file.document
|
for i, line in enumerate(parsed_file.lines_iter()):
|
||||||
lines = list(parsed_file.lines_iter())
|
if len(line) > self._max_line_length:
|
||||||
|
yield (i + 1, 'D001', 'Line too long')
|
||||||
|
|
||||||
|
def _rst_checker(self, parsed_file):
|
||||||
|
lines = list(parsed_file.lines_iter())
|
||||||
|
doc = parsed_file.document
|
||||||
nodes_lines, first_line = self._extract_node_lines(doc)
|
nodes_lines, first_line = self._extract_node_lines(doc)
|
||||||
directives = self._extract_directives(lines)
|
directives = self._extract_directives(lines)
|
||||||
|
|
||||||
@ -225,10 +235,8 @@ class CheckMaxLineLength(ContentCheck):
|
|||||||
docutils_nodes.subtitle,
|
docutils_nodes.subtitle,
|
||||||
docutils_nodes.section,
|
docutils_nodes.section,
|
||||||
)
|
)
|
||||||
max_line_length = self._cfg['max_line_length']
|
|
||||||
allow_long_titles = self._cfg['allow_long_titles']
|
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
if len(line) > max_line_length:
|
if len(line) > self._max_line_length:
|
||||||
in_directive = False
|
in_directive = False
|
||||||
for (start, end) in directives:
|
for (start, end) in directives:
|
||||||
if i >= start and i <= end:
|
if i >= start and i <= end:
|
||||||
@ -245,6 +253,14 @@ class CheckMaxLineLength(ContentCheck):
|
|||||||
nodes = find_containing_nodes(i + 1)
|
nodes = find_containing_nodes(i + 1)
|
||||||
if any_types(nodes, skip_types):
|
if any_types(nodes, skip_types):
|
||||||
continue
|
continue
|
||||||
if allow_long_titles and any_types(nodes, title_types):
|
if self._allow_long_titles and any_types(nodes, title_types):
|
||||||
continue
|
continue
|
||||||
yield (i + 1, 'D001', 'Line too long')
|
yield (i + 1, 'D001', 'Line too long')
|
||||||
|
|
||||||
|
def report_iter(self, parsed_file):
|
||||||
|
if parsed_file.extension.lower() != '.rst':
|
||||||
|
checker_func = self._txt_checker
|
||||||
|
else:
|
||||||
|
checker_func = self._rst_checker
|
||||||
|
for issue in checker_func(parsed_file):
|
||||||
|
yield issue
|
||||||
|
10
doc8/main.py
10
doc8/main.py
@ -216,6 +216,16 @@ def main():
|
|||||||
check_name = ".".join([c.__class__.__module__,
|
check_name = ".".join([c.__class__.__module__,
|
||||||
c.__class__.__name__])
|
c.__class__.__name__])
|
||||||
error_counts.setdefault(check_name, 0)
|
error_counts.setdefault(check_name, 0)
|
||||||
|
try:
|
||||||
|
extension_matcher = c.EXT_MATCHER
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if not extension_matcher.match(f.extension):
|
||||||
|
print(" Skipping check '%s' since it does not understand"
|
||||||
|
" parsing a file with extension '%s'"
|
||||||
|
% (check_name, f.extension))
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
reports = set(c.REPORTS)
|
reports = set(c.REPORTS)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -33,6 +33,7 @@ class ParsedFile(object):
|
|||||||
self._encoding = encoding
|
self._encoding = encoding
|
||||||
self._doc = None
|
self._doc = None
|
||||||
self._errors = None
|
self._errors = None
|
||||||
|
self._extension = os.path.splitext(filename)[1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def errors(self):
|
def errors(self):
|
||||||
@ -76,6 +77,10 @@ class ParsedFile(object):
|
|||||||
line = line[0:-1]
|
line = line[0:-1]
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extension(self):
|
||||||
|
return self._extension
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self):
|
def filename(self):
|
||||||
return self._filename
|
return self._filename
|
||||||
|
@ -73,15 +73,16 @@ test
|
|||||||
content += "\n\n"
|
content += "\n\n"
|
||||||
content += ("a" * 60) + " " + ("b" * 60)
|
content += ("a" * 60) + " " + ("b" * 60)
|
||||||
content += "\n"
|
content += "\n"
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile() as fh:
|
|
||||||
fh.write(content)
|
|
||||||
fh.flush()
|
|
||||||
parsed_file = parser.ParsedFile(fh.name)
|
|
||||||
conf = {
|
conf = {
|
||||||
'max_line_length': 79,
|
'max_line_length': 79,
|
||||||
'allow_long_titles': True,
|
'allow_long_titles': True,
|
||||||
}
|
}
|
||||||
|
for ext in ['.rst', '.txt']:
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=ext) as fh:
|
||||||
|
fh.write(content)
|
||||||
|
fh.flush()
|
||||||
|
|
||||||
|
parsed_file = parser.ParsedFile(fh.name)
|
||||||
check = checks.CheckMaxLineLength(conf)
|
check = checks.CheckMaxLineLength(conf)
|
||||||
errors = list(check.report_iter(parsed_file))
|
errors = list(check.report_iter(parsed_file))
|
||||||
self.assertEqual(1, len(errors))
|
self.assertEqual(1, len(errors))
|
||||||
@ -102,15 +103,20 @@ test
|
|||||||
content += "\n\n"
|
content += "\n\n"
|
||||||
content += "a" * 100
|
content += "a" * 100
|
||||||
content += "\n"
|
content += "\n"
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile() as fh:
|
|
||||||
fh.write(content)
|
|
||||||
fh.flush()
|
|
||||||
parsed_file = parser.ParsedFile(fh.name)
|
|
||||||
conf = {
|
conf = {
|
||||||
'max_line_length': 79,
|
'max_line_length': 79,
|
||||||
'allow_long_titles': True,
|
'allow_long_titles': True,
|
||||||
}
|
}
|
||||||
|
# This number is different since rst parsing is aware that titles
|
||||||
|
# are allowed to be over-length, while txt parsing is not aware of
|
||||||
|
# this fact (since it has no concept of title sections).
|
||||||
|
extensions = [(0, '.rst'), (1, '.txt')]
|
||||||
|
for expected_errors, ext in extensions:
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=ext) as fh:
|
||||||
|
fh.write(content)
|
||||||
|
fh.flush()
|
||||||
|
|
||||||
|
parsed_file = parser.ParsedFile(fh.name)
|
||||||
check = checks.CheckMaxLineLength(conf)
|
check = checks.CheckMaxLineLength(conf)
|
||||||
errors = list(check.report_iter(parsed_file))
|
errors = list(check.report_iter(parsed_file))
|
||||||
self.assertEqual(0, len(errors))
|
self.assertEqual(expected_errors, len(errors))
|
||||||
|
Loading…
Reference in New Issue
Block a user