mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-11 07:14:18 +00:00
Merge branch 'physical-line-multiple' into 'master'
Allow physical checks to return multiple results See merge request pycqa/flake8!269
This commit is contained in:
commit
cad4e5be6f
2 changed files with 109 additions and 18 deletions
|
|
@ -541,21 +541,38 @@ class FileChecker(object):
|
||||||
self.processor.next_logical_line()
|
self.processor.next_logical_line()
|
||||||
|
|
||||||
def run_physical_checks(self, physical_line, override_error_line=None):
|
def run_physical_checks(self, physical_line, override_error_line=None):
|
||||||
"""Run all checks for a given physical line."""
|
"""Run all checks for a given physical line.
|
||||||
|
|
||||||
|
A single physical check may return multiple errors.
|
||||||
|
"""
|
||||||
for plugin in self.checks["physical_line_plugins"]:
|
for plugin in self.checks["physical_line_plugins"]:
|
||||||
self.processor.update_checker_state_for(plugin)
|
self.processor.update_checker_state_for(plugin)
|
||||||
result = self.run_check(plugin, physical_line=physical_line)
|
result = self.run_check(plugin, physical_line=physical_line)
|
||||||
if result is not None:
|
|
||||||
column_offset, text = result
|
|
||||||
error_code = self.report(
|
|
||||||
error_code=None,
|
|
||||||
line_number=self.processor.line_number,
|
|
||||||
column=column_offset,
|
|
||||||
text=text,
|
|
||||||
line=(override_error_line or physical_line),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.processor.check_physical_error(error_code, physical_line)
|
if result is not None:
|
||||||
|
# This is a single result if first element is an int
|
||||||
|
column_offset = None
|
||||||
|
try:
|
||||||
|
column_offset = result[0]
|
||||||
|
except (IndexError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(column_offset, int):
|
||||||
|
# If we only have a single result, convert to a collection
|
||||||
|
result = (result,)
|
||||||
|
|
||||||
|
for result_single in result:
|
||||||
|
column_offset, text = result_single
|
||||||
|
error_code = self.report(
|
||||||
|
error_code=None,
|
||||||
|
line_number=self.processor.line_number,
|
||||||
|
column=column_offset,
|
||||||
|
text=text,
|
||||||
|
line=(override_error_line or physical_line),
|
||||||
|
)
|
||||||
|
self.processor.check_physical_error(
|
||||||
|
error_code, physical_line
|
||||||
|
)
|
||||||
|
|
||||||
def process_tokens(self):
|
def process_tokens(self):
|
||||||
"""Process tokens and trigger checks.
|
"""Process tokens and trigger checks.
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,17 @@ import pytest
|
||||||
from flake8 import checker
|
from flake8 import checker
|
||||||
from flake8.plugins import manager
|
from flake8.plugins import manager
|
||||||
|
|
||||||
|
PHYSICAL_LINE = "# Physical line content"
|
||||||
|
|
||||||
EXPECTED_REPORT = (1, 1, 'T000 Expected Message')
|
EXPECTED_REPORT = (1, 1, 'T000 Expected Message')
|
||||||
|
EXPECTED_REPORT_PHYSICAL_LINE = (1, 'T000 Expected Message')
|
||||||
|
EXPECTED_RESULT_PHYSICAL_LINE = (
|
||||||
|
'T000',
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
'Expected Message',
|
||||||
|
PHYSICAL_LINE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PluginClass(object):
|
class PluginClass(object):
|
||||||
|
|
@ -43,13 +52,48 @@ def plugin_func_list(tree):
|
||||||
return [EXPECTED_REPORT + (type(plugin_func_list), )]
|
return [EXPECTED_REPORT + (type(plugin_func_list), )]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('plugin_target', [
|
@plugin_func
|
||||||
PluginClass,
|
def plugin_func_physical_ret(physical_line):
|
||||||
plugin_func_gen,
|
"""Expect report from a physical_line. Single return."""
|
||||||
plugin_func_list,
|
return EXPECTED_REPORT_PHYSICAL_LINE
|
||||||
])
|
|
||||||
def test_handle_file_plugins(plugin_target):
|
|
||||||
"""Test the FileChecker class handling different file plugin types."""
|
@plugin_func
|
||||||
|
def plugin_func_physical_none(physical_line):
|
||||||
|
"""Expect report from a physical_line. No results."""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@plugin_func
|
||||||
|
def plugin_func_physical_list_single(physical_line):
|
||||||
|
"""Expect report from a physical_line. List of single result."""
|
||||||
|
return [EXPECTED_REPORT_PHYSICAL_LINE]
|
||||||
|
|
||||||
|
|
||||||
|
@plugin_func
|
||||||
|
def plugin_func_physical_list_multiple(physical_line):
|
||||||
|
"""Expect report from a physical_line. List of multiple results."""
|
||||||
|
return [EXPECTED_REPORT_PHYSICAL_LINE] * 2
|
||||||
|
|
||||||
|
|
||||||
|
@plugin_func
|
||||||
|
def plugin_func_physical_gen_single(physical_line):
|
||||||
|
"""Expect report from a physical_line. Generator of single result."""
|
||||||
|
yield EXPECTED_REPORT_PHYSICAL_LINE
|
||||||
|
|
||||||
|
|
||||||
|
@plugin_func
|
||||||
|
def plugin_func_physical_gen_multiple(physical_line):
|
||||||
|
"""Expect report from a physical_line. Generator of multiple results."""
|
||||||
|
for _ in range(3):
|
||||||
|
yield EXPECTED_REPORT_PHYSICAL_LINE
|
||||||
|
|
||||||
|
|
||||||
|
def mock_file_checker_with_plugin(plugin_target):
|
||||||
|
"""Get a mock FileChecker class with plugin_target registered.
|
||||||
|
|
||||||
|
Useful as a starting point for mocking reports/results.
|
||||||
|
"""
|
||||||
# Mock an entry point returning the plugin target
|
# Mock an entry point returning the plugin target
|
||||||
entry_point = mock.Mock(spec=['load'])
|
entry_point = mock.Mock(spec=['load'])
|
||||||
entry_point.name = plugin_target.name
|
entry_point.name = plugin_target.name
|
||||||
|
|
@ -67,6 +111,17 @@ def test_handle_file_plugins(plugin_target):
|
||||||
checks.to_dictionary(),
|
checks.to_dictionary(),
|
||||||
mock.MagicMock()
|
mock.MagicMock()
|
||||||
)
|
)
|
||||||
|
return file_checker
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('plugin_target', [
|
||||||
|
PluginClass,
|
||||||
|
plugin_func_gen,
|
||||||
|
plugin_func_list,
|
||||||
|
])
|
||||||
|
def test_handle_file_plugins(plugin_target):
|
||||||
|
"""Test the FileChecker class handling different file plugin types."""
|
||||||
|
file_checker = mock_file_checker_with_plugin(plugin_target)
|
||||||
|
|
||||||
# Do not actually build an AST
|
# Do not actually build an AST
|
||||||
file_checker.processor.build_ast = lambda: True
|
file_checker.processor.build_ast = lambda: True
|
||||||
|
|
@ -81,6 +136,25 @@ def test_handle_file_plugins(plugin_target):
|
||||||
text=EXPECTED_REPORT[2])
|
text=EXPECTED_REPORT[2])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('plugin_target,len_results', [
|
||||||
|
(plugin_func_physical_ret, 1),
|
||||||
|
(plugin_func_physical_none, 0),
|
||||||
|
(plugin_func_physical_list_single, 1),
|
||||||
|
(plugin_func_physical_list_multiple, 2),
|
||||||
|
(plugin_func_physical_gen_single, 1),
|
||||||
|
(plugin_func_physical_gen_multiple, 3),
|
||||||
|
])
|
||||||
|
def test_line_check_results(plugin_target, len_results):
|
||||||
|
"""Test the FileChecker class handling results from line checks."""
|
||||||
|
file_checker = mock_file_checker_with_plugin(plugin_target)
|
||||||
|
|
||||||
|
# Results will be store in an internal array
|
||||||
|
file_checker.run_physical_checks(PHYSICAL_LINE)
|
||||||
|
assert file_checker.results == [
|
||||||
|
EXPECTED_RESULT_PHYSICAL_LINE
|
||||||
|
] * len_results
|
||||||
|
|
||||||
|
|
||||||
PLACEHOLDER_CODE = 'some_line = "of" * code'
|
PLACEHOLDER_CODE = 'some_line = "of" * code'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue