Repository navigation
display_name tag is ignored in visualizations for @config.when nodes #1761
Description
The display_name tag works in visualizations for plain functions, but a node built from a @config.when or @config.when_not function is always labelled <node name>: <config keys> and the tag is dropped. This happens in both decorator stacking orders, with display_all_functions() and with visualize_execution().
Current behavior
With config {"mode": "x"}, a__x tagged display_name="Pretty A" under @config.when(mode="x"), c tagged display_name="Pretty C" under @config.when_not(mode="y"), and a plain d tagged display_name="Pretty D":
list_available_variables()reports all threedisplay_nametags.display_all_functions()andvisualize_execution(["d"], inputs={"b": 1})renderdasPretty D, but render the other two asa: modeandc: mode. "Pretty A" and "Pretty C" do not appear anywhere in the dot source.
Stack Traces
None, the label is just wrong.
Steps to replicate behavior
pip install "apache-hamilton==1.90.0" graphviz- Run this script. It only inspects
Digraph.source, so the graphvizdotbinary is not needed:
import platform
import re
from importlib.metadata import version
from hamilton import ad_hoc_utils, driver
from hamilton.function_modifiers import config, tag
print(f"python: {platform.python_version()}")
print(f"apache-hamilton: {version('apache-hamilton')}")
print(f"graphviz (python package): {version('graphviz')}")
@tag(display_name="Pretty A")
@config.when(mode="x")
def a__x(b: int) -> int:
return b
@config.when_not(mode="y")
@tag(display_name="Pretty C")
def c(a: int) -> int:
return a
@tag(display_name="Pretty D")
def d(c: int) -> int:
return c
mod = ad_hoc_utils.create_temporary_module(a__x, c, d)
dr = driver.Builder().with_modules(mod).with_config({"mode": "x"}).build()
tags = {v.name: v.tags.get("display_name") for v in dr.list_available_variables()}
print("display_name tags:", {k: tags[k] for k in ("a", "c", "d")})
for label, dot in (
("display_all_functions", dr.display_all_functions()),
("visualize_execution", dr.visualize_execution(["d"], inputs={"b": 1})),
):
bold = sorted(set(re.findall(r"<b>([^<]*)</b>", dot.source)))
print(f"{label} bold labels: {bold}")
print("expected: labels 'Pretty A: mode', 'Pretty C: mode' and 'Pretty D'")Output:
python: 3.12.3
apache-hamilton: 1.90.0
graphviz (python package): 0.21
display_name tags: {'a': 'Pretty A', 'c': 'Pretty C', 'd': 'Pretty D'}
display_all_functions bold labels: ['Pretty D', 'a: mode', 'c: mode', 'mode']
visualize_execution bold labels: ['Pretty D', 'a: mode', 'c: mode', 'mode']
expected: labels 'Pretty A: mode', 'Pretty C: mode' and 'Pretty D'
(mode on its own is the config input node.)
Library & System Information
- python 3.12.3
- apache-hamilton 1.90.0
- graphviz python package 0.21 (no
dotbinary installed, not needed for this) - Linux (x86_64)
The code below is the same on main at fa786ea.
Expected behavior
Config-decorated nodes use their display_name tag like any other node, for example Pretty A: mode and Pretty C: mode. The docs for the tag (docs/concepts/visualization.rst from line 169, docs/reference/decorators/tag.rst from line 38) say the node is shown with the tag instead of the function name, with no exception for @config.when.
Additional context
Cause, with lines at main fa786ea: hamilton/node.py line 316 sets tags["hamilton.config"] on every node that comes from a config-decorated function. In create_graphviz_graph, hamilton/graph.py lines 537-540 then rebuild the label for those nodes as _get_node_label(n, name=f"{n.name}: {config_key}"). _get_node_label gives the explicit name argument priority over the display_name tag (line 296, if name is not None: display_name = name), so on this path the tag is never consulted. No existing test combines display_name with a @config.when node.
Proposed fix: in create_graphviz_graph, resolve the base name from the display_name tag first and pass name=f"{resolved}: {config_key}", so the config suffix is kept and the tag is used. Then add a test with a @config.when function that carries display_name and assert on the exact label.
I'm happy to take this one and will open a PR with the fix and the test.
Activity