From 2f1338c34277a39bd0f49145c372c804cd79552e Mon Sep 17 00:00:00 2001 From: Lukasz Langa Date: Sun, 27 Nov 2016 17:42:00 -0800 Subject: [PATCH] Assign missing codes to PyFlakes messages Some PyFlakes messages weren't covered by unique messages, making them impossible to select/ignore. This is now fixed. To ensure we don't regress in the future, a test has been added that fails if there's any uncovered messages. --- docs/source/release-notes/3.3.0.rst | 3 ++ docs/source/user/error-codes.rst | 34 ++++++++++++++++++- src/flake8/plugins/pyflakes.py | 51 +++++++++++++++++++---------- tests/unit/test_pyflakes_codes.py | 15 +++++++++ 4 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 tests/unit/test_pyflakes_codes.py diff --git a/docs/source/release-notes/3.3.0.rst b/docs/source/release-notes/3.3.0.rst index ed9f171..fc7c2f4 100644 --- a/docs/source/release-notes/3.3.0.rst +++ b/docs/source/release-notes/3.3.0.rst @@ -6,6 +6,9 @@ You can view the `3.3.0 milestone`_ on GitLab for more details. - Fix problem where hooks should only check \*.py files. (See also `GitLab#268`_) +- Added unique error codes for all missing PyFlakes messages (14 new + codes, see all :ref:`Error / Violation Codes `) + .. links .. _3.3.0 milestone: https://gitlab.com/pycqa/flake8/milestones/16 diff --git a/docs/source/user/error-codes.rst b/docs/source/user/error-codes.rst index 8bff640..dbaf35e 100644 --- a/docs/source/user/error-codes.rst +++ b/docs/source/user/error-codes.rst @@ -1,3 +1,5 @@ +.. _error_codes: + ========================= Error / Violation Codes ========================= @@ -22,6 +24,36 @@ generates its own :term:`error code`\ s for ``pyflakes``: +------+---------------------------------------------------------------------+ | F405 | ``name`` may be undefined, or defined from star imports: ``module`` | +------+---------------------------------------------------------------------+ +| F406 | 'from ``module`` import \*' only allowed at module level | ++------+---------------------------------------------------------------------+ +| F407 | an undefined ``__future__`` feature name was imported | ++------+---------------------------------------------------------------------+ ++------+---------------------------------------------------------------------+ +| F601 | dictionary key ``name`` repeated with different values | ++------+---------------------------------------------------------------------+ +| F602 | dictionary key variable ``name`` repeated with different values | ++------+---------------------------------------------------------------------+ +| F621 | too many expressions in an assignment with star-unpacking | ++------+---------------------------------------------------------------------+ +| F622 | two or more starred expressions in an assignment ``(a, *b, *c = d)``| ++------+---------------------------------------------------------------------+ +| F631 | assertion test is a tuple, which are always ``True`` | ++------+---------------------------------------------------------------------+ ++------+---------------------------------------------------------------------+ +| F701 | a ``break`` statement outside of a ``while`` or ``for`` loop | ++------+---------------------------------------------------------------------+ +| F702 | a ``continue`` statement outside of a ``while`` or ``for`` loop | ++------+---------------------------------------------------------------------+ +| F703 | a ``continue`` statement in a ``finally`` block in a loop | ++------+---------------------------------------------------------------------+ +| F704 | a ``yield`` or ``yield from`` statement outside of a function | ++------+---------------------------------------------------------------------+ +| F705 | a ``return`` statement with arguments inside a generator | ++------+---------------------------------------------------------------------+ +| F706 | a ``return`` statement outside of a function/method | ++------+---------------------------------------------------------------------+ +| F707 | an ``except:`` block as not the last exception handler | ++------+---------------------------------------------------------------------+ +------+---------------------------------------------------------------------+ | F811 | redefinition of unused ``name`` from line ``N`` | +------+---------------------------------------------------------------------+ @@ -29,7 +61,7 @@ generates its own :term:`error code`\ s for ``pyflakes``: +------+---------------------------------------------------------------------+ | F821 | undefined name ``name`` | +------+---------------------------------------------------------------------+ -| F822 | undefined name ``name`` in __all__ | +| F822 | undefined name ``name`` in ``__all__`` | +------+---------------------------------------------------------------------+ | F823 | local variable ``name`` ... referenced before assignment | +------+---------------------------------------------------------------------+ diff --git a/src/flake8/plugins/pyflakes.py b/src/flake8/plugins/pyflakes.py index ca22302..65a31d0 100644 --- a/src/flake8/plugins/pyflakes.py +++ b/src/flake8/plugins/pyflakes.py @@ -17,27 +17,44 @@ import pyflakes.checker from flake8 import utils +FLAKE8_PYFLAKES_CODES = dict([line.split()[::-1] for line in ( + 'F401 UnusedImport', + 'F402 ImportShadowedByLoopVar', + 'F403 ImportStarUsed', + 'F404 LateFutureImport', + 'F405 ImportStarUsage', + 'F406 ImportStarNotPermitted', + 'F407 FutureFeatureNotDefined', + 'F601 MultiValueRepeatedKeyLiteral', + 'F602 MultiValueRepeatedKeyVariable', + 'F621 TooManyExpressionsInStarredAssignment', + 'F622 TwoStarredExpressions', + 'F631 AssertTuple', + 'F701 BreakOutsideLoop', + 'F702 ContinueOutsideLoop', + 'F703 ContinueInFinally', + 'F704 YieldOutsideFunction', + 'F705 ReturnWithArgsInsideGenerator', + 'F706 ReturnOutsideFunction', + 'F707 DefaultExceptNotLast', + 'F721 DoctestSyntaxError', + 'F811 RedefinedWhileUnused', + 'F812 RedefinedInListComp', + 'F821 UndefinedName', + 'F822 UndefinedExport', + 'F823 UndefinedLocal', + 'F831 DuplicateArgument', + 'F841 UnusedVariable', +)]) + + def patch_pyflakes(): """Add error codes to Pyflakes messages.""" - codes = dict([line.split()[::-1] for line in ( - 'F401 UnusedImport', - 'F402 ImportShadowedByLoopVar', - 'F403 ImportStarUsed', - 'F404 LateFutureImport', - 'F405 ImportStarUsage', - 'F810 Redefined', - 'F811 RedefinedWhileUnused', - 'F812 RedefinedInListComp', - 'F821 UndefinedName', - 'F822 UndefinedExport', - 'F823 UndefinedLocal', - 'F831 DuplicateArgument', - 'F841 UnusedVariable', - )]) - for name, obj in vars(pyflakes.messages).items(): if name[0].isupper() and obj.message: - obj.flake8_msg = '%s %s' % (codes.get(name, 'F999'), obj.message) + obj.flake8_msg = '%s %s' % ( + FLAKE8_PYFLAKES_CODES.get(name, 'F999'), obj.message + ) patch_pyflakes() diff --git a/tests/unit/test_pyflakes_codes.py b/tests/unit/test_pyflakes_codes.py new file mode 100644 index 0000000..837e971 --- /dev/null +++ b/tests/unit/test_pyflakes_codes.py @@ -0,0 +1,15 @@ +"""Tests of pyflakes monkey patches.""" + +import pyflakes + +from flake8.plugins import pyflakes as pyflakes_shim + + +def test_all_pyflakes_messages_have_flake8_codes_assigned(): + """Verify all PyFlakes messages have error codes assigned.""" + messages = { + name + for name, obj in vars(pyflakes.messages).items() + if name[0].isupper() and obj.message + } + assert messages == set(pyflakes_shim.FLAKE8_PYFLAKES_CODES)