Add handling and decision making for select and ignore

This commit is contained in:
Ian Cordasco 2016-02-02 20:48:26 -06:00
parent 0645ec3ef7
commit eafc91ae6a
4 changed files with 249 additions and 6 deletions

View file

@ -1,4 +1,30 @@
"""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):
@ -10,7 +36,85 @@ class StyleGuide(object):
.. 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

View file

@ -3,3 +3,7 @@ test=pytest
[bdist_wheel]
universal=1
[metadata]
requires-dist =
enum34; python_version<"3.4"

View file

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from __future__ import with_statement
import setuptools
import sys
import flake8
@ -25,6 +26,16 @@ if mock is None:
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():
"""Generate a long description from the README and CHANGES files."""
descr = []
@ -51,11 +62,7 @@ setuptools.setup(
"flake8.options",
"flake8.plugins",
],
install_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",
],
install_requires=requires,
entry_points={
'distutils.commands': ['flake8 = flake8.main:Flake8Command'],
'console_scripts': ['flake8 = flake8.main.cli:main'],

View 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