Skip to content

Commit

Permalink
Add disable-next option
Browse files Browse the repository at this point in the history
Adding `# pylint: disable-next=msgid` to your file will disable the
message for the next line.
This closes pylint-dev#1682
  • Loading branch information
DanielNoord committed Aug 4, 2021
1 parent a71cfe1 commit f58f428
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 5 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -85,6 +85,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?
===========================
Expand Down
4 changes: 4 additions & 0 deletions doc/whatsnew/2.10.rst
Expand Up @@ -70,3 +70,7 @@ Other Changes
in an exception handler, but used outside of the handler.

Closes #626

* Add ``disable-next`` option: allows using `# pylint: disable-next=msgid` to disable a message for the following line

Closes #1682
4 changes: 4 additions & 0 deletions pylint/exceptions.py
Expand Up @@ -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"""
8 changes: 6 additions & 2 deletions pylint/lint/pylinter.py
Expand Up @@ -490,7 +490,11 @@ def __init__(self, options=(), reporter=None, option_groups=(), pylintrc=None):
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"],
Expand Down Expand Up @@ -800,7 +804,7 @@ def list_messages_enabled(self):
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
Expand Down
26 changes: 24 additions & 2 deletions pylint/message/message_handler_mix_in.py
Expand Up @@ -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,
Expand All @@ -15,7 +15,11 @@
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
Expand Down Expand Up @@ -59,6 +63,24 @@ def disable(self, msgid, scope="package", line=None, ignore_unknown=False):
)
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
Expand Down
4 changes: 3 additions & 1 deletion pylint/utils/pragma_parser.py
Expand Up @@ -27,7 +27,9 @@


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,
Expand Down
20 changes: 20 additions & 0 deletions 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
5 changes: 5 additions & 0 deletions 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

0 comments on commit f58f428

Please sign in to comment.