diff options
| author | Daniël van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-08-05 06:59:00 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-05 06:59:00 +0200 |
| commit | 7d84a322afb129045b5c82790bad56b7d7f4fbc3 (patch) | |
| tree | ea159d966f239f763bdae15bdafa16ad15fcdd0f | |
| parent | 8ea16d4077412f1ce7c4ebee551ff8fc0947f35a (diff) | |
| download | pylint-git-7d84a322afb129045b5c82790bad56b7d7f4fbc3.tar.gz | |
Add ``disable-next`` option (#4797)
* Add ``disable-next`` option
Adding `# pylint: disable-next=msgid` to your file will disable the
message for the next line.
This closes #1682
* Add documentation, rorganize the FAQ for disable/enable and add ref to the full doc
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | doc/faq.rst | 16 | ||||
| -rw-r--r-- | doc/user_guide/message-control.rst | 15 | ||||
| -rw-r--r-- | doc/whatsnew/2.10.rst | 4 | ||||
| -rw-r--r-- | pylint/exceptions.py | 4 | ||||
| -rw-r--r-- | pylint/lint/pylinter.py | 8 | ||||
| -rw-r--r-- | pylint/message/message_handler_mix_in.py | 26 | ||||
| -rw-r--r-- | pylint/utils/pragma_parser.py | 4 | ||||
| -rw-r--r-- | tests/functional/d/disable_msg_next_line.py | 20 | ||||
| -rw-r--r-- | tests/functional/d/disable_msg_next_line.txt | 5 |
10 files changed, 97 insertions, 9 deletions
@@ -89,6 +89,10 @@ Release date: TBA Closes #626 +* Add ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line + + Closes #1682 + What's New in Pylint 2.9.6? =========================== diff --git a/doc/faq.rst b/doc/faq.rst index d679bc286..02e252457 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -123,12 +123,20 @@ Much probably. Read :ref:`ide-integration` 4.1 How to disable a particular message? ----------------------------------------------------------- -Add "#pylint: disable=some-message,another-one" at the desired block level -or at the end of the desired line of code. - -A block is either a scope (say a function, a module), or a multiline statement (Try, Finally, if statements, for loops). +For a single line : Add ``#pylint: disable=some-message,another-one`` at the +end of the desired line of code. Since Pylint 2.10 you can also use +``#pylint: disable-next=...`` on the line just above the problem. +``...`` in the following example is a short hand for the list of +messages you want to disable. + +For larger disable : You can add ``#pylint: disable=...`` at the block level to +disable for the block. It's possible to enable for the reminder of the block +with ``#pylint: enable=...`` A block is either a scope (say a function, a module), +or a multiline statement (try, finally, if statements, for loops). `It's currently impossible to disable inside an else block`_ +Read :ref:`message-control` for details and examples. + .. _`It's currently impossible to disable inside an else block`: https://github.com/PyCQA/pylint/issues/872 4.2 Is there a way to disable a message for a particular module only? diff --git a/doc/user_guide/message-control.rst b/doc/user_guide/message-control.rst index 217b1b556..dafbe2af4 100644 --- a/doc/user_guide/message-control.rst +++ b/doc/user_guide/message-control.rst @@ -39,6 +39,13 @@ The pragma controls can disable / enable: a, b = ... # pylint: disable=unbalanced-tuple-unpacking +* All the violations on the following line + + .. sourcecode:: python + + # pylint: disable-next=unbalanced-tuple-unpacking + a, b = ... + * All the violations in a single scope .. sourcecode:: python @@ -179,6 +186,14 @@ Here's an example with all these rules in a single place: print(self.bla) print(self.blop) + def meth9(self): + """test next line disabling""" + # no error + # pylint: disable-next=no-member + print(self.bla) + # error + print(self.blop) + Detecting useless disables -------------------------- diff --git a/doc/whatsnew/2.10.rst b/doc/whatsnew/2.10.rst index de209d5d2..6622c20fa 100644 --- a/doc/whatsnew/2.10.rst +++ b/doc/whatsnew/2.10.rst @@ -71,6 +71,10 @@ Other Changes Closes #626 +* Add ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line + + Closes #1682 + * Added ``format-string-without-interpolation`` checker: Emitted when formatting is applied to a string without any variables to be replaced Closes #4042 diff --git a/pylint/exceptions.py b/pylint/exceptions.py index 416183abc..68d03b269 100644 --- a/pylint/exceptions.py +++ b/pylint/exceptions.py @@ -31,3 +31,7 @@ class InvalidReporterError(Exception): class InvalidArgsError(ValueError): """raised when passed arguments are invalid, e.g., have the wrong length""" + + +class NoLineSuppliedError(Exception): + """raised when trying to disable a message on a next line without supplying a line number""" diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py index 3c816cbff..c34594fb0 100644 --- a/pylint/lint/pylinter.py +++ b/pylint/lint/pylinter.py @@ -490,7 +490,11 @@ class PyLinter( self._external_opts = options self.options = options + PyLinter.make_options() self.option_groups = option_groups + PyLinter.option_groups - self._options_methods = {"enable": self.enable, "disable": self.disable} + self._options_methods = { + "enable": self.enable, + "disable": self.disable, + "disable-next": self.disable_next, + } self._bw_options_methods = { "disable-msg": self._options_methods["disable"], "enable-msg": self._options_methods["enable"], @@ -800,7 +804,7 @@ class PyLinter( def process_tokens(self, tokens): """Process tokens from the current module to search for module/block level options.""" - control_pragmas = {"disable", "enable"} + control_pragmas = {"disable", "disable-next", "enable"} prev_line = None saw_newline = True seen_newline = True diff --git a/pylint/message/message_handler_mix_in.py b/pylint/message/message_handler_mix_in.py index b28be128d..495599757 100644 --- a/pylint/message/message_handler_mix_in.py +++ b/pylint/message/message_handler_mix_in.py @@ -2,7 +2,7 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE import sys -from typing import List, Tuple +from typing import List, Tuple, Union from pylint.constants import ( _SCOPE_EXEMPT, @@ -15,7 +15,11 @@ from pylint.constants import ( MSG_TYPES_STATUS, WarningScope, ) -from pylint.exceptions import InvalidMessageError, UnknownMessageError +from pylint.exceptions import ( + InvalidMessageError, + NoLineSuppliedError, + UnknownMessageError, +) from pylint.interfaces import UNDEFINED from pylint.message.message import Message from pylint.utils import get_module_and_frameid, get_rst_section, get_rst_title @@ -59,6 +63,24 @@ class MessagesHandlerMixIn: ) self._register_by_id_managed_msg(msgid, line) + def disable_next( + self, + msgid: str, + scope: str = "package", + line: Union[bool, int] = None, + ignore_unknown: bool = False, + ): + if not line: + raise NoLineSuppliedError + self._set_msg_status( + msgid, + enable=False, + scope=scope, + line=line + 1, + ignore_unknown=ignore_unknown, + ) + self._register_by_id_managed_msg(msgid, line + 1) + def enable(self, msgid, scope="package", line=None, ignore_unknown=False): self._set_msg_status( msgid, enable=True, scope=scope, line=line, ignore_unknown=ignore_unknown diff --git a/pylint/utils/pragma_parser.py b/pylint/utils/pragma_parser.py index 488b4626c..d57d6a1de 100644 --- a/pylint/utils/pragma_parser.py +++ b/pylint/utils/pragma_parser.py @@ -27,7 +27,9 @@ PragmaRepresenter = namedtuple("PragmaRepresenter", "action messages") ATOMIC_KEYWORDS = frozenset(("disable-all", "skip-file")) -MESSAGE_KEYWORDS = frozenset(("disable-msg", "enable-msg", "disable", "enable")) +MESSAGE_KEYWORDS = frozenset( + ("disable-next", "disable-msg", "enable-msg", "disable", "enable") +) # sorted is necessary because sets are unordered collections and ALL_KEYWORDS # string should not vary between executions # reverse is necessary in order to have the longest keywords first, so that, for example, diff --git a/tests/functional/d/disable_msg_next_line.py b/tests/functional/d/disable_msg_next_line.py new file mode 100644 index 000000000..f500feb1e --- /dev/null +++ b/tests/functional/d/disable_msg_next_line.py @@ -0,0 +1,20 @@ +"""Test if disable-next only disables messages for the next line""" +# pylint: disable=missing-function-docstring +# pylint: disable-next=unused-argument, invalid-name +def function_A(arg1, arg2): + return arg1 + + +# pylint: disable-next=unused-argument,invalid-name +def function_B(arg1, arg2): + return arg1 + + +# pylint: disable-next=invalid-name, f-string-without-interpolation +def function_C(): + x = "string" # [unused-variable, invalid-name] + return f"This should be a normal string" # [f-string-without-interpolation] + + +def function_D(arg1, arg2): # [unused-argument, invalid-name] + return arg1 diff --git a/tests/functional/d/disable_msg_next_line.txt b/tests/functional/d/disable_msg_next_line.txt new file mode 100644 index 000000000..bfd0adeae --- /dev/null +++ b/tests/functional/d/disable_msg_next_line.txt @@ -0,0 +1,5 @@ +invalid-name:15:4:function_C:"Variable name ""x"" doesn't conform to snake_case naming style":HIGH +unused-variable:15:4:function_C:"Unused variable 'x'":HIGH +f-string-without-interpolation:16:11:function_C:"Using an f-string that does not have any interpolated variables":HIGH +invalid-name:19:0:function_D:"Function name ""function_D"" doesn't conform to snake_case naming style":HIGH +unused-argument:19:21:function_D:"Unused argument 'arg2'":HIGH |
