Improve render()

Done

/home/devdi/devswarm/evals/tasks/hard_template_engine/repo · 2026-11-09 17:19:28 UTC · took 44.3s

  1. Plan (done)
  2. Code (done)
  3. Test (done)
  4. Review (done)
  5. Finish (done)
Cost
$0.0056
Tests
Passed
Iterations
1
Re-plans
0
LLM calls
11
Prompt read from cache
77%

Usage by agent

Cost per agent
planner: $0.0013 planner planner, Cost: $0.0013 $0.0013 coder: $0.0023 coder coder, Cost: $0.0023 $0.0023 tester: $0.0020 tester tester, Cost: $0.0020 $0.0020
Tokens per agent
  • Cache read
  • Cache write
  • Input
  • Output
planner: 9,407 planner planner, Cache read: 6,099 planner, Cache write: 982 planner, Output: 2,318 9,407 coder: 30.4K coder coder, Cache read: 22.0K coder, Cache write: 5,714 coder, Output: 2,673 30.4K tester: 22.6K tester tester, Cache read: 14.4K tester, Cache write: 5,895 tester, Output: 2,282 22.6K
View as table
AgentCostCache readCache writeInputOutput
planner$0.00136,09998282,318
coder$0.002322,0145,714122,673
tester$0.002014,3845,89582,282

Timeline

  1. planner iteration 1 Finished 3 calls · 9,407 tokens · $0.0013 · 12.4s

    Loading…

  2. coder iteration 1 Finished 5 calls · 30.4K tokens · $0.0023 · 17.8s

    Loading…

  3. tester iteration 1 Finished 3 calls · 22.6K tokens · $0.0020 · 12.9s

    Loading…

  4. verify iteration 1 Passed 0.5s
    .....................                                                    [100%]
    21 passed in 0.04s
    

Final diff

diff --git a/template.py b/template.py
index 8cfdd25..b567e26 100644
--- a/template.py
+++ b/template.py
@@ -1,5 +1,31 @@
 import re
 
+_PATTERN = re.compile(r"(\\)?\{\{\s*(\w+(?:\.\w+)*)\s*\}\}")
+
+
+class MissingVariable(KeyError):
+    def __str__(self) -> str:
+        return str(self.args[0])
+
+
+def _lookup(name: str, context: dict):
+    parts = name.split(".")
+    if parts[0] not in context:
+        raise MissingVariable(f"missing variable: {name}")
+    value = context[parts[0]]
+    for part in parts[1:]:
+        if not isinstance(value, dict) or part not in value:
+            raise MissingVariable(f"missing variable: {name}")
+        value = value[part]
+    return value
+
 
 def render(template: str, context: dict) -> str:
-    return re.sub(r"\{\{(\w+)\}\}", lambda match: str(context[match[1]]), template)
+    def replace(match: re.Match) -> str:
+        if match[1]:
+            # Escaped opening: drop the backslash and leave the rest literal.
+            return match[0][1:]
+        value = _lookup(match[2], context)
+        return "" if value is None else str(value)
+
+    return _PATTERN.sub(replace, template)
diff --git a/test_template.py b/test_template.py
index 9cfb1dc..c4393fb 100644
--- a/test_template.py
+++ b/test_template.py
@@ -1,5 +1,102 @@
-from template import render
+import pytest
+
+from template import MissingVariable, render
 
 
 def test_simple():
     assert render("Hi {{name}}!", {"name": "Ada"}) == "Hi Ada!"
+
+
+def test_spaces_inside_braces():
+    assert render("Hi {{ name }}!", {"name": "Ada"}) == "Hi Ada!"
+
+
+def test_dotted_lookup():
+    assert render("{{ user.name }}", {"user": {"name": "Ada"}}) == "Ada"
+
+
+def test_escaped_opening():
+    assert render("\\{{ name }}", {"name": "Ada"}) == "{{ name }}"
+
+
+def test_missing_top_level_name():
+    with pytest.raises(MissingVariable) as exc:
+        render("{{ x }}", {})
+    assert "x" in str(exc.value)
+    assert isinstance(exc.value, KeyError)
+
+
+def test_missing_nested_key():
+    with pytest.raises(MissingVariable) as exc:
+        render("{{user.age}}", {"user": {"name": "Ada"}})
+    assert "user.age" in str(exc.value)
+    assert isinstance(exc.value, KeyError)
+
+
+@pytest.mark.parametrize("user", ["Ada", 42])
+def test_dotted_path_through_non_dict(user):
+    with pytest.raises(MissingVariable) as exc:
+        render("{{ user.name }}", {"user": user})
+    assert "user.name" in str(exc.value)
+
+
+def test_none_renders_as_empty():
+    assert render("[{{ x }}]", {"x": None}) == "[]"
+
+
+def test_substituted_value_not_expanded():
+    assert render("{{ a }}", {"a": "{{ b }}", "b": "X"}) == "{{ b }}"
+
+
+def test_missing_message_is_plain_not_repr_quoted():
+    with pytest.raises(MissingVariable) as exc:
+        render("{{ user.age }}", {"user": {}})
+    assert not str(exc.value).startswith(("'", '"'))
+    assert "user.age" in str(exc.value)
+
+
+def test_missing_top_level_message_contains_dotted_name():
+    with pytest.raises(MissingVariable) as exc:
+        render("{{ nope.deep }}", {})
+    assert "nope.deep" in str(exc.value)
+
+
+def test_missing_variable_is_key_error_subclass():
+    assert issubclass(MissingVariable, KeyError)
+
+
+def test_intermediate_none_raises_missing():
+    with pytest.raises(MissingVariable) as exc:
+        render("{{ user.name }}", {"user": None})
+    assert "user.name" in str(exc.value)
+
+
+def test_final_none_in_nested_dict_renders_empty():
+    assert render("[{{ user.name }}]", {"user": {"name": None}}) == "[]"
+
+
+def test_dict_and_list_values_are_str_ed():
+    assert render("{{ d }}", {"d": {"k": 1}}) == str({"k": 1})
+    assert render("{{ l }}", {"l": [1, 2]}) == str([1, 2])
+
+
+def test_lone_backslash_left_alone():
+    assert render("C:\\path {{ a }}", {"a": "x"}) == "C:\\path x"
+    assert render("a\\b", {}) == "a\\b"
+
+
+def test_escaped_dotted_name_untouched():
+    assert render("\\{{ user.age }}", {}) == "{{ user.age }}"
+
+
+def test_escape_only_affects_its_own_placeholder():
+    assert render("\\{{ a }} and {{ a }}", {"a": "X"}) == "{{ a }} and X"
+
+
+def test_empty_segment_passes_through_unchanged():
+    assert render("{{ a..b }}", {"a": {"b": 1}}) == "{{ a..b }}"
+    assert render("{{ a. }}", {"a": 1}) == "{{ a. }}"
+
+
+def test_value_containing_escape_sequence_not_reprocessed():
+    assert render("{{ a }}", {"a": "\\{{ b }}", "b": "X"}) == "\\{{ b }}"