Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions garak/attempt.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class Attempt:
:param conversations: conversation turn histories
:type conversations: List(Conversation)
:param reverse_translation_outputs: The reverse translation of output based on the original language of the probe
:type reverse_translation_outputs: List(str)
:type reverse_translation_outputs: List[Optional[Message]]
:param intent: None, or the primary intent type in this attempt
:type notes: str|None

Expand Down Expand Up @@ -261,7 +261,7 @@ def __init__(
self.goal = goal
self.seq = seq
self.reverse_translation_outputs = (
{} if reverse_translation_outputs is None else reverse_translation_outputs
[] if reverse_translation_outputs is None else reverse_translation_outputs
)
self.intent = intent

Expand Down
45 changes: 45 additions & 0 deletions tests/test_attempt.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,51 @@ def test_outputs_for():
assert all_output_a.outputs_for("en") == reverse_outputs


def test_reverse_translation_outputs_defaults_to_list():
"""The default for reverse_translation_outputs must be a list, not a dict.

Regression for the type drift between the docstring (``List[str]``) and the
former ``{}`` default: list operations (``append``, indexing, ``len``) fail
on a dict, and ``outputs_for`` silently returned no outputs for translated
runs when the field was never populated.
"""
attempt = garak.attempt.Attempt()
assert attempt.reverse_translation_outputs == []
assert isinstance(attempt.reverse_translation_outputs, list)


def test_outputs_for_unset_reverse_translation_returns_empty_list():
attempt = garak.attempt.Attempt()
attempt.prompt = garak.attempt.Message("hello", lang="en")
attempt.outputs = [garak.attempt.Message("bonjour", lang="fr")]

assert attempt.outputs_for("en") == [garak.attempt.Message("bonjour", lang="fr")]
assert attempt.outputs_for("de") == []
assert isinstance(attempt.outputs_for("de"), list)


def test_reverse_translation_outputs_as_dict_round_trip():
attempt = garak.attempt.Attempt()
attempt.prompt = garak.attempt.Message("hello", lang="en")
attempt.outputs = [garak.attempt.Message("bonjour", lang="fr")]
attempt.reverse_translation_outputs = [
garak.attempt.Message("this is a test", lang="en"),
None,
]

data = attempt.as_dict()
entries = data["reverse_translation_outputs"]
assert len(entries) == 2
assert entries[0]["text"] == "this is a test"
assert entries[0]["lang"] == "en"
assert entries[1] is None

# Reconstructing the serialized Message must preserve its fields.
restored = garak.attempt.Message(**entries[0])
assert restored.text == "this is a test"
assert restored.lang == "en"


def test_attempt_prompt_no_str():
with pytest.raises(TypeError):
attempt = garak.attempt.Attempt(prompt="nine two one eight black")
Expand Down