Skip to content

docs: add note about unmatched braces in format strings#1031

Open
devimano2011 wants to merge 3 commits intotaverntesting:masterfrom
devimano2011:docs/733-document-format-string-escaping
Open

docs: add note about unmatched braces in format strings#1031
devimano2011 wants to merge 3 commits intotaverntesting:masterfrom
devimano2011:docs/733-document-format-string-escaping

Conversation

@devimano2011
Copy link
Copy Markdown
Contributor

@devimano2011 devimano2011 commented Apr 29, 2026

Related to #733

The existing docs explain how to escape literal { and } using {{ and }}. However they don't mention what happens when a string contains an unmatched brace (e.g. {Explanation 1 from an MQTT payload), which previously caused an unhandled ValueError.

Adds a short **NOTE** paragraph after the existing escaping example to explain that strings with unmatched braces will log a warning and be passed through unformatted rather than raising an error, and directs users to escape literal braces to avoid unexpected behaviour.

Summary by CodeRabbit

  • Documentation
    • Updated documentation now clarifies string formatting behaviour when encountering unmatched curly braces. The guidance specifies that Tavern will emit a warning and pass strings through without formatting, rather than failing. Comprehensive guidance provided on escaping literal curly braces to prevent unexpected formatting results.

Added a note about unmatched curly braces in string values.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

Documentation update to basics.md that adds clarification about Tavern's string formatting behaviour when encountering unmatched curly braces. The change specifies that Tavern emits a warning and passes the string through without formatting, rather than failing.

Changes

Cohort / File(s) Summary
Documentation updates
docs/source/basics.md
Added warning details about unmatched { handling in string formatting—specifies that Tavern emits a warning and passes the string through without formatting, and reiterates the requirement to escape literal curly braces.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding documentation about unmatched braces in format strings, which is the primary objective of updating the basics.md file.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/source/basics.md (2)

207-208: Minor: remove trailing whitespace in the GraphQL toy-example NOTE.

Line 207 ends with a trailing space after “then”. Not a functional issue, but it’s worth cleaning up to avoid whitespace-lint noise.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/basics.md` around lines 207 - 208, Remove the trailing space at
the end of the GraphQL toy-example NOTE line (the line starting "**NOTE**: This
is a toy example, if you want to use GraphQL with tavern then ") so it no longer
ends with extra whitespace; update the markdown line that includes the link
"[GraphQL docs](./graphql.md)" to remove the stray space after “then” to satisfy
whitespace linting.

210-215: Clarity tweak (optional): consider adding a concrete example.

To make the NOTE more immediately actionable, you could include a tiny inline example (e.g., "{Explanation 1" in an MQTT payload) alongside the “escape with {{ / }}” guidance. This reduces ambiguity about what Tavern considers “unmatched” in practice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/basics.md` around lines 210 - 215, Add a concrete inline example
to the NOTE paragraph that demonstrates an unmatched brace and the correct
escaping: insert the sample literal string "{Explanation 1" as an MQTT payload
example next to the sentence about unmatched `{`, and show the intended escape
pattern using the existing guidance (`{{` / `}}`) so readers immediately see
both the problematic input and the escaped form; update the NOTE text (the
paragraph starting "**NOTE**: If a string value contains an unmatched `{`...")
to include this inline example for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/source/basics.md`:
- Around line 210-214: The docs claim unmatched "{" are logged and passed
through unformatted, but _check_and_format_values in tavern/_core/dict_util.py
currently calls to_format.format(**box_vars) without catching ValueError; update
_check_and_format_values to catch ValueError around the .format call (in
addition to existing KeyError/IndexError handling), log a warning mentioning the
offending string and the exception, and return the original unformatted
to_format value so the string is passed through unchanged (preserve current
behavior for successful formatting and keep existing handling for other
exceptions).

---

Nitpick comments:
In `@docs/source/basics.md`:
- Around line 207-208: Remove the trailing space at the end of the GraphQL
toy-example NOTE line (the line starting "**NOTE**: This is a toy example, if
you want to use GraphQL with tavern then ") so it no longer ends with extra
whitespace; update the markdown line that includes the link "[GraphQL
docs](./graphql.md)" to remove the stray space after “then” to satisfy
whitespace linting.
- Around line 210-215: Add a concrete inline example to the NOTE paragraph that
demonstrates an unmatched brace and the correct escaping: insert the sample
literal string "{Explanation 1" as an MQTT payload example next to the sentence
about unmatched `{`, and show the intended escape pattern using the existing
guidance (`{{` / `}}`) so readers immediately see both the problematic input and
the escaped form; update the NOTE text (the paragraph starting "**NOTE**: If a
string value contains an unmatched `{`...") to include this inline example for
clarity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5e3036f9-5607-40b5-9e1b-7885bba9bcf8

📥 Commits

Reviewing files that changed from the base of the PR and between 55e5925 and c969983.

📒 Files selected for processing (1)
  • docs/source/basics.md

Comment thread docs/source/basics.md Outdated
Comment on lines +210 to +214
**NOTE**: If a string value contains an unmatched `{` that is not a valid
format placeholder (for example, an MQTT payload value like `{Explanation 1`),
Tavern will log a warning and pass the string through unformatted rather than
raising an error. To avoid unexpected behaviour, always escape literal curly
braces as described above.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect whether ValueError (unmatched braces) is handled near the actual formatting call.
rg -n --hidden --no-messages "to_format\.format\(\*\*box_vars\)" tavern/_core/dict_util.py
rg -n --hidden --no-messages "except\s+ValueError" tavern/_core/dict_util.py
rg -n --hidden --no-messages "unmatched\s*\{" -S tavern/_core/dict_util.py tavern/_core || true

# 2) Runtime probe (best-effort): confirm whether unmatched braces warn+passthrough or raise.
python - <<'PY'
import warnings

try:
    # Attempt to import the internal helper shown in the context snippet.
    from tavern._core.dict_util import _check_and_format_values
    # Box-like object: if the function expects a dict, pass a dict.
    box_vars = {}
    s = "{Explanation 1"
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        out = _check_and_format_values(s, box_vars)
    print("PASS: returned without raising. output:", out)
    if w:
        print("Warnings:", [str(x.message) for x in w])
    else:
        print("Warnings: none captured")
except Exception as e:
    print("RAISED:", type(e).__name__, str(e))
    raise
PY

Repository: taverntesting/tavern

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get the full context around line 73 in dict_util.py
echo "=== Full function containing to_format.format ===  "
rg -B 30 -A 5 "to_format\.format\(\*\*box_vars\)" tavern/_core/dict_util.py

echo ""
echo "=== Search for _check_and_format_values function definition ===" 
rg -B 2 -A 20 "def _check_and_format_values" tavern/_core/dict_util.py

echo ""
echo "=== Check for any ValueError handling in dict_util.py ===" 
rg "ValueError|except|try:" tavern/_core/dict_util.py -n

Repository: taverntesting/tavern

Length of output: 4051


🏁 Script executed:

#!/bin/bash

# More precise runtime test with detailed error capture
python3 <<'PY'
import sys
import traceback

print("=== Testing unmatched brace behaviour ===")
try:
    from tavern._core.dict_util import _check_and_format_values
    
    box_vars = {}
    test_string = "{Explanation 1"
    
    result = _check_and_format_values(test_string, box_vars)
    print(f"SUCCESS: Function returned: {repr(result)}")
    
except Exception as e:
    print(f"EXCEPTION RAISED: {type(e).__name__}")
    print(f"Message: {e}")
    print("\nFull traceback:")
    traceback.print_exc()
    sys.exit(0)  # Exit cleanly to see output
PY

Repository: taverntesting/tavern

Length of output: 417


🏁 Script executed:

#!/bin/bash

# Check if there are any other places where unmatched brace handling might occur
echo "=== Search for 'unmatched' references in codebase ===" 
rg "unmatched" tavern/ || echo "No matches for 'unmatched'"

echo ""
echo "=== Search for handling of ValueError from format() ===" 
rg "except.*ValueError" tavern/ -A 2 -B 2 || echo "No ValueError handlers found"

echo ""
echo "=== Check git history for recent changes to basics.md ===" 
git log --oneline -n 20 -- docs/source/basics.md 2>/dev/null || echo "Git not available"

echo ""
echo "=== Verify the exact location in basics.md ===" 
sed -n '205,220p' docs/source/basics.md

Repository: taverntesting/tavern

Length of output: 4678


Documentation claims unmatched brace handling that is not implemented in the code.

The NOTE states that unmatched { characters "will log a warning and pass the string through unformatted rather than raising an error". However, code inspection of _check_and_format_values() in tavern/_core/dict_util.py reveals that:

  1. The function validates placeholders using formatter.get_field() (catching KeyError and IndexError only)
  2. It directly executes to_format.format(**box_vars) without catching ValueError
  3. There are no references to "unmatched" or handling of unmatched braces anywhere in the codebase

When Python's str.format() encounters an unmatched {, it raises ValueError, which will propagate uncaught and crash with an exception—contradicting the documented behaviour. Either update the documentation to reflect the actual behaviour, or implement the described feature in the code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/basics.md` around lines 210 - 214, The docs claim unmatched "{"
are logged and passed through unformatted, but _check_and_format_values in
tavern/_core/dict_util.py currently calls to_format.format(**box_vars) without
catching ValueError; update _check_and_format_values to catch ValueError around
the .format call (in addition to existing KeyError/IndexError handling), log a
warning mentioning the offending string and the exception, and return the
original unformatted to_format value so the string is passed through unchanged
(preserve current behavior for successful formatting and keep existing handling
for other exceptions).

Comment thread docs/source/basics.md Outdated
Comment on lines +210 to +214
**NOTE**: If a string value contains an unmatched `{` that is not a valid
format placeholder (for example, an MQTT payload value like `{Explanation 1`),
Tavern will log a warning and pass the string through unformatted rather than
raising an error. To avoid unexpected behaviour, always escape literal curly
braces as described above.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true.

…d_format_values for unmatched bracesmatting

Add error handling for string formatting in dict_util.py
…oncrete example

Clarified note on escaping curly braces in string values and improved explanation of behavior with unmatched placeholders.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants