Repository: tox-dev/pipdeptree
Pull request #200 (2023-03-04 07:55:13)

Quote Mermaid node and edge labels
This PR quotes label strings in the Mermaid produced graph, for both nodes and edges. The way `pipdeptree` currently produce the Mermaid graph is good and working well. This is a safety measure to make sure the output is more resilient.

See the [result in Mermaid's live editor](https://mermaid.live/edit#pako:eNp9kcluwjAURX_FeutgeUhCErWs-IN21boL4yFEzYAyqKWIf-9LCISyqFf2ufe-QT6BaayDDHzZfJm9bnvyulU1wWNK3XVb50lVdF1R56Tr2-bTrazu0NfqY0aii1O_K9BK1ZKGlCn4uNAd0h1SQSXlN2qQGqQR5ezObBHbizm6QYfQIWSUi7sSHrGf2i0sR5Yji2lCZWsWQZPViijYPAs69cPnhuwetIiux1qTZubpl5xkwZOgoZgNdl7karhON4nuQRzTf3N2yaW3geaYX2L8cdj8n9xNk3dLegigcm2lC4v_exqdCvq9q5yCDK_WeT2UvQJVn9Gqh755OdYGsr4dXADDwerebQudt7qCzOuyQ3rQ9VvTVFcTPiE7wTdkgkVUSiHjlLOERUkYB3AcMeXrhKUp53GYcJ6KcwA_UwVGo_MvVqym_A):
 
<img width="1272" alt="Screenshot 2023-03-04 at 11 52 38" src="https://user-images.githubusercontent.com/159718/222884047-687de4bb-c726-481a-94f3-8cd6dfe5684e.png">

For the record, I found out about this more robust syntax while debugging an [edge-case with Mermaid itself, in which `click` cannot be used for node IDs](https://github.com/mermaid-js/mermaid/issues/4182).


Patch:
diff --git a/src/pipdeptree/__init__.py b/src/pipdeptree/__init__.py
index 805035d..250a70d 100644
--- a/src/pipdeptree/__init__.py
+++ b/src/pipdeptree/__init__.py
@@ -562,15 +562,15 @@ def render_mermaid(tree) -> str:
 
     for pkg, deps in tree.items():
         pkg_label = f"{pkg.project_name}\\n{pkg.version}"
-        nodes.add(f"{pkg.key}[{pkg_label}]")
+        nodes.add(f'{pkg.key}["{pkg_label}"]')
         for dep in deps:
             edge_label = dep.version_spec or "any"
             if dep.is_missing:
                 dep_label = f"{dep.project_name}\\n(missing)"
-                nodes.add(f"{dep.key}[{dep_label}]:::missing")
+                nodes.add(f'{dep.key}["{dep_label}"]:::missing')
                 edges.add(f"{pkg.key} -.-> {dep.key}")
             else:
-                edges.add(f"{pkg.key} -- {edge_label} --> {dep.key}")
+                edges.add(f'{pkg.key} -- "{edge_label}" --> {dep.key}')
 
     # Produce the Mermaid Markdown.
     indent = " " * 4


Test patch:
diff --git a/tests/test_pipdeptree.py b/tests/test_pipdeptree.py
index ef95065..2097233 100644
--- a/tests/test_pipdeptree.py
+++ b/tests/test_pipdeptree.py
@@ -325,30 +325,33 @@ def randomized_dag_copy(t):
 
 
 def test_render_mermaid():
-    # Check both the sorted and randomized package tree produces the same sorted
-    # Mermaid output.
+    """Check both the sorted and randomized package tree produces the same sorted Mermaid output.
+
+    `See how this renders
+    <https://mermaid.ink/img/pako:eNp9kcluwjAURX_FeutgeUhCErWs-IN21boL4yFEzYAyqKWIf-9LCISyqFf2ufe-QT6BaayDDHzZfJm9bnvyulU1wWNK3XVb50lVdF1R56Tr2-bTrazu0NfqY0aii1O_K9BK1ZKGlCn4uNAd0h1SQSXlN2qQGqQR5ezObBHbizm6QYfQIWSUi7sSHrGf2i0sR5Yji2lCZWsWQZPViijYPAs69cPnhuwetIiux1qTZubpl5xkwZOgoZgNdl7karhON4nuQRzTf3N2yaW3geaYX2L8cdj8n9xNk3dLegigcm2lC4v_exqdCvq9q5yCDK_WeT2UvQJVn9Gqh755OdYGsr4dXADDwerebQudt7qCzOuyQ3rQ9VvTVFcTPiE7wTdkgkVUSiHjlLOERUkYB3AcMeXrhKUp53GYcJ6KcwA_UwVGo_MvVqym_A?type=png)](https://mermaid.live/edit#pako:eNp9kcluwjAURX_FeutgeUhCErWs-IN21boL4yFEzYAyqKWIf-9LCISyqFf2ufe-QT6BaayDDHzZfJm9bnvyulU1wWNK3XVb50lVdF1R56Tr2-bTrazu0NfqY0aii1O_K9BK1ZKGlCn4uNAd0h1SQSXlN2qQGqQR5ezObBHbizm6QYfQIWSUi7sSHrGf2i0sR5Yji2lCZWsWQZPViijYPAs69cPnhuwetIiux1qTZubpl5xkwZOgoZgNdl7karhON4nuQRzTf3N2yaW3geaYX2L8cdj8n9xNk3dLegigcm2lC4v_exqdCvq9q5yCDK_WeT2UvQJVn9Gqh755OdYGsr4dXADDwerebQudt7qCzOuyQ3rQ9VvTVFcTPiE7wTdkgkVUSiHjlLOERUkYB3AcMeXrhKUp53GYcJ6KcwA_UwVGo_MvVqym_A>`_.
+    """
     for package_tree in (t, randomized_dag_copy(t)):
         output = p.render_mermaid(package_tree)
         assert output == dedent(
             """\
             flowchart TD
                 classDef missing stroke-dasharray: 5
-                a[a\\n3.4.0]
-                b[b\\n2.3.1]
-                c[c\\n5.10.0]
-                d[d\\n2.35]
-                e[e\\n0.12.1]
-                f[f\\n3.1]
-                g[g\\n6.8.3rc1]
-                a -- >=2.0.0 --> b
-                a -- >=5.7.1 --> c
-                b -- >=2.30,<2.42 --> d
-                c -- >=0.12.1 --> e
-                c -- >=2.30 --> d
-                d -- >=0.9.0 --> e
-                f -- >=2.1.0 --> b
-                g -- >=0.9.0 --> e
-                g -- >=3.0.0 --> f
+                a["a\\n3.4.0"]
+                b["b\\n2.3.1"]
+                c["c\\n5.10.0"]
+                d["d\\n2.35"]
+                e["e\\n0.12.1"]
+                f["f\\n3.1"]
+                g["g\\n6.8.3rc1"]
+                a -- ">=2.0.0" --> b
+                a -- ">=5.7.1" --> c
+                b -- ">=2.30,<2.42" --> d
+                c -- ">=0.12.1" --> e
+                c -- ">=2.30" --> d
+                d -- ">=0.9.0" --> e
+                f -- ">=2.1.0" --> b
+                g -- ">=0.9.0" --> e
+                g -- ">=3.0.0" --> f
             """
         )