mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-13 16:14:18 +00:00
Add handling and decision making for select and ignore
This commit is contained in:
parent
0645ec3ef7
commit
eafc91ae6a
4 changed files with 249 additions and 6 deletions
|
|
@ -1,4 +1,30 @@
|
||||||
"""Implementation of the StyleGuide used by Flake8."""
|
"""Implementation of the StyleGuide used by Flake8."""
|
||||||
|
import enum
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'StyleGuide',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Selected(enum.Enum):
|
||||||
|
"""Enum representing an explicitly or implicitly selected code."""
|
||||||
|
|
||||||
|
Explicitly = 'explicitly selected'
|
||||||
|
Implicitly = 'implicitly selected'
|
||||||
|
|
||||||
|
|
||||||
|
class Ignored(enum.Enum):
|
||||||
|
"""Enum representing an explicitly or implicitly ignored code."""
|
||||||
|
|
||||||
|
Explicitly = 'explicitly ignored'
|
||||||
|
Implicitly = 'implicitly ignored'
|
||||||
|
|
||||||
|
|
||||||
|
class Decision(enum.Enum):
|
||||||
|
"""Enum representing whether a code should be ignored or selected."""
|
||||||
|
|
||||||
|
Ignored = 'ignored error'
|
||||||
|
Selected = 'selected error'
|
||||||
|
|
||||||
|
|
||||||
class StyleGuide(object):
|
class StyleGuide(object):
|
||||||
|
|
@ -10,7 +36,85 @@ class StyleGuide(object):
|
||||||
|
|
||||||
.. todo:: Add parameter documentation.
|
.. todo:: Add parameter documentation.
|
||||||
"""
|
"""
|
||||||
pass
|
self.options = options
|
||||||
|
self.arguments = arguments
|
||||||
|
self.checkers = checker_plugins
|
||||||
|
self.listeners = listening_plugins
|
||||||
|
self.formatters = formatting_plugins
|
||||||
|
self._selected = tuple(options.select)
|
||||||
|
self._ignored = tuple(options.ignore)
|
||||||
|
self._decision_cache = {}
|
||||||
|
|
||||||
|
def is_user_selected(self, code):
|
||||||
|
"""Determine if the code has been selected by the user.
|
||||||
|
|
||||||
|
:param str code:
|
||||||
|
The code for the check that has been run.
|
||||||
|
:returns:
|
||||||
|
Selected.Implicitly if the selected list is empty,
|
||||||
|
Selected.Explicitly if the selected list is not empty and a match
|
||||||
|
was found,
|
||||||
|
Ignored.Implicitly if the selected list is not empty but no match
|
||||||
|
was found.
|
||||||
|
"""
|
||||||
|
if not self._selected:
|
||||||
|
return Selected.Implicitly
|
||||||
|
|
||||||
|
if code.startswith(self._selected):
|
||||||
|
return Selected.Explicitly
|
||||||
|
|
||||||
|
return Ignored.Implicitly
|
||||||
|
|
||||||
|
def is_user_ignored(self, code):
|
||||||
|
"""Determine if the code has been ignored by the user.
|
||||||
|
|
||||||
|
:param str code:
|
||||||
|
The code for the check that has been run.
|
||||||
|
:returns:
|
||||||
|
Selected.Implicitly if the ignored list is empty,
|
||||||
|
Ignored.Explicitly if the ignored list is not empty and a match was
|
||||||
|
found,
|
||||||
|
Selected.Implicitly if the ignored list is not empty but no match
|
||||||
|
was found.
|
||||||
|
"""
|
||||||
|
if self._ignored and code.startswith(self._ignored):
|
||||||
|
return Ignored.Explicitly
|
||||||
|
|
||||||
|
return Selected.Implicitly
|
||||||
|
|
||||||
|
def _decision_for(self, code):
|
||||||
|
startswith = code.startswith
|
||||||
|
selected = sorted([s for s in self._selected if startswith(s)])[0]
|
||||||
|
ignored = sorted([i for i in self._ignored if startswith(i)])[0]
|
||||||
|
|
||||||
|
if selected.startswith(ignored):
|
||||||
|
return Decision.Selected
|
||||||
|
return Decision.Ignored
|
||||||
|
|
||||||
|
def should_report_error(self, code):
|
||||||
|
"""Determine if the error code should be reported or ignored.
|
||||||
|
|
||||||
|
:param str code:
|
||||||
|
The code for the check that has been run.
|
||||||
|
"""
|
||||||
|
decision = self._decision_cache.get(code)
|
||||||
|
if decision is None:
|
||||||
|
selected = self.is_user_selected(code)
|
||||||
|
ignored = self.is_user_ignored(code)
|
||||||
|
|
||||||
|
if ((selected is Selected.Explicitly or
|
||||||
|
selected is Selected.Implicitly) and
|
||||||
|
ignored is Selected.Implicitly):
|
||||||
|
decision = Decision.Selected
|
||||||
|
elif (selected is Selected.Explicitly and
|
||||||
|
ignored is Ignored.Explicitly):
|
||||||
|
decision = self._decision_for(code)
|
||||||
|
elif (selected is Ignored.Implicitly or
|
||||||
|
ignored is Ignored.Explicitly):
|
||||||
|
decision = Decision.Ignored
|
||||||
|
|
||||||
|
self._decision_cache[code] = decision
|
||||||
|
return decision
|
||||||
|
|
||||||
|
|
||||||
# Should separate style guide logic from code that runs checks
|
# Should separate style guide logic from code that runs checks
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,7 @@ test=pytest
|
||||||
|
|
||||||
[bdist_wheel]
|
[bdist_wheel]
|
||||||
universal=1
|
universal=1
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
requires-dist =
|
||||||
|
enum34; python_version<"3.4"
|
||||||
|
|
|
||||||
17
setup.py
17
setup.py
|
|
@ -2,6 +2,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
import setuptools
|
import setuptools
|
||||||
|
import sys
|
||||||
|
|
||||||
import flake8
|
import flake8
|
||||||
|
|
||||||
|
|
@ -25,6 +26,16 @@ if mock is None:
|
||||||
tests_require += ['mock']
|
tests_require += ['mock']
|
||||||
|
|
||||||
|
|
||||||
|
requires = [
|
||||||
|
"pyflakes >= 0.8.1, < 1.1",
|
||||||
|
"pep8 >= 1.5.7, != 1.6.0, != 1.6.1, != 1.6.2",
|
||||||
|
# "mccabe >= 0.2.1, < 0.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
if sys.version_info < (3, 4):
|
||||||
|
requires.append("enum34")
|
||||||
|
|
||||||
|
|
||||||
def get_long_description():
|
def get_long_description():
|
||||||
"""Generate a long description from the README and CHANGES files."""
|
"""Generate a long description from the README and CHANGES files."""
|
||||||
descr = []
|
descr = []
|
||||||
|
|
@ -51,11 +62,7 @@ setuptools.setup(
|
||||||
"flake8.options",
|
"flake8.options",
|
||||||
"flake8.plugins",
|
"flake8.plugins",
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=requires,
|
||||||
"pyflakes >= 0.8.1, < 1.1",
|
|
||||||
"pep8 >= 1.5.7, != 1.6.0, != 1.6.1, != 1.6.2",
|
|
||||||
# "mccabe >= 0.2.1, < 0.4",
|
|
||||||
],
|
|
||||||
entry_points={
|
entry_points={
|
||||||
'distutils.commands': ['flake8 = flake8.main:Flake8Command'],
|
'distutils.commands': ['flake8 = flake8.main:Flake8Command'],
|
||||||
'console_scripts': ['flake8 = flake8.main.cli:main'],
|
'console_scripts': ['flake8 = flake8.main.cli:main'],
|
||||||
|
|
|
||||||
128
tests/unit/test_style_guide.py
Normal file
128
tests/unit/test_style_guide.py
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
"""Tests for the flake8.style_guide.StyleGuide class."""
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
from flake8 import style_guide
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def create_options(**kwargs):
|
||||||
|
"""Create and return an instance of optparse.Values."""
|
||||||
|
kwargs.setdefault('select', [])
|
||||||
|
kwargs.setdefault('ignore', [])
|
||||||
|
return optparse.Values(kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('ignore_list,error_code', [
|
||||||
|
(['E111', 'E121'], 'E111'),
|
||||||
|
(['E111', 'E121'], 'E121'),
|
||||||
|
(['E11', 'E12'], 'E121'),
|
||||||
|
(['E2', 'E12'], 'E121'),
|
||||||
|
(['E2', 'E12'], 'E211'),
|
||||||
|
])
|
||||||
|
def test_is_user_ignored_ignores_errors(ignore_list, error_code):
|
||||||
|
"""Verify we detect users explicitly ignoring an error."""
|
||||||
|
guide = style_guide.StyleGuide(create_options(ignore=ignore_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert guide.is_user_ignored(error_code) is style_guide.Ignored.Explicitly
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('ignore_list,error_code', [
|
||||||
|
(['E111', 'E121'], 'E112'),
|
||||||
|
(['E111', 'E121'], 'E122'),
|
||||||
|
(['E11', 'E12'], 'W121'),
|
||||||
|
(['E2', 'E12'], 'E112'),
|
||||||
|
(['E2', 'E12'], 'E111'),
|
||||||
|
])
|
||||||
|
def test_is_user_ignored_implicitly_selects_errors(ignore_list, error_code):
|
||||||
|
"""Verify we detect users does not explicitly ignore an error."""
|
||||||
|
guide = style_guide.StyleGuide(create_options(ignore=ignore_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert guide.is_user_ignored(error_code) is style_guide.Selected.Implicitly
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('select_list,error_code', [
|
||||||
|
(['E111', 'E121'], 'E111'),
|
||||||
|
(['E111', 'E121'], 'E121'),
|
||||||
|
(['E11', 'E12'], 'E121'),
|
||||||
|
(['E2', 'E12'], 'E121'),
|
||||||
|
(['E2', 'E12'], 'E211'),
|
||||||
|
])
|
||||||
|
def test_is_user_selected_selects_errors(select_list, error_code):
|
||||||
|
"""Verify we detect users explicitly selecting an error."""
|
||||||
|
guide = style_guide.StyleGuide(create_options(select=select_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert (guide.is_user_selected(error_code) is
|
||||||
|
style_guide.Selected.Explicitly)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_user_selected_implicitly_selects_errors():
|
||||||
|
"""Verify we detect users implicitly selecting an error."""
|
||||||
|
select_list = []
|
||||||
|
error_code = 'E121'
|
||||||
|
guide = style_guide.StyleGuide(create_options(select=select_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert (guide.is_user_selected(error_code) is
|
||||||
|
style_guide.Selected.Implicitly)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('select_list,error_code', [
|
||||||
|
(['E111', 'E121'], 'E112'),
|
||||||
|
(['E111', 'E121'], 'E122'),
|
||||||
|
(['E11', 'E12'], 'E132'),
|
||||||
|
(['E2', 'E12'], 'E321'),
|
||||||
|
(['E2', 'E12'], 'E410'),
|
||||||
|
])
|
||||||
|
def test_is_user_selected_excludes_errors(select_list, error_code):
|
||||||
|
"""Verify we detect users implicitly excludes an error."""
|
||||||
|
guide = style_guide.StyleGuide(create_options(select=select_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert guide.is_user_selected(error_code) is style_guide.Ignored.Implicitly
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('select_list,ignore_list,error_code,expected', [
|
||||||
|
(['E111', 'E121'], [], 'E111', style_guide.Decision.Selected),
|
||||||
|
(['E111', 'E121'], [], 'E112', style_guide.Decision.Ignored),
|
||||||
|
(['E111', 'E121'], [], 'E121', style_guide.Decision.Selected),
|
||||||
|
(['E111', 'E121'], [], 'E122', style_guide.Decision.Ignored),
|
||||||
|
(['E11', 'E12'], [], 'E132', style_guide.Decision.Ignored),
|
||||||
|
(['E2', 'E12'], [], 'E321', style_guide.Decision.Ignored),
|
||||||
|
(['E2', 'E12'], [], 'E410', style_guide.Decision.Ignored),
|
||||||
|
(['E11', 'E121'], ['E1'], 'E112', style_guide.Decision.Selected),
|
||||||
|
(['E111', 'E121'], ['E2'], 'E122', style_guide.Decision.Ignored),
|
||||||
|
(['E11', 'E12'], ['E13'], 'E132', style_guide.Decision.Ignored),
|
||||||
|
(['E1', 'E3'], ['E32'], 'E321', style_guide.Decision.Ignored),
|
||||||
|
([], ['E2', 'E12'], 'E410', style_guide.Decision.Selected),
|
||||||
|
(['E4'], ['E2', 'E12', 'E41'], 'E410', style_guide.Decision.Ignored),
|
||||||
|
(['E41'], ['E2', 'E12', 'E4'], 'E410', style_guide.Decision.Selected),
|
||||||
|
])
|
||||||
|
def test_should_report_error(select_list, ignore_list, error_code, expected):
|
||||||
|
"""Verify we decide when to report an error."""
|
||||||
|
guide = style_guide.StyleGuide(create_options(select=select_list,
|
||||||
|
ignore=ignore_list),
|
||||||
|
arguments=[],
|
||||||
|
checker_plugins=None,
|
||||||
|
listening_plugins=None,
|
||||||
|
formatting_plugins=None)
|
||||||
|
|
||||||
|
assert guide.should_report_error(error_code) is expected
|
||||||
Loading…
Add table
Add a link
Reference in a new issue