diff --git a/hamilton/graph.py b/hamilton/graph.py index a6246e5d3..93ee23efb 100644 --- a/hamilton/graph.py +++ b/hamilton/graph.py @@ -6,6 +6,7 @@ Note: one should largely consider the code in this module to be "private". """ +import html import inspect import logging import os.path @@ -235,6 +236,7 @@ def create_graphviz_graph( :return: a graphviz.Digraph; use this to render/save a graph representation. """ PATH_COLOR = "red" + MAX_STRING_LENGTH = 80 import graphviz @@ -270,7 +272,16 @@ def _get_node_label( if type_string is None: type_string = get_type_as_string(n.type) if get_type_as_string(n.type) else "" - return f"<{name}

{type_string}>" + # We need to ensure that name and type string are HTML-escaped + # strings to avoid syntax errors. This is particular important + # because config *values* are passed through this function + # see issue: https://github.com/DAGWorks-Inc/hamilton/issues/1200 + # see graphviz ref: https://graphviz.org/doc/info/shapes.html#html + if len(type_string) > MAX_STRING_LENGTH: + type_string = type_string[:MAX_STRING_LENGTH] + "[...]" + + escaped_type_string = html.escape(type_string, quote=True) + return f"<{name}

{escaped_type_string}>" def _get_input_label(input_nodes: FrozenSet[node.Node]) -> str: """Get a graphviz HTML-like node label formatted aspyer a table. @@ -372,7 +383,6 @@ def _get_edge_style(from_type: str, to_type: str) -> Dict: Graphviz needs values to be strings. """ edge_style = dict() - if from_type == "expand": edge_style.update( dir="both",