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
6 changes: 5 additions & 1 deletion garak/harnesses/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,15 @@ def run(self, model, probes, detectors, evaluator, announce_probe=True) -> None:
attempt_results, (list, types.GeneratorType)
), "probing should always return an ordered iterable"

probe_display_name = probe.probename.replace("garak.", "")
for d in detectors:
logging.debug("harness: run detector %s", d.detectorname)
attempt_iterator = tqdm.tqdm(attempt_results, leave=False)
detector_probe_name = d.detectorname.replace("garak.detectors.", "")
attempt_iterator.set_description("detectors." + detector_probe_name)
# issue #324: include probe name in the detector progress bar
attempt_iterator.set_description(
f"{probe_display_name}/detectors.{detector_probe_name}"
)
for attempt in attempt_iterator:
if d.skip:
continue
Expand Down
62 changes: 60 additions & 2 deletions tests/harnesses/test_harnesses.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import pytest
import importlib
import tempfile

import pytest

from garak import _plugins
from garak import _plugins, _config

import garak.buffs.base
import garak.harnesses.base

HARNESSES = [
classname for (classname, active) in _plugins.enumerate_plugins("harnesses")
]


@pytest.fixture(autouse=True)
def _config_loaded():
"""Load base config + a temp report file so harness.run() can write."""
_config.load_base_config()
_config.plugins.probes["test"]["generations"] = 1
temp_report_file = tempfile.NamedTemporaryFile(
mode="w+", suffix=".report.jsonl", delete=False
)
_config.transient.report_filename = temp_report_file.name
_config.transient.reportfile = open(
_config.transient.report_filename, "w", buffering=1, encoding="utf-8"
)

yield


@pytest.mark.parametrize("classname", HARNESSES)
def test_harness_structure(classname):

Expand Down Expand Up @@ -47,3 +66,42 @@ def test_harness_modality_match():
assert garak.harnesses.base._modality_match(t, tvi, False) is True
assert garak.harnesses.base._modality_match(ti, tvi, False) is True
assert garak.harnesses.base._modality_match(t, ti, False) is True


def test_harness_detector_progress_shows_probe_name(mocker, monkeypatch):
"""Detector progress bar must show which probe is being processed (#324)."""
mocker.patch("garak.harnesses.base._initialize_runtime_services")

captured_descriptions = []
real_tqdm = garak.harnesses.base.tqdm.tqdm

def capturing_tqdm(*args, **kwargs):
bar = real_tqdm(*args, **kwargs)
original_set_description = bar.set_description

def set_description(desc, *a, **kw):
captured_descriptions.append(desc)
return original_set_description(desc, *a, **kw)

bar.set_description = set_description
return bar

monkeypatch.setattr(garak.harnesses.base.tqdm, "tqdm", capturing_tqdm)

harness = garak.harnesses.base.Harness()
model = _plugins.load_plugin("generators.test.Blank")
probe = _plugins.load_plugin("probes.test.Blank")
detector = _plugins.load_plugin("detectors.always.Pass")
monkeypatch.setattr(
_config.buffmanager,
"buffs",
[garak.buffs.base.Buff()],
)

harness.run(model, [probe], [detector], mocker.Mock())

assert captured_descriptions, "detector progress bar should have a description"
assert any(
"probes.test.Blank" in desc and "detectors.always.Pass" in desc
for desc in captured_descriptions
), "detector progress description should include probe and detector names"
Loading