Skip to content

display_name tag is ignored in visualizations for @config.when nodes #1761

Open

Description

@digit50

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 three display_name tags.
  • display_all_functions() and visualize_execution(["d"], inputs={"b": 1}) render d as Pretty D, but render the other two as a: mode and c: 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

  1. pip install "apache-hamilton==1.90.0" graphviz
  2. Run this script. It only inspects Digraph.source, so the graphviz dot binary 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 dot binary 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions