From 8898465c5003257be717b90b1cab3544687a8f90 Mon Sep 17 00:00:00 2001 From: Julfried Date: Thu, 22 May 2025 22:02:28 +0200 Subject: [PATCH 1/5] Escape characters in mermaid viewer --- pylint/pyreverse/mermaidjs_printer.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/pylint/pyreverse/mermaidjs_printer.py b/pylint/pyreverse/mermaidjs_printer.py index 22a8f768b1..621c60f993 100644 --- a/pylint/pyreverse/mermaidjs_printer.py +++ b/pylint/pyreverse/mermaidjs_printer.py @@ -32,6 +32,14 @@ def _open_graph(self) -> None: self.emit("classDiagram") self._inc_indent() + def _escape_mermaid_text(self, text: str) -> str: + """Escape text to prevent Mermaid from interpreting it as Markdown + formatting. + """ + # Escape characters that conflict with Markdown formatting + text = text.replace("__", r"\_\_") # Double underscore → escaped + return text + def emit_node( self, name: str, @@ -48,14 +56,24 @@ def emit_node( nodetype = self.NODES[type_] body = [] if properties.attrs: - body.extend(properties.attrs) + # Escape attribute names to prevent Markdown formatting issues + escaped_attrs = [ + self._escape_mermaid_text(attr) for attr in properties.attrs + ] + body.extend(escaped_attrs) if properties.methods: for func in properties.methods: args = self._get_method_arguments(func) - line = f"{func.name}({', '.join(args)})" + # Escape method name and arguments + escaped_method_name = self._escape_mermaid_text(func.name) + escaped_args = [self._escape_mermaid_text(arg) for arg in args] + line = f"{escaped_method_name}({', '.join(escaped_args)})" line += "*" if func.is_abstract() else "" if func.returns: - line += f" {get_annotation_label(func.returns)}" + # Escape return type annotation + return_type = get_annotation_label(func.returns) + escaped_return_type = self._escape_mermaid_text(return_type) + line += f" {escaped_return_type}" body.append(line) name = name.split(".")[-1] self.emit(f"{nodetype} {name} {{") @@ -80,7 +98,7 @@ def emit_edge( to_node = to_node.split(".")[-1] edge = f"{from_node} {self.ARROWS[type_]} {to_node}" if label: - edge += f" : {label}" + edge += f" : {self._escape_mermaid_text(label)}" self.emit(edge) def _close_graph(self) -> None: From 05debcf132d3065201dfd7601387253aebb7c63c Mon Sep 17 00:00:00 2001 From: Julfried Date: Thu, 22 May 2025 22:05:50 +0200 Subject: [PATCH 2/5] Update test files --- .../aggregation_filtering/all.mmd | 18 +++++++++--------- .../aggregation_filtering/other.mmd | 14 +++++++------- .../aggregation_filtering/special.mmd | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/all.mmd b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/all.mmd index 3b445288a1..378ef5ccaf 100644 --- a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/all.mmd +++ b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/all.mmd @@ -1,25 +1,25 @@ classDiagram class P { name : str - __init__(name: str) + \_\_init\_\_(name: str) } class PrivateAttr { - __x - __init__() + \_\_x + \_\_init\_\_() } class ProtectedAttr { _x - __init__() + \_\_init\_\_() } class PublicAttr { x - __init__() + \_\_init\_\_() } class SpecialAttr { - __x__ - __init__() + \_\_x\_\_ + \_\_init\_\_() } - P --* PrivateAttr : __x + P --* PrivateAttr : \_\_x P --* ProtectedAttr : _x P --* PublicAttr : x - P --* SpecialAttr : __x__ + P --* SpecialAttr : \_\_x\_\_ diff --git a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/other.mmd b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/other.mmd index 6cfcae244f..07439b6c55 100644 --- a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/other.mmd +++ b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/other.mmd @@ -1,21 +1,21 @@ classDiagram class P { name : str - __init__(name: str) + \_\_init\_\_(name: str) } class PrivateAttr { - __init__() + \_\_init\_\_() } class ProtectedAttr { - __init__() + \_\_init\_\_() } class PublicAttr { x - __init__() + \_\_init\_\_() } class SpecialAttr { - __x__ - __init__() + \_\_x\_\_ + \_\_init\_\_() } P --* PublicAttr : x - P --* SpecialAttr : __x__ + P --* SpecialAttr : \_\_x\_\_ diff --git a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/special.mmd b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/special.mmd index 149b0a694a..6b7f39b905 100644 --- a/tests/pyreverse/functional/class_diagrams/aggregation_filtering/special.mmd +++ b/tests/pyreverse/functional/class_diagrams/aggregation_filtering/special.mmd @@ -3,7 +3,7 @@ classDiagram name : str } class PrivateAttr { - __x + \_\_x } class ProtectedAttr { _x @@ -13,6 +13,6 @@ classDiagram } class SpecialAttr { } - P --* PrivateAttr : __x + P --* PrivateAttr : \_\_x P --* ProtectedAttr : _x P --* PublicAttr : x From 50ff08f88b21ece959fc9b8a8660e445195cb997 Mon Sep 17 00:00:00 2001 From: Julfried Date: Thu, 22 May 2025 22:18:41 +0200 Subject: [PATCH 3/5] Add news fragement --- doc/whatsnew/fragments/10402.bugfix | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 doc/whatsnew/fragments/10402.bugfix diff --git a/doc/whatsnew/fragments/10402.bugfix b/doc/whatsnew/fragments/10402.bugfix new file mode 100644 index 0000000000..e383df3997 --- /dev/null +++ b/doc/whatsnew/fragments/10402.bugfix @@ -0,0 +1,3 @@ +Fix double underscores rendering as bold in pyreverse Mermaid output. + +Closes #10402 \ No newline at end of file From 90e9d94f89319fde9de47038b84b5bf3c89af0ce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 20:22:10 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/whatsnew/fragments/10402.bugfix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whatsnew/fragments/10402.bugfix b/doc/whatsnew/fragments/10402.bugfix index e383df3997..eb196ba66c 100644 --- a/doc/whatsnew/fragments/10402.bugfix +++ b/doc/whatsnew/fragments/10402.bugfix @@ -1,3 +1,3 @@ Fix double underscores rendering as bold in pyreverse Mermaid output. -Closes #10402 \ No newline at end of file +Closes #10402 From 5c71a811a709e8bf0e2c4c60197737ddccb044bc Mon Sep 17 00:00:00 2001 From: Julian Grimm <51880314+Julfried@users.noreply.github.com> Date: Sun, 25 May 2025 21:59:34 +0200 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Pierre Sassoulas --- doc/whatsnew/fragments/10402.bugfix | 2 +- pylint/pyreverse/mermaidjs_printer.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/whatsnew/fragments/10402.bugfix b/doc/whatsnew/fragments/10402.bugfix index eb196ba66c..a7cea6782e 100644 --- a/doc/whatsnew/fragments/10402.bugfix +++ b/doc/whatsnew/fragments/10402.bugfix @@ -1,3 +1,3 @@ -Fix double underscores rendering as bold in pyreverse Mermaid output. +Fix double underscores erroneously rendering as bold in pyreverse's Mermaid output. Closes #10402 diff --git a/pylint/pyreverse/mermaidjs_printer.py b/pylint/pyreverse/mermaidjs_printer.py index 621c60f993..0f1ebd04f0 100644 --- a/pylint/pyreverse/mermaidjs_printer.py +++ b/pylint/pyreverse/mermaidjs_printer.py @@ -33,10 +33,7 @@ def _open_graph(self) -> None: self._inc_indent() def _escape_mermaid_text(self, text: str) -> str: - """Escape text to prevent Mermaid from interpreting it as Markdown - formatting. - """ - # Escape characters that conflict with Markdown formatting + """Escape characters that conflict with Markdown formatting.""" text = text.replace("__", r"\_\_") # Double underscore → escaped return text