Skip to content

Commit 6d66b18

Browse files
Fix: reporters receive copy of message (#7620)
Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 4ee928d commit 6d66b18

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

doc/whatsnew/fragments/7214.bugfix

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Message send to reporter are now copied so a reporter cannot modify the message sent to other reporters.
2+
3+
Closes #7214

pylint/reporters/multi_reporter.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import os
88
from collections.abc import Callable
9+
from copy import copy
910
from typing import TYPE_CHECKING, TextIO
1011

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

8284
def writeln(self, string: str = "") -> None:
8385
"""Write a line in the output buffer."""

requirements_test_min.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# astroid dependency is also defined in pyproject.toml
33
# You need to increment the CACHE_VERSION in github actions too
44
astroid==2.12.12 # Pinned to a specific version for tests
5-
typing-extensions~=4.4
5+
typing-extensions~=4.3
66
py~=1.11.0
77
pytest~=7.2
88
pytest-benchmark~=4.0

tests/reporters/unittest_reporting.py

+50-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
import pytest
1717

1818
from pylint import checkers
19+
from pylint.interfaces import HIGH
1920
from pylint.lint import PyLinter
20-
from pylint.reporters import BaseReporter
21+
from pylint.message.message import Message
22+
from pylint.reporters import BaseReporter, MultiReporter
2123
from pylint.reporters.text import ParseableTextReporter, TextReporter
22-
from pylint.typing import FileItem
24+
from pylint.typing import FileItem, MessageLocationTuple
2325

2426
if TYPE_CHECKING:
2527
from pylint.reporters.ureports.nodes import Section
@@ -329,13 +331,57 @@ def test_multi_format_output(tmp_path):
329331
)
330332

331333

332-
def test_display_results_is_renamed():
334+
def test_multi_reporter_independant_messages() -> None:
335+
"""Messages should not be modified by multiple reporters"""
336+
337+
check_message = "Not modified"
338+
339+
class ReporterModify(BaseReporter):
340+
def handle_message(self, msg: Message) -> None:
341+
msg.msg = "Modified message"
342+
343+
def writeln(self, string: str = "") -> None:
344+
pass
345+
346+
def _display(self, layout: Section) -> None:
347+
pass
348+
349+
class ReporterCheck(BaseReporter):
350+
def handle_message(self, msg: Message) -> None:
351+
assert (
352+
msg.msg == check_message
353+
), "Message object should not be changed by other reporters."
354+
355+
def writeln(self, string: str = "") -> None:
356+
pass
357+
358+
def _display(self, layout: Section) -> None:
359+
pass
360+
361+
multi_reporter = MultiReporter([ReporterModify(), ReporterCheck()], lambda: None)
362+
363+
message = Message(
364+
symbol="missing-docstring",
365+
msg_id="C0123",
366+
location=MessageLocationTuple("abspath", "path", "module", "obj", 1, 2, 1, 3),
367+
msg=check_message,
368+
confidence=HIGH,
369+
)
370+
371+
multi_reporter.handle_message(message)
372+
373+
assert (
374+
message.msg == check_message
375+
), "Message object should not be changed by reporters."
376+
377+
378+
def test_display_results_is_renamed() -> None:
333379
class CustomReporter(TextReporter):
334380
def _display(self, layout: Section) -> None:
335381
return None
336382

337383
reporter = CustomReporter()
338384
with pytest.raises(AttributeError) as exc:
339385
# pylint: disable=no-member
340-
reporter.display_results()
386+
reporter.display_results() # type: ignore[attr-defined]
341387
assert "no attribute 'display_results'" in str(exc)

0 commit comments

Comments
 (0)