Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/7401.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``disable-next`` is now correctly scoped to only the succeeding line.

Closes #7401
3 changes: 1 addition & 2 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2209,9 +2209,8 @@ def _loopvar_name(self, node: astroid.Name) -> None:
# scope lookup rules would need to be changed to return the initial
# assignment (which does not exist in code per se) as well as any later
# modifications.
# pylint: disable-next=too-many-boolean-expressions
if (
not astmts
not astmts # pylint: disable=too-many-boolean-expressions
or (
astmts[0].parent == astmts[0].root()
and astmts[0].parent.parent_of(node)
Expand Down
10 changes: 5 additions & 5 deletions pylint/lint/message_state_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ def _set_one_msg_status(
self, scope: str, msg: MessageDefinition, line: int | None, enable: bool
) -> None:
"""Set the status of an individual message."""
if scope == "module":
if scope in {"module", "line"}:
assert isinstance(line, int) # should always be int inside module scope

self.linter.file_state.set_msg_status(msg, line, enable)
self.linter.file_state.set_msg_status(msg, line, enable, scope)
if not enable and msg.symbol != "locally-disabled":
self.linter.add_message(
"locally-disabled", line=line, args=(msg.symbol, msg.msgid)
Expand Down Expand Up @@ -143,7 +143,7 @@ def _set_msg_status(
ignore_unknown: bool = False,
) -> None:
"""Do some tests and then iterate over message definitions to set state."""
assert scope in {"package", "module"}
assert scope in {"package", "module", "line"}

message_definitions = self._get_messages_to_set(msgid, enable, ignore_unknown)

Expand Down Expand Up @@ -197,7 +197,7 @@ def disable(
def disable_next(
self,
msgid: str,
scope: str = "package",
_: str = "package",
line: int | None = None,
ignore_unknown: bool = False,
) -> None:
Expand All @@ -207,7 +207,7 @@ def disable_next(
self._set_msg_status(
msgid,
enable=False,
scope=scope,
scope="line",
line=line + 1,
ignore_unknown=ignore_unknown,
)
Expand Down
50 changes: 35 additions & 15 deletions pylint/utils/file_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,30 +194,50 @@ def _set_message_state_in_block(
state = lines[line]
original_lineno = line

# Update suppression mapping
if not state:
self._suppression_mapping[(msg.msgid, line)] = original_lineno
else:
self._suppression_mapping.pop((msg.msgid, line), None)
self._set_message_state_on_line(msg, line, state, original_lineno)

# Update message state for respective line
try:
self._module_msgs_state[msg.msgid][line] = state
except KeyError:
self._module_msgs_state[msg.msgid] = {line: state}
del lines[lineno]

def set_msg_status(self, msg: MessageDefinition, line: int, status: bool) -> None:
def _set_message_state_on_line(
self,
msg: MessageDefinition,
line: int,
state: bool,
original_lineno: int,
) -> None:
"""Set the state of a message on a line."""
# Update suppression mapping
if not state:
self._suppression_mapping[(msg.msgid, line)] = original_lineno
else:
self._suppression_mapping.pop((msg.msgid, line), None)

# Update message state for respective line
try:
self._module_msgs_state[msg.msgid][line] = state
except KeyError:
self._module_msgs_state[msg.msgid] = {line: state}

def set_msg_status(
self,
msg: MessageDefinition,
line: int,
status: bool,
scope: str = "package",
) -> None:
"""Set status (enabled/disable) for a given message at a given line."""
assert line > 0
assert self._module
# TODO: 3.0: Remove unnecessary assertion
assert self._msgs_store

# Expand the status to cover all relevant block lines
self._set_state_on_block_lines(
self._msgs_store, self._module, msg, {line: status}
)
if scope != "line":
# Expand the status to cover all relevant block lines
self._set_state_on_block_lines(
self._msgs_store, self._module, msg, {line: status}
)
else:
self._set_message_state_on_line(msg, line, status, line)

# Store the raw value
try:
Expand Down
7 changes: 7 additions & 0 deletions tests/functional/d/disable_msg_next_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ def function_C():

def function_D(arg1, arg2): # [unused-argument, invalid-name]
return arg1


def function_E(): # [invalid-name]
# pylint: disable-next=unused-variable

Comment thread
Pierre-Sassoulas marked this conversation as resolved.
test = 43 # [unused-variable]
blah = 123 # [unused-variable]
3 changes: 3 additions & 0 deletions tests/functional/d/disable_msg_next_line.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ unused-variable:15:4:15:5:function_C:Unused variable 'x':UNDEFINED
f-string-without-interpolation:16:11:16:44:function_C:Using an f-string that does not have any interpolated variables:UNDEFINED
invalid-name:19:0:19:14:function_D:"Function name ""function_D"" doesn't conform to snake_case naming style":HIGH
unused-argument:19:21:19:25:function_D:Unused argument 'arg2':HIGH
invalid-name:23:0:23:14:function_E:"Function name ""function_E"" doesn't conform to snake_case naming style":HIGH
unused-variable:26:4:26:8:function_E:Unused variable 'test':UNDEFINED
unused-variable:27:4:27:8:function_E:Unused variable 'blah':UNDEFINED