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/7214.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Message send to reporter are now copied so a reporter cannot modify the message sent to other reporters.

Closes #7214
4 changes: 3 additions & 1 deletion pylint/reporters/multi_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import os
from collections.abc import Callable
from copy import copy
from typing import TYPE_CHECKING, TextIO

from pylint.message import Message
Expand Down Expand Up @@ -77,7 +78,8 @@ def linter(self, value: PyLinter) -> None:
def handle_message(self, msg: Message) -> None:
"""Handle a new message triggered on the current file."""
for rep in self._sub_reporters:
rep.handle_message(msg)
# We provide a copy so reporters can't modify message for others.
rep.handle_message(copy(msg))

def writeln(self, string: str = "") -> None:
"""Write a line in the output buffer."""
Expand Down
48 changes: 47 additions & 1 deletion tests/reporters/unittest_reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
from _pytest.recwarn import WarningsRecorder

from pylint import checkers
from pylint.interfaces import HIGH
from pylint.lint import PyLinter
from pylint.message.message import Message
from pylint.reporters import BaseReporter, MultiReporter
from pylint.reporters.text import ParseableTextReporter, TextReporter
from pylint.typing import FileItem
from pylint.typing import FileItem, MessageLocationTuple

if TYPE_CHECKING:
from pylint.reporters.ureports.nodes import Section
Expand Down Expand Up @@ -334,6 +336,50 @@ def test_multi_format_output(tmp_path: Path) -> None:
)


def test_multi_reporter_independant_messages() -> None:
"""Messages should not be modified by multiple reporters"""

check_message = "Not modified"

class ReporterModify(BaseReporter):
def handle_message(self, msg: Message) -> None:
msg.msg = "Modified message"

def writeln(self, string: str = "") -> None:
pass

def _display(self, layout: Section) -> None:
pass

class ReporterCheck(BaseReporter):
def handle_message(self, msg: Message) -> None:
assert (
msg.msg == check_message
), "Message object should not be changed by other reporters."

def writeln(self, string: str = "") -> None:
pass

def _display(self, layout: Section) -> None:
pass

multi_reporter = MultiReporter([ReporterModify(), ReporterCheck()], lambda: None)

message = Message(
symbol="missing-docstring",
msg_id="C0123",
location=MessageLocationTuple("abspath", "path", "module", "obj", 1, 2, 1, 3),
msg=check_message,
confidence=HIGH,
)

multi_reporter.handle_message(message)

Comment thread
Pierre-Sassoulas marked this conversation as resolved.
assert (
message.msg == check_message
), "Message object should not be changed by reporters."


def test_display_results_is_renamed() -> None:
class CustomReporter(TextReporter):
def _display(self, layout: Section) -> None:
Expand Down