Files
César ValadezandClaude Sonnet 4.6 fcd53df552 feat: remove dynamicprompts dependency, add native WildcardManager
Replace dynamicprompts.WildcardManager with a native implementation in
src/wildcards.py that loads .txt, .yaml, and .json wildcard files from
one or more directories using fnmatch pattern matching. EvaluationContext
now types wildcard_manager as a WildcardProvider Protocol rather than the
concrete class.

Remove dynamicprompts from dependencies; add pyyaml>=6.0 and types-pyyaml
as its replacement. Add explicit_package_bases = true to mypy config to
resolve duplicate module path ambiguity from the root __init__.py.

Update README and CLAUDE to reflect the native parser architecture and
removal of the Jinja2 node. Remove completed plan documents. Ignore
user-specific yaml wildcard files via .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:33:29 -06:00

61 lines
1.8 KiB
Python

import pytest
from pathlib import Path
import random
from src.evaluator.context import EvaluationContext
from src.evaluator.combinatorial_eval import evaluate_all
from src.parser.parser import parse
from src.wildcards import WildcardManager
@pytest.fixture
def ctx(wildcards_path: Path) -> EvaluationContext:
return EvaluationContext(
rng=random.Random(0),
wildcard_manager=WildcardManager(paths=[wildcards_path]),
)
def test_plain_text(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("hello"), ctx)
assert results == ["hello"]
def test_single_variant(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("{a|b|c}"), ctx)
assert sorted(results) == ["a", "b", "c"]
def test_cross_product(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("{a|b} {c|d}"), ctx)
assert sorted(results) == ["a c", "a d", "b c", "b d"]
def test_cross_product_count(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("{a|b} {c|d}"))
assert len(results) == 4
def test_nested_variant(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("{a|{b|c}}"), ctx)
assert sorted(results) == ["a", "b", "c"]
def test_wildcard_combinatorial(ctx: EvaluationContext) -> None:
results = evaluate_all(parse("__animals__"), ctx)
assert sorted(results) == ["bird", "cat", "dog"]
def test_variable_evaluated_once_per_branch(ctx: EvaluationContext) -> None:
# ${x=!{a|b}} creates branches; each branch fixes x for that branch
results = evaluate_all(parse("${x=!{a|b}} ${x} ${x}"), ctx)
# Each result should have the same word repeated
for r in results:
words = [w for w in r.split() if w]
assert words[0] == words[1]
def test_empty_template(ctx: EvaluationContext) -> None:
results = evaluate_all(parse(""), ctx)
assert results == [""]