diff --git a/doc/whatsnew/fragments/10914.internal b/doc/whatsnew/fragments/10914.internal new file mode 100644 index 0000000000..05947c343b --- /dev/null +++ b/doc/whatsnew/fragments/10914.internal @@ -0,0 +1,8 @@ +The primer now pairs residual messages — first by ``(symbol, path, obj)`` and then by +exact source location — and reports altered messages as a single *changed* entry with +a compact diff, rather than as a separate removal + addition. The location-based pass +also catches symbol renames at the same code position (e.g. ``used-before-assignment`` +→ ``possibly-used-before-assignment``). New messages are classified into fixed false +positives (``useless-suppression``), ``astroid-error`` fatal errors, and the rest. + +Refs #10914 diff --git a/pylint/testutils/_primer/comparator.py b/pylint/testutils/_primer/comparator.py index 655a050f04..6feb4f744f 100644 --- a/pylint/testutils/_primer/comparator.py +++ b/pylint/testutils/_primer/comparator.py @@ -5,15 +5,24 @@ from __future__ import annotations import json -from collections.abc import Iterator +from collections import defaultdict +from collections.abc import Callable, Hashable, Iterator +from difflib import SequenceMatcher from pathlib import Path from typing import NamedTuple from pylint.reporters.json_reporter import JSONMessage -from pylint.testutils._primer.primer_command import ( - PackageData, - PackageMessages, -) +from pylint.testutils._primer.primer_command import PackageData, PackageMessages + + +class ChangedMessage(NamedTuple): + """A message that was present on both runs but with altered details.""" + + old: JSONMessage + new: JSONMessage + + +_LOCATION_KEYS = {"line", "column", "endLine", "endColumn"} class PackageDiff(NamedTuple): @@ -22,6 +31,156 @@ class PackageDiff(NamedTuple): package: str missing: PackageData # emitted on main but not on the PR new: PackageData # emitted on the PR but not on main + changed: list[ChangedMessage] # same message, altered line / text + + +SYMBOL_RENAME_SIMILARITY_THRESHOLD = 0.5 + + +def _pair_by_key( + old_residuals: list[JSONMessage], + new_residuals: list[JSONMessage], + key: Callable[[JSONMessage], tuple[Hashable, ...]], + accept: Callable[[JSONMessage, JSONMessage], bool] = lambda _o, _n: True, +) -> tuple[list[ChangedMessage], list[JSONMessage], list[JSONMessage]]: + """Pair messages whose ``key`` matches, in input order. + + Two messages sharing the key are the "same warning" — if they differ only + in line numbers or message text, they should be reported as *changed* + rather than as a separate removal + addition. Leftovers on each side are + passed through to the next pass (or reported as missing/new). + + ``accept`` is an optional predicate that can veto a candidate pair (used to + avoid pairing two unrelated messages that happen to share the key). + """ + new_by_key: dict[tuple[Hashable, ...], list[JSONMessage]] = defaultdict(list) + for m in new_residuals: + new_by_key[key(m)].append(m) + + paired: list[ChangedMessage] = [] + final_missing: list[JSONMessage] = [] + matched_new: set[int] = set() + for old in old_residuals: + bucket = new_by_key.get(key(old)) + if bucket and accept(old, bucket[0]): + new = bucket.pop(0) + paired.append(ChangedMessage(old=old, new=new)) + matched_new.add(id(new)) + else: + final_missing.append(old) + final_new = [m for m in new_residuals if id(m) not in matched_new] + return paired, final_missing, final_new + + +def _is_symbol_rename(old: JSONMessage, new: JSONMessage) -> bool: + """True when the two symbols are textually similar enough to be a rename. + + Used to avoid pairing unrelated messages that happen to share a source + position (e.g. ``useless-suppression`` removed and ``locally-disabled`` + added on the same line — those are conceptually opposite, not a rename). + """ + ratio = SequenceMatcher(None, old["symbol"], new["symbol"]).ratio() + return ratio >= SYMBOL_RENAME_SIMILARITY_THRESHOLD + + +def _pair_residuals( + old_residuals: list[JSONMessage], new_residuals: list[JSONMessage] +) -> tuple[list[ChangedMessage], list[JSONMessage], list[JSONMessage]]: + """Pair residual messages with two passes of decreasing strictness. + + First by ``(symbol, path, obj)`` — catches line-only or message-only changes + for the same warning. Then by exact source location, gated on symbol + similarity — catches symbol renames such as ``used-before-assignment`` → + ``possibly-used-before-assignment``, where the same code position now + emits a renamed message. + """ + paired_by_symbol, missing, new = _pair_by_key( + old_residuals, + new_residuals, + key=lambda m: (m["symbol"], m["path"], m["obj"]), + ) + paired_by_location, missing, new = _pair_by_key( + missing, + new, + key=lambda m: ( + m["path"], + m["line"], + m["column"], + m.get("endLine"), + m.get("endColumn"), + ), + accept=_is_symbol_rename, + ) + return paired_by_symbol + paired_by_location, missing, new + + +def format_span(msg: JSONMessage) -> str: + """Format a message's location as ``line:col to endLine:endCol``.""" + start = f"{msg['line']}:{msg['column']}" + end_line = msg.get("endLine") + end_col = msg.get("endColumn") + if end_line is not None and end_col is not None: + return f"`{start}`-`{end_line}:{end_col}`" + return f"`{start}`" + + +def message_diff(change: ChangedMessage) -> str: + """Return a compact summary of changed fields between two messages. + + Location changes are merged into a single human-readable span. + String fields (like ``message``) get a ``diff`` code block so GitHub + renders them with red/green highlighting. + """ + old, new = change.old, change.new + changed_keys: set[str] = set() + for key in old.keys() | new.keys(): + if old.get(key) != new.get(key): + changed_keys.add(key) + + parts: list[str] = [] + # Location: combine line/column/endLine/endColumn into one sentence. + if changed_keys & _LOCATION_KEYS: + parts.append(f"Moved from {format_span(old)} to {format_span(new)}.") + + # Other fields (typically ``message`` or ``type``). + for key in sorted(changed_keys - _LOCATION_KEYS): + old_val = old[key] # type: ignore[literal-required] + new_val = new[key] # type: ignore[literal-required] + if ( + isinstance(old_val, str) + and isinstance(new_val, str) + and (len(old_val) > 40 or len(new_val) > 40) + ): + caret_line = _caret_hint(old_val, new_val) + diff_block = f"```diff\n- {old_val}\n+ {new_val}\n" + if caret_line: + diff_block += f" {caret_line}\n" + diff_block += "```" + parts.append(diff_block) + else: + parts.append(f"{key}: `{old_val}` → `{new_val}`") + return "\n\n".join(parts) + + +def _caret_hint(old: str, new: str) -> str: + """Build a ``^`` marker line highlighting changed spans in *new*. + + Uses SequenceMatcher to find which parts of *new* differ from *old* + and places ``^`` characters under them (aligned with the ``+ `` prefix). + Returns an empty string when the whole line changed (carets wouldn't help). + """ + matcher = SequenceMatcher(None, old, new) + carets = [" "] * len(new) + changed_count = 0 + for tag, _i1, _i2, j1, j2 in matcher.get_opcodes(): + if tag != "equal": + for j in range(j1, j2): + carets[j] = "^" + changed_count += j2 - j1 + # If most of the string changed, carets are just noise. + if changed_count > len(new) * 0.6: + return "" + return "".join(carets).rstrip() class Comparator: @@ -58,24 +217,32 @@ def __iter__(self) -> Iterator[PackageDiff]: main_data = self._main_data pr_data = self._pr_data - missing_messages: PackageMessages = {} for package, data in main_data.items(): - package_missing_messages: list[JSONMessage] = [] + # First pass: exact-match removal. + pr_messages = list(pr_data[package]["messages"]) + residual_old: list[JSONMessage] = [] for message in data["messages"]: try: - pr_data[package]["messages"].remove(message) + pr_messages.remove(message) except ValueError: - package_missing_messages.append(message) - missing_messages[package] = PackageData( - commit=pr_data[package]["commit"], - messages=package_missing_messages, + residual_old.append(message) + + # Second pass: pair residuals by symbol then by location to + # detect *changed* messages (same warning, different line/text, + # or a symbol rename at the same source position). + paired, final_missing, final_new = _pair_residuals( + residual_old, pr_messages ) - for package, pkg_missing in missing_messages.items(): - new_messages = pr_data[package] - if not pkg_missing["messages"] and not new_messages["messages"]: + if not final_missing and not final_new and not paired: continue - yield PackageDiff(package, pkg_missing, new_messages) + commit = pr_data[package]["commit"] + yield PackageDiff( + package, + missing=PackageData(commit=commit, messages=final_missing), + new=PackageData(commit=commit, messages=final_new), + changed=paired, + ) @staticmethod def _load_json(file_path: Path | str) -> PackageMessages: diff --git a/pylint/testutils/_primer/primer_compare_command.py b/pylint/testutils/_primer/primer_compare_command.py index e1c02300ad..222ad09a33 100644 --- a/pylint/testutils/_primer/primer_compare_command.py +++ b/pylint/testutils/_primer/primer_compare_command.py @@ -3,12 +3,38 @@ # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt from __future__ import annotations +import re +from collections.abc import Callable from pathlib import PurePosixPath -from pylint.testutils._primer.comparator import Comparator -from pylint.testutils._primer.primer_command import PackageData, PrimerCommand +from pylint.reporters.json_reporter import JSONMessage +from pylint.testutils._primer.comparator import ( + ChangedMessage, + Comparator, + message_diff, +) +from pylint.testutils._primer.primer_command import PrimerCommand MAX_GITHUB_COMMENT_LENGTH = 65536 +USELESS_SUPPRESSION_RE = re.compile(r"Useless suppression of '(.+)'") + + +def _format_messages( + messages: list[JSONMessage], + source_link: Callable[[JSONMessage], str], +) -> str: + """Format a list of messages as a numbered body for a ``
`` block.""" + body = "" + for count, msg in enumerate(messages, 1): + body += ( + f"{count}) {msg['symbol']}:\n*{msg['message']}*\n" f"{source_link(msg)}\n" + ) + return body + + +def _details_section(title: str, body: str) -> str: + # Blank line after
required for GitHub markdown rendering. + return f"{title}\n\n
\n\n{body}
\n\n" class CompareCommand(PrimerCommand): @@ -26,9 +52,17 @@ def _create_comment(self, comparator: Comparator) -> str: if len(comment) >= MAX_GITHUB_COMMENT_LENGTH: break package = diff.package - comment += f"\n**Effect on [{package}]({self.packages[package].url}):**\n\n" - comment += self._format_new_messages(package, diff.new) - comment += self._format_missing_messages(package, diff.missing) + url = self.packages[package].url + assert not url.endswith( + ".git" + ), "You don't need the .git at the end of the github url." + source_link = self._source_link_for(package, diff.new["commit"]) + comment += f"\n**Effect on [{package}]({url}):**\n\n" + comment += self._format_changed_messages(diff.changed, source_link) + comment += self._format_new_messages(diff.new["messages"], source_link) + comment += self._format_missing_messages( + diff.missing["messages"], source_link + ) comment = ( f"🤖 **Effect of this PR on checked open source code:** 🤖\n\n{comment}" if comment @@ -39,71 +73,84 @@ def _create_comment(self, comparator: Comparator) -> str: ) return self._truncate_comment(comment) - def _format_new_messages(self, package: str, new_messages: PackageData) -> str: - comment = "" - count = 1 - astroid_errors = 0 - new_non_astroid_messages = "" - if new_messages["messages"]: - print("Now emitted:") - for message in new_messages["messages"]: - filepath = str( - PurePosixPath(message["path"]).relative_to( - self.packages[package].clone_directory - ) + def _source_link_for( + self, package: str, commit: str + ) -> Callable[[JSONMessage], str]: + clone_dir = self.packages[package].clone_directory + url = self.packages[package].url + + def _link(msg: JSONMessage) -> str: + filepath = str(PurePosixPath(msg["path"]).relative_to(clone_dir)) + return f"{url}/blob/{commit}/{filepath}#L{msg['line']}" + + return _link + + def _format_changed_messages( + self, + changed: list[ChangedMessage], + source_link: Callable[[JSONMessage], str], + ) -> str: + if not changed: + return "" + print("Changed:") + body = "" + for count, change in enumerate(changed, 1): + print(change.new) + body += ( + f"{count}) [{change.new['symbol']}]({source_link(change.new)}):\n" + f"{message_diff(change)}\n" ) - # Existing astroid errors may still show up as "new" because the timestamp - # in the message is slightly different. + return _details_section("Changed messages:", body) + + def _format_new_messages( + self, + messages: list[JSONMessage], + source_link: Callable[[JSONMessage], str], + ) -> str: + if not messages: + return "" + print("Now emitted:") + astroid_errors = 0 + fixed_fp: list[JSONMessage] = [] + other_new: list[JSONMessage] = [] + for message in messages: + print(message) if message["symbol"] == "astroid-error": astroid_errors += 1 + elif USELESS_SUPPRESSION_RE.match(message["message"]): + fixed_fp.append(message) else: - new_non_astroid_messages += ( - f"{count}) {message['symbol']}:\n*{message['message']}*\n" - f"{self.packages[package].url}/blob/{new_messages['commit']}/{filepath}#L{message['line']}\n" - ) - print(message) - count += 1 + other_new.append(message) + out = "" if astroid_errors: - comment += ( + out += ( f'{astroid_errors} "astroid error(s)" were found. ' "Please open the GitHub Actions log to see what failed or crashed.\n\n" ) - if new_non_astroid_messages: - comment += ( - "The following messages are now emitted:\n\n
\n\n" - + new_non_astroid_messages - + "
\n\n" + if fixed_fp: + out += _details_section( + "🎉 Fixed false positives:", _format_messages(fixed_fp, source_link) ) - return comment + if other_new: + out += _details_section( + "New messages:", _format_messages(other_new, source_link) + ) + return out def _format_missing_messages( - self, package: str, missing_messages: PackageData + self, + messages: list[JSONMessage], + source_link: Callable[[JSONMessage], str], ) -> str: - comment = "" - count = 1 - if missing_messages["messages"]: - comment += "The following messages are no longer emitted:\n\n
\n\n" - print("No longer emitted:") - for message in missing_messages["messages"]: - comment += f"{count}) {message['symbol']}:\n*{message['message']}*\n" - filepath = str( - PurePosixPath(message["path"]).relative_to( - self.packages[package].clone_directory - ) - ) - assert not self.packages[package].url.endswith( - ".git" - ), "You don't need the .git at the end of the github url." - comment += ( - f"{self.packages[package].url}" - f"/blob/{missing_messages['commit']}/{filepath}#L{message['line']}\n" - ) - count += 1 + if not messages: + return "" + print("No longer emitted:") + for message in messages: print(message) - if missing_messages["messages"]: - comment += "
\n\n" - return comment + return _details_section( + "Removed messages:", _format_messages(messages, source_link) + ) def _truncate_comment(self, comment: str) -> str: """GitHub allows only a set number of characters in a comment.""" diff --git a/tests/testutils/_primer/batched_cases/expected.txt b/tests/testutils/_primer/batched_cases/expected.txt index 2c112f6e75..9427ea15e6 100644 --- a/tests/testutils/_primer/batched_cases/expected.txt +++ b/tests/testutils/_primer/batched_cases/expected.txt @@ -3,7 +3,7 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are no longer emitted: +Removed messages:
diff --git a/tests/testutils/_primer/batched_cases/expected_comparator.json b/tests/testutils/_primer/batched_cases/expected_comparator.json index e3a42bfd31..3be623243d 100644 --- a/tests/testutils/_primer/batched_cases/expected_comparator.json +++ b/tests/testutils/_primer/batched_cases/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 2, "new": 0 }] +[{ "package": "astroid", "missing": 2, "new": 0, "changed": 0 }] diff --git a/tests/testutils/_primer/cases/confidence_changed/expected.txt b/tests/testutils/_primer/cases/confidence_changed/expected.txt index 8555240d13..717bb004f8 100644 --- a/tests/testutils/_primer/cases/confidence_changed/expected.txt +++ b/tests/testutils/_primer/cases/confidence_changed/expected.txt @@ -3,22 +3,12 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) dangerous-default-value: -*Dangerous default value [] as argument* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/inference.py#L42 -
- -The following messages are no longer emitted: - -
- -1) dangerous-default-value: -*Dangerous default value [] as argument* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/inference.py#L42 +1) [dangerous-default-value](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/inference.py#L42): +confidence: `UNDEFINED` → `HIGH`
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/confidence_changed/expected_comparator.json b/tests/testutils/_primer/cases/confidence_changed/expected_comparator.json index d826f8390a..47824cb2e1 100644 --- a/tests/testutils/_primer/cases/confidence_changed/expected_comparator.json +++ b/tests/testutils/_primer/cases/confidence_changed/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/line_moved/expected.txt b/tests/testutils/_primer/cases/line_moved/expected.txt index 27266ea0b8..b52b2a9fc1 100644 --- a/tests/testutils/_primer/cases/line_moved/expected.txt +++ b/tests/testutils/_primer/cases/line_moved/expected.txt @@ -3,22 +3,12 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) too-complex: -*'my_function' is too complex. The McCabe rating is 18* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L103 -
- -The following messages are no longer emitted: - -
- -1) too-complex: -*'my_function' is too complex. The McCabe rating is 18* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L100 +1) [too-complex](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L103): +Moved from `100:0`-`100:15` to `103:0`-`103:15`.
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/line_moved/expected_comparator.json b/tests/testutils/_primer/cases/line_moved/expected_comparator.json index d826f8390a..47824cb2e1 100644 --- a/tests/testutils/_primer/cases/line_moved/expected_comparator.json +++ b/tests/testutils/_primer/cases/line_moved/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/message_changed/expected.txt b/tests/testutils/_primer/cases/message_changed/expected.txt index a99896696e..cb4812421a 100644 --- a/tests/testutils/_primer/cases/message_changed/expected.txt +++ b/tests/testutils/_primer/cases/message_changed/expected.txt @@ -3,22 +3,16 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) locally-disabled: -*Locally disabling redefined-builtin [we added some text in the message] (W0622)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91 -
- -The following messages are no longer emitted: - -
- -1) locally-disabled: -*Locally disabling redefined-builtin (W0622)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91 +1) [locally-disabled](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91): +```diff +- Locally disabling redefined-builtin (W0622) ++ Locally disabling redefined-builtin [we added some text in the message] (W0622) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +```
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/message_changed/expected_comparator.json b/tests/testutils/_primer/cases/message_changed/expected_comparator.json index d826f8390a..47824cb2e1 100644 --- a/tests/testutils/_primer/cases/message_changed/expected_comparator.json +++ b/tests/testutils/_primer/cases/message_changed/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/message_changed/expected_truncated.txt b/tests/testutils/_primer/cases/message_changed/expected_truncated.txt index 44926e4485..55d70bb96f 100644 --- a/tests/testutils/_primer/cases/message_changed/expected_truncated.txt +++ b/tests/testutils/_primer/cases/message_changed/expected_truncated.txt @@ -3,14 +3,15 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) locally-disabled: -*Locally disabling redefined-builtin [we added some text in the message]... +1) [locally-disabled](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91): +```diff +- Locally disabling...
-*This comment was truncated because GitHub allows only 525 characters in a comment.* +*This comment was truncated because GitHub allows only 450 characters in a comment.* *This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/message_changed/expected_truncated_in_details.txt b/tests/testutils/_primer/cases/message_changed/expected_truncated_in_details.txt index c8406b21f8..a285996bf7 100644 --- a/tests/testutils/_primer/cases/message_changed/expected_truncated_in_details.txt +++ b/tests/testutils/_primer/cases/message_changed/expected_truncated_in_details.txt @@ -3,14 +3,13 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) locally-disabled: -*Locally disabling redefined-builtin [we added some text in the... +1)...
-*This comment was truncated because GitHub allows only 420 characters in a comment.* +*This comment was truncated because GitHub allows only 400 characters in a comment.* *This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/message_changed_line/expected.txt b/tests/testutils/_primer/cases/message_changed_line/expected.txt index 959804eb5a..acb71c2498 100644 --- a/tests/testutils/_primer/cases/message_changed_line/expected.txt +++ b/tests/testutils/_primer/cases/message_changed_line/expected.txt @@ -3,22 +3,18 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) too-complex: -*'my_function' is too complex. The McCabe rating is 17* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L103 -
- -The following messages are no longer emitted: - -
+1) [too-complex](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L103): +Moved from `100:0`-`100:15` to `103:0`-`103:15`. -1) too-complex: -*'my_function' is too complex. The McCabe rating is 18* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L100 +```diff +- 'my_function' is too complex. The McCabe rating is 18 ++ 'my_function' is too complex. The McCabe rating is 17 + ^ +```
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/message_changed_line/expected_comparator.json b/tests/testutils/_primer/cases/message_changed_line/expected_comparator.json index d826f8390a..47824cb2e1 100644 --- a/tests/testutils/_primer/cases/message_changed_line/expected_comparator.json +++ b/tests/testutils/_primer/cases/message_changed_line/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/mixed_changes/expected.txt b/tests/testutils/_primer/cases/mixed_changes/expected.txt index 9590f932d6..23511399cd 100644 --- a/tests/testutils/_primer/cases/mixed_changes/expected.txt +++ b/tests/testutils/_primer/cases/mixed_changes/expected.txt @@ -3,28 +3,28 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) locally-disabled: -*Locally disabling redefined-builtin [we added some text in the message] (W0622)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91 -2) too-complex: -*'my_function' is too complex. The McCabe rating is 17* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L105 -
- -The following messages are no longer emitted: - -
- -1) locally-disabled: -*Locally disabling redefined-builtin (W0622)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91 -2) too-complex: -*'my_function' is too complex. The McCabe rating is 18* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L100 +1) [locally-disabled](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91): +```diff +- Locally disabling redefined-builtin (W0622) ++ Locally disabling redefined-builtin [we added some text in the message] (W0622) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` +2) [too-complex](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L105): +Moved from `100:0`-`100:15` to `105:0`-`105:15`. + +confidence: `UNDEFINED` → `HIGH` + +```diff +- 'my_function' is too complex. The McCabe rating is 18 ++ 'my_function' is too complex. The McCabe rating is 17 + ^ +``` +3) [unknown-option-value](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/__init__.py#L91): +confidence: `UNDEFINED` → `HIGH`
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/mixed_changes/expected_comparator.json b/tests/testutils/_primer/cases/mixed_changes/expected_comparator.json index a0e7f6f710..6e33a850d4 100644 --- a/tests/testutils/_primer/cases/mixed_changes/expected_comparator.json +++ b/tests/testutils/_primer/cases/mixed_changes/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 2, "new": 2 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 3 }] diff --git a/tests/testutils/_primer/cases/mixed_changes/pr.json b/tests/testutils/_primer/cases/mixed_changes/pr.json index 87d7e44b04..fbadd2d9fe 100644 --- a/tests/testutils/_primer/cases/mixed_changes/pr.json +++ b/tests/testutils/_primer/cases/mixed_changes/pr.json @@ -29,7 +29,7 @@ "symbol": "too-complex", "message": "'my_function' is too complex. The McCabe rating is 17", "messageId": "R1260", - "confidence": "UNDEFINED", + "confidence": "HIGH", "absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/node_classes.py" }, { @@ -44,7 +44,7 @@ "symbol": "unknown-option-value", "message": "Unknown option value for 'disable', expected a valid pylint message and got 'Ellipsis'", "messageId": "W0012", - "confidence": "UNDEFINED", + "confidence": "HIGH", "absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/__init__.py" } ] diff --git a/tests/testutils/_primer/cases/multi_package/expected.txt b/tests/testutils/_primer/cases/multi_package/expected.txt index 46f9611eb7..5da2087bc3 100644 --- a/tests/testutils/_primer/cases/multi_package/expected.txt +++ b/tests/testutils/_primer/cases/multi_package/expected.txt @@ -3,28 +3,24 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) too-complex: -*'my_function' is too complex. The McCabe rating is 17* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L105 -
- -The following messages are no longer emitted: - -
+1) [too-complex](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L105): +Moved from `100:0`-`100:15` to `105:0`-`105:15`. -1) too-complex: -*'my_function' is too complex. The McCabe rating is 18* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L100 +```diff +- 'my_function' is too complex. The McCabe rating is 18 ++ 'my_function' is too complex. The McCabe rating is 17 + ^ +```
**Effect on [astropy](https://github.com/astropy/astropy):** -The following messages are now emitted: +New messages:
@@ -33,7 +29,7 @@ The following messages are now emitted: https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14
-The following messages are no longer emitted: +Removed messages:
diff --git a/tests/testutils/_primer/cases/multi_package/expected_comparator.json b/tests/testutils/_primer/cases/multi_package/expected_comparator.json index 456a50f703..38f460088e 100644 --- a/tests/testutils/_primer/cases/multi_package/expected_comparator.json +++ b/tests/testutils/_primer/cases/multi_package/expected_comparator.json @@ -1,4 +1,4 @@ [ - { "package": "astroid", "missing": 1, "new": 1 }, - { "package": "astropy", "missing": 1, "new": 1 } + { "package": "astroid", "missing": 0, "new": 0, "changed": 1 }, + { "package": "astropy", "missing": 1, "new": 1, "changed": 0 } ] diff --git a/tests/testutils/_primer/cases/multi_package/expected_truncated_break.txt b/tests/testutils/_primer/cases/multi_package/expected_truncated_break.txt index 331f74ff7f..a285996bf7 100644 --- a/tests/testutils/_primer/cases/multi_package/expected_truncated_break.txt +++ b/tests/testutils/_primer/cases/multi_package/expected_truncated_break.txt @@ -3,14 +3,13 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) too-complex: -*'my_function' is too complex. The McCabe rating is... +1)...
-*This comment was truncated because GitHub allows only 500 characters in a comment.* +*This comment was truncated because GitHub allows only 400 characters in a comment.* *This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/new_message/expected.txt b/tests/testutils/_primer/cases/new_message/expected.txt index 425df41d6a..040f70014a 100644 --- a/tests/testutils/_primer/cases/new_message/expected.txt +++ b/tests/testutils/_primer/cases/new_message/expected.txt @@ -3,7 +3,7 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +New messages:
diff --git a/tests/testutils/_primer/cases/new_message/expected_comparator.json b/tests/testutils/_primer/cases/new_message/expected_comparator.json index e436268fa3..1d944b5bb8 100644 --- a/tests/testutils/_primer/cases/new_message/expected_comparator.json +++ b/tests/testutils/_primer/cases/new_message/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 0, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 1, "changed": 0 }] diff --git a/tests/testutils/_primer/cases/new_messages_classified/expected.txt b/tests/testutils/_primer/cases/new_messages_classified/expected.txt new file mode 100644 index 0000000000..b07e280a11 --- /dev/null +++ b/tests/testutils/_primer/cases/new_messages_classified/expected.txt @@ -0,0 +1,29 @@ +🤖 **Effect of this PR on checked open source code:** 🤖 + + +**Effect on [astropy](https://github.com/astropy/astropy):** + +1 "astroid error(s)" were found. Please open the GitHub Actions log to see what failed or crashed. + +🎉 Fixed false positives: + +
+ +1) useless-suppression: +*Useless suppression of 'looping-through-iterator'* +https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14 +
+ +New messages: + +
+ +1) locally-disabled: +*Locally disabling looping-through-iterator (W4801)* +https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14 +2) unused-variable: +*Unused variable 'foo'* +https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L42 +
+ +*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/new_messages_classified/expected_comparator.json b/tests/testutils/_primer/cases/new_messages_classified/expected_comparator.json new file mode 100644 index 0000000000..bb57521031 --- /dev/null +++ b/tests/testutils/_primer/cases/new_messages_classified/expected_comparator.json @@ -0,0 +1 @@ +[{ "package": "astropy", "missing": 0, "new": 4, "changed": 0 }] diff --git a/tests/testutils/_primer/cases/new_messages_classified/main.json b/tests/testutils/_primer/cases/new_messages_classified/main.json new file mode 100644 index 0000000000..337476e532 --- /dev/null +++ b/tests/testutils/_primer/cases/new_messages_classified/main.json @@ -0,0 +1,6 @@ +{ + "astropy": { + "commit": "1fb40bc1f22f176254ef583065aa155f53f3b414", + "messages": [] + } +} diff --git a/tests/testutils/_primer/cases/new_messages_classified/pr.json b/tests/testutils/_primer/cases/new_messages_classified/pr.json new file mode 100644 index 0000000000..238805c199 --- /dev/null +++ b/tests/testutils/_primer/cases/new_messages_classified/pr.json @@ -0,0 +1,67 @@ +{ + "astropy": { + "commit": "1fb40bc1f22f176254ef583065aa155f53f3b414", + "messages": [ + { + "type": "error", + "module": "astropy.coordinates.angles.angle_parsetab", + "obj": "", + "line": 1, + "column": 0, + "endLine": null, + "endColumn": null, + "path": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py", + "symbol": "astroid-error", + "message": "Fatal error while checking 'astropy/module.py'. Please open an issue.", + "messageId": "F0002", + "confidence": "UNDEFINED", + "absolutePath": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py" + }, + { + "type": "info", + "module": "astropy.coordinates.angles.angle_parsetab", + "obj": "", + "line": 14, + "column": 0, + "endLine": null, + "endColumn": null, + "path": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py", + "symbol": "locally-disabled", + "message": "Locally disabling looping-through-iterator (W4801)", + "messageId": "I0011", + "confidence": "UNDEFINED", + "absolutePath": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py" + }, + { + "type": "warning", + "module": "astropy.coordinates.angles.angle_parsetab", + "obj": "", + "line": 14, + "column": 0, + "endLine": null, + "endColumn": null, + "path": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py", + "symbol": "useless-suppression", + "message": "Useless suppression of 'looping-through-iterator'", + "messageId": "I0021", + "confidence": "UNDEFINED", + "absolutePath": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py" + }, + { + "type": "warning", + "module": "astropy.coordinates.angles.angle_parsetab", + "obj": "my_function", + "line": 42, + "column": 4, + "endLine": 42, + "endColumn": 16, + "path": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py", + "symbol": "unused-variable", + "message": "Unused variable 'foo'", + "messageId": "W0612", + "confidence": "UNDEFINED", + "absolutePath": "tests/.pylint_primer_tests/astropy/astropy/astropy/coordinates/angles/angle_parsetab.py" + } + ] + } +} diff --git a/tests/testutils/_primer/cases/removed_message/expected.txt b/tests/testutils/_primer/cases/removed_message/expected.txt index 88af536d71..0200400648 100644 --- a/tests/testutils/_primer/cases/removed_message/expected.txt +++ b/tests/testutils/_primer/cases/removed_message/expected.txt @@ -3,7 +3,7 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are no longer emitted: +Removed messages:
diff --git a/tests/testutils/_primer/cases/removed_message/expected_comparator.json b/tests/testutils/_primer/cases/removed_message/expected_comparator.json index cd879eeea8..723706ace4 100644 --- a/tests/testutils/_primer/cases/removed_message/expected_comparator.json +++ b/tests/testutils/_primer/cases/removed_message/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 0 }] +[{ "package": "astroid", "missing": 1, "new": 0, "changed": 0 }] diff --git a/tests/testutils/_primer/cases/symbol_renamed/expected.txt b/tests/testutils/_primer/cases/symbol_renamed/expected.txt new file mode 100644 index 0000000000..5c723cc900 --- /dev/null +++ b/tests/testutils/_primer/cases/symbol_renamed/expected.txt @@ -0,0 +1,26 @@ +🤖 **Effect of this PR on checked open source code:** 🤖 + + +**Effect on [astroid](https://github.com/pylint-dev/astroid):** + +Changed messages: + +
+ +1) [possibly-used-before-assignment](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/wcs.py#L3072): +confidence: `HIGH` → `INFERENCE` + +```diff +- Using variable 'orig_key' before assignment ++ Possibly using variable 'orig_key' before assignment + ^^^^^^^^^^ +``` + +messageId: `E0601` → `E0606` + +symbol: `used-before-assignment` → `possibly-used-before-assignment` + +type: `error` → `warning` +
+ +*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/symbol_renamed/expected_comparator.json b/tests/testutils/_primer/cases/symbol_renamed/expected_comparator.json new file mode 100644 index 0000000000..47824cb2e1 --- /dev/null +++ b/tests/testutils/_primer/cases/symbol_renamed/expected_comparator.json @@ -0,0 +1 @@ +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/symbol_renamed/main.json b/tests/testutils/_primer/cases/symbol_renamed/main.json new file mode 100644 index 0000000000..e655ae656d --- /dev/null +++ b/tests/testutils/_primer/cases/symbol_renamed/main.json @@ -0,0 +1,22 @@ +{ + "astroid": { + "commit": "1234567890abcdef", + "messages": [ + { + "type": "error", + "module": "astroid.wcs", + "obj": "WCS.fix", + "line": 3072, + "column": 12, + "endLine": 3072, + "endColumn": 20, + "path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/wcs.py", + "symbol": "used-before-assignment", + "message": "Using variable 'orig_key' before assignment", + "messageId": "E0601", + "confidence": "HIGH", + "absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/wcs.py" + } + ] + } +} diff --git a/tests/testutils/_primer/cases/symbol_renamed/pr.json b/tests/testutils/_primer/cases/symbol_renamed/pr.json new file mode 100644 index 0000000000..3b90e6c589 --- /dev/null +++ b/tests/testutils/_primer/cases/symbol_renamed/pr.json @@ -0,0 +1,22 @@ +{ + "astroid": { + "commit": "123456789abcdef", + "messages": [ + { + "type": "warning", + "module": "astroid.wcs", + "obj": "WCS.fix", + "line": 3072, + "column": 12, + "endLine": 3072, + "endColumn": 20, + "path": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/wcs.py", + "symbol": "possibly-used-before-assignment", + "message": "Possibly using variable 'orig_key' before assignment", + "messageId": "E0606", + "confidence": "INFERENCE", + "absolutePath": "tests/.pylint_primer_tests/pylint-dev/astroid/astroid/wcs.py" + } + ] + } +} diff --git a/tests/testutils/_primer/cases/type_changed/expected.txt b/tests/testutils/_primer/cases/type_changed/expected.txt index d83b197c08..64423538a0 100644 --- a/tests/testutils/_primer/cases/type_changed/expected.txt +++ b/tests/testutils/_primer/cases/type_changed/expected.txt @@ -3,22 +3,12 @@ **Effect on [astroid](https://github.com/pylint-dev/astroid):** -The following messages are now emitted: +Changed messages:
-1) line-too-long: -*Line too long (120/100)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L50 -
- -The following messages are no longer emitted: - -
- -1) line-too-long: -*Line too long (120/100)* -https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L50 +1) [line-too-long](https://github.com/pylint-dev/astroid/blob/123456789abcdef/astroid/node_classes.py#L50): +type: `convention` → `warning`
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/type_changed/expected_comparator.json b/tests/testutils/_primer/cases/type_changed/expected_comparator.json index d826f8390a..47824cb2e1 100644 --- a/tests/testutils/_primer/cases/type_changed/expected_comparator.json +++ b/tests/testutils/_primer/cases/type_changed/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astroid", "missing": 1, "new": 1 }] +[{ "package": "astroid", "missing": 0, "new": 0, "changed": 1 }] diff --git a/tests/testutils/_primer/cases/useless_suppression/expected.txt b/tests/testutils/_primer/cases/useless_suppression/expected.txt index 8f56c44551..5120f86953 100644 --- a/tests/testutils/_primer/cases/useless_suppression/expected.txt +++ b/tests/testutils/_primer/cases/useless_suppression/expected.txt @@ -3,16 +3,22 @@ **Effect on [astropy](https://github.com/astropy/astropy):** -The following messages are now emitted: +🎉 Fixed false positives: + +
+ +1) useless-suppression: +*Useless suppression of 'looping-through-iterator'* +https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14 +
+ +New messages:
1) locally-disabled: *Locally disabling looping-through-iterator (W4801)* https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14 -2) useless-suppression: -*Useless suppression of 'looping-through-iterator'* -https://github.com/astropy/astropy/blob/1fb40bc1f22f176254ef583065aa155f53f3b414/astropy/coordinates/angles/angle_parsetab.py#L14
*This comment was generated for commit v2.14.2* diff --git a/tests/testutils/_primer/cases/useless_suppression/expected_comparator.json b/tests/testutils/_primer/cases/useless_suppression/expected_comparator.json index b02271a012..68ea0d61b5 100644 --- a/tests/testutils/_primer/cases/useless_suppression/expected_comparator.json +++ b/tests/testutils/_primer/cases/useless_suppression/expected_comparator.json @@ -1 +1 @@ -[{ "package": "astropy", "missing": 0, "new": 2 }] +[{ "package": "astropy", "missing": 0, "new": 2, "changed": 0 }] diff --git a/tests/testutils/_primer/test_comparator.py b/tests/testutils/_primer/test_comparator.py index 212af59e61..c672a0fcea 100644 --- a/tests/testutils/_primer/test_comparator.py +++ b/tests/testutils/_primer/test_comparator.py @@ -4,14 +4,41 @@ import json from pathlib import Path +from typing import cast import pytest -from pylint.testutils._primer.comparator import Comparator +from pylint.reporters.json_reporter import JSONMessage +from pylint.testutils._primer.comparator import ( + Comparator, + _caret_hint, + _is_symbol_rename, + format_span, +) CASES_PATH = Path(__file__).parent / "cases" +def _msg(**overrides: object) -> JSONMessage: + base: dict[str, object] = { + "type": "warning", + "module": "m", + "obj": "", + "line": 1, + "column": 0, + "endLine": 1, + "endColumn": 5, + "path": "m.py", + "symbol": "s", + "message": "msg", + "messageId": "W0000", + "confidence": "UNDEFINED", + "absolutePath": "m.py", + } + base.update(overrides) + return cast(JSONMessage, base) + + @pytest.mark.parametrize( "directory", [pytest.param(p, id=p.name) for p in CASES_PATH.iterdir() if p.is_dir()], @@ -22,10 +49,38 @@ def test_comparator(directory: Path) -> None: expected = json.loads((directory / "expected_comparator.json").read_text("utf-8")) results = list(comparator) assert len(results) == len(expected) - for (package, missing, new), exp in zip(results, expected): + for (package, missing, new, changed), exp in zip(results, expected): assert package == exp["package"] assert len(missing["messages"]) == exp["missing"] assert len(new["messages"]) == exp["new"] + assert len(changed) == exp["changed"] + + +def test_format_span_without_end_position() -> None: + """Messages missing endLine/endColumn fall back to a start-only span.""" + assert ( + format_span(_msg(line=42, column=7, endLine=None, endColumn=None)) == "`42:7`" + ) + + +def test_caret_hint_returns_empty_when_mostly_changed() -> None: + """When more than 60% of the text differs, carets are noise and are skipped.""" + assert _caret_hint("hello world", "goodbye universe") == "" + + +@pytest.mark.parametrize( + ("old_symbol", "new_symbol", "expected"), + [ + ("used-before-assignment", "possibly-used-before-assignment", True), + ("abstract-method", "no-abstract-method", True), + ("useless-suppression", "locally-disabled", False), + ("too-complex", "too-many-locals", False), + ], +) +def test_is_symbol_rename(old_symbol: str, new_symbol: str, expected: bool) -> None: + old = _msg(symbol=old_symbol) + new = _msg(symbol=new_symbol) + assert _is_symbol_rename(old, new) is expected def test_comparator_batched() -> None: @@ -38,7 +93,8 @@ def test_comparator_batched() -> None: expected = json.loads((fixture / "expected_comparator.json").read_text("utf-8")) results = list(comparator) assert len(results) == len(expected) - for (package, missing, new), exp in zip(results, expected): + for (package, missing, new, changed), exp in zip(results, expected): assert package == exp["package"] assert len(missing["messages"]) == exp["missing"] assert len(new["messages"]) == exp["new"] + assert len(changed) == exp["changed"] diff --git a/tests/testutils/_primer/test_primer.py b/tests/testutils/_primer/test_primer.py index d639a27c19..69f675f418 100644 --- a/tests/testutils/_primer/test_primer.py +++ b/tests/testutils/_primer/test_primer.py @@ -77,7 +77,7 @@ def test_compare_batched(self) -> None: def test_truncated_compare(self) -> None: """Test for the truncation of comments that are too long.""" - max_comment_length = 525 + max_comment_length = 450 directory = CASES_PATH / "message_changed" with patch( "pylint.testutils._primer.primer_compare_command.MAX_GITHUB_COMMENT_LENGTH", @@ -90,7 +90,7 @@ def test_truncated_compare(self) -> None: def test_truncated_compare_stops_iterating_packages(self) -> None: """Once the comment exceeds MAX, further packages should be skipped.""" - max_comment_length = 500 + max_comment_length = 400 directory = CASES_PATH / "multi_package" with patch( "pylint.testutils._primer.primer_compare_command.MAX_GITHUB_COMMENT_LENGTH", @@ -107,7 +107,7 @@ def test_truncated_compare_stops_iterating_packages(self) -> None: def test_truncated_compare_in_details(self) -> None: """Test for the truncation of comments that are too long inside details.""" - max_comment_length = 420 + max_comment_length = 400 directory = CASES_PATH / "message_changed" with patch( "pylint.testutils._primer.primer_compare_command.MAX_GITHUB_COMMENT_LENGTH",