mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-15 16:49:52 +00:00
Refactor Error formatting and handling
This allows us to handle --show-source in our formatters by default. This also adds the physical line information to the Error class instead of passing it to is_inline_ignored. This allows us to avoid using linecache in our formatters.
This commit is contained in:
parent
8300e0f97c
commit
467672fc5c
3 changed files with 54 additions and 17 deletions
|
|
@ -55,8 +55,9 @@ class BaseFormatter(object):
|
||||||
def handle(self, error):
|
def handle(self, error):
|
||||||
"""Handle an error reported by Flake8.
|
"""Handle an error reported by Flake8.
|
||||||
|
|
||||||
This defaults to calling :meth:`format` and then :meth:`write`. To
|
This defaults to calling :meth:`format`, :meth:`format_source`, and
|
||||||
extend how errors are handled, override this method.
|
then :meth:`write`. To extend how errors are handled, override this
|
||||||
|
method.
|
||||||
|
|
||||||
:param error:
|
:param error:
|
||||||
This will be an instance of :class:`~flake8.style_guide.Error`.
|
This will be an instance of :class:`~flake8.style_guide.Error`.
|
||||||
|
|
@ -64,7 +65,8 @@ class BaseFormatter(object):
|
||||||
flake8.style_guide.Error
|
flake8.style_guide.Error
|
||||||
"""
|
"""
|
||||||
line = self.format(error)
|
line = self.format(error)
|
||||||
self.write(line)
|
source = self.format_source(error)
|
||||||
|
self.write(line, source)
|
||||||
|
|
||||||
def format(self, error):
|
def format(self, error):
|
||||||
"""Format an error reported by Flake8.
|
"""Format an error reported by Flake8.
|
||||||
|
|
@ -83,7 +85,26 @@ class BaseFormatter(object):
|
||||||
raise NotImplementedError('Subclass of BaseFormatter did not implement'
|
raise NotImplementedError('Subclass of BaseFormatter did not implement'
|
||||||
' format.')
|
' format.')
|
||||||
|
|
||||||
def write(self, line):
|
def format_source(self, error):
|
||||||
|
"""Format the physical line generating the error.
|
||||||
|
|
||||||
|
:param error:
|
||||||
|
This will be an instance of :class:`~flake8.style_guide.Error`.
|
||||||
|
:returns:
|
||||||
|
The formatted error string if the user wants to show the source.
|
||||||
|
If the user does not want to show the source, this will return
|
||||||
|
``None``.
|
||||||
|
:rtype:
|
||||||
|
str
|
||||||
|
"""
|
||||||
|
if not self.options.show_source:
|
||||||
|
return None
|
||||||
|
pointer = (' ' * error.column_number) + '^'
|
||||||
|
# Physical lines have a newline at the end, no need to add an extra
|
||||||
|
# one
|
||||||
|
return error.physical_line + pointer
|
||||||
|
|
||||||
|
def write(self, line, source):
|
||||||
"""Write the line either to the output file or stdout.
|
"""Write the line either to the output file or stdout.
|
||||||
|
|
||||||
This handles deciding whether to write to a file or print to standard
|
This handles deciding whether to write to a file or print to standard
|
||||||
|
|
@ -94,9 +115,14 @@ class BaseFormatter(object):
|
||||||
The formatted string to print or write.
|
The formatted string to print or write.
|
||||||
"""
|
"""
|
||||||
if self.output_fd is not None:
|
if self.output_fd is not None:
|
||||||
self.output_fd.write(line + self.newline)
|
write = self.output_fd.write
|
||||||
|
output_func = lambda line: write(line + self.newline)
|
||||||
else:
|
else:
|
||||||
print(line)
|
output_func = print
|
||||||
|
|
||||||
|
output_func(line)
|
||||||
|
if source:
|
||||||
|
output_func(source)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Clean up after reporting is finished."""
|
"""Clean up after reporting is finished."""
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,17 @@ class Decision(enum.Enum):
|
||||||
Selected = 'selected error'
|
Selected = 'selected error'
|
||||||
|
|
||||||
|
|
||||||
Error = collections.namedtuple('Error', ['code',
|
Error = collections.namedtuple(
|
||||||
'filename',
|
'Error',
|
||||||
'line_number',
|
[
|
||||||
'column_number',
|
'code',
|
||||||
'text'])
|
'filename',
|
||||||
|
'line_number',
|
||||||
|
'column_number',
|
||||||
|
'text',
|
||||||
|
'physical_line',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StyleGuide(object):
|
class StyleGuide(object):
|
||||||
|
|
@ -157,9 +163,10 @@ class StyleGuide(object):
|
||||||
LOG.debug('"%s" will be "%s"', code, decision)
|
LOG.debug('"%s" will be "%s"', code, decision)
|
||||||
return decision
|
return decision
|
||||||
|
|
||||||
def is_inline_ignored(self, error, physical_line=None):
|
def is_inline_ignored(self, error):
|
||||||
# type: (Error) -> bool
|
# type: (Error) -> bool
|
||||||
"""Determine if an comment has been added to ignore this line."""
|
"""Determine if an comment has been added to ignore this line."""
|
||||||
|
physical_line = error.physical_line
|
||||||
# TODO(sigmavirus24): Determine how to handle stdin with linecache
|
# TODO(sigmavirus24): Determine how to handle stdin with linecache
|
||||||
if self.options.disable_noqa:
|
if self.options.disable_noqa:
|
||||||
return False
|
return False
|
||||||
|
|
@ -191,9 +198,10 @@ class StyleGuide(object):
|
||||||
physical_line=None):
|
physical_line=None):
|
||||||
# type: (str, str, int, int, str) -> NoneType
|
# type: (str, str, int, int, str) -> NoneType
|
||||||
"""Handle an error reported by a check."""
|
"""Handle an error reported by a check."""
|
||||||
error = Error(code, filename, line_number, column_number, text)
|
error = Error(code, filename, line_number, column_number, text,
|
||||||
|
physical_line)
|
||||||
if (self.should_report_error(error.code) is Decision.Selected and
|
if (self.should_report_error(error.code) is Decision.Selected and
|
||||||
self.is_inline_ignored(error, physical_line) is False):
|
self.is_inline_ignored(error) is False):
|
||||||
self.formatter.handle(error)
|
self.formatter.handle(error)
|
||||||
self.listener.notify(error.code, error)
|
self.listener.notify(error.code, error)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,8 @@ def test_is_inline_ignored(error_code, physical_line, expected_result):
|
||||||
guide = style_guide.StyleGuide(create_options(select=['E', 'W', 'F']),
|
guide = style_guide.StyleGuide(create_options(select=['E', 'W', 'F']),
|
||||||
listener_trie=None,
|
listener_trie=None,
|
||||||
formatter=None)
|
formatter=None)
|
||||||
error = style_guide.Error(error_code, 'filename.py', 1, 1, 'error text')
|
error = style_guide.Error(error_code, 'filename.py', 1, 1, 'error text',
|
||||||
|
physical_line)
|
||||||
|
|
||||||
with mock.patch('linecache.getline', return_value=physical_line):
|
with mock.patch('linecache.getline', return_value=physical_line):
|
||||||
assert guide.is_inline_ignored(error) is expected_result
|
assert guide.is_inline_ignored(error) is expected_result
|
||||||
|
|
@ -145,7 +146,8 @@ def test_disable_is_inline_ignored():
|
||||||
guide = style_guide.StyleGuide(create_options(disable_noqa=True),
|
guide = style_guide.StyleGuide(create_options(disable_noqa=True),
|
||||||
listener_trie=None,
|
listener_trie=None,
|
||||||
formatter=None)
|
formatter=None)
|
||||||
error = style_guide.Error('E121', 'filename.py', 1, 1, 'error text')
|
error = style_guide.Error('E121', 'filename.py', 1, 1, 'error text',
|
||||||
|
'line')
|
||||||
|
|
||||||
with mock.patch('linecache.getline') as getline:
|
with mock.patch('linecache.getline') as getline:
|
||||||
assert guide.is_inline_ignored(error) is False
|
assert guide.is_inline_ignored(error) is False
|
||||||
|
|
@ -171,7 +173,8 @@ def test_handle_error_notifies_listeners(select_list, ignore_list, error_code):
|
||||||
|
|
||||||
with mock.patch('linecache.getline', return_value=''):
|
with mock.patch('linecache.getline', return_value=''):
|
||||||
guide.handle_error(error_code, 'stdin', 1, 1, 'error found')
|
guide.handle_error(error_code, 'stdin', 1, 1, 'error found')
|
||||||
error = style_guide.Error(error_code, 'stdin', 1, 1, 'error found')
|
error = style_guide.Error(error_code, 'stdin', 1, 1, 'error found',
|
||||||
|
None)
|
||||||
listener_trie.notify.assert_called_once_with(error_code, error)
|
listener_trie.notify.assert_called_once_with(error_code, error)
|
||||||
formatter.handle.assert_called_once_with(error)
|
formatter.handle.assert_called_once_with(error)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue