Skip to content

Commit a537c3d

Browse files
fix: update FunctionDetector and RegexDetector to handle missing detection functions and patterns, returning None or 0.0 as appropriate
1 parent d753c62 commit a537c3d

File tree

3 files changed

+25
-24
lines changed

3 files changed

+25
-24
lines changed

garak/detectors/function.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,17 @@ def detect(self, attempt: garak.attempt.Attempt) -> List[float]:
140140
Returns:
141141
List of scores (0.0-1.0) for each output, or [None] * len if detector failed to initialize
142142
"""
143-
# If detection_function failed to load, return None for all outputs
144-
if self.detection_function is None:
145-
logging.error(
146-
"function.FunctionDetector: Failed to load function %s",
147-
self.function_name
148-
)
149-
return [None] * len(attempt.outputs)
150-
151-
results = []
152-
for output in attempt.outputs:
143+
results = [None] * len(attempt.outputs)
144+
for idx, output in enumerate(attempt.outputs):
153145
output_text = output.text if output else None
146+
154147
if output_text is None:
155-
results.append(None)
148+
continue
149+
150+
if self.detection_function is None:
151+
logging.warning(
152+
"function.FunctionDetector: No detection function found (or failed to load), setting None",
153+
)
156154
continue
157155

158156
try:
@@ -162,7 +160,7 @@ def detect(self, attempt: garak.attempt.Attempt) -> List[float]:
162160
# Validate return type
163161
if not isinstance(score, (int, float)):
164162
logging.error(
165-
"function.FunctionDetector: %s returned non-numeric value: %s (type: %s)",
163+
"function.FunctionDetector: %s returned non-numeric value: %s (type: %s). Setting 0.0",
166164
self.function_name, score, type(score)
167165
)
168166
score = 0.0
@@ -174,13 +172,13 @@ def detect(self, attempt: garak.attempt.Attempt) -> List[float]:
174172
"function.FunctionDetector: %s returned score outside 0-1 range: %s (clamped to %s)",
175173
self.function_name, score, score_clamped
176174
)
177-
results.append(score_clamped)
175+
results[idx] = score_clamped
178176

179177
except Exception as e:
180178
logging.error(
181179
"function.FunctionDetector: Error calling %s: %s",
182180
self.function_name, e, exc_info=e
183181
)
184-
results.append(None) # Default to None on error
182+
results[idx] = None # Default to None on error
185183

186184
return results

garak/detectors/regex.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,20 @@ def detect(self, attempt: garak.attempt.Attempt) -> List[float]:
145145
List of scores (0.0 or 1.0) for each output
146146
"""
147147
results = [None] * len(attempt.outputs)
148-
if not self.compiled_patterns:
149-
logging.error(
150-
"regex.RegexDetector: No compiled patterns found, returning None for all outputs"
151-
)
152-
return results
153148

154149
for idx, output in enumerate(attempt.outputs):
155150
output_text = output.text if output else None
156151
if output_text is None:
157152
continue
158153

154+
# If no patterns configured, return 0.0 (no match) for valid outputs
155+
if not self.compiled_patterns:
156+
logging.warning(
157+
"regex.RegexDetector: No compiled patterns found, setting 0.0 (no match or safe)"
158+
)
159+
results[idx] = 0.0
160+
continue
161+
159162
# Check patterns based on match_type
160163
matched = False
161164
if self.match_type == "any":

tests/detectors/test_detectors_regex.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def test_none_output_handling(self):
159159
assert results[2] == 0.0
160160

161161
def test_empty_patterns_returns_safe(self):
162-
"""Test that RegexDetector with no patterns returns None"""
162+
"""Test that RegexDetector with no patterns returns 0.0 (safe)"""
163163
config = {
164164
'detectors': {
165165
'regex': {
@@ -176,7 +176,7 @@ def test_empty_patterns_returns_safe(self):
176176
attempt.outputs = [garak.attempt.Message("any text here")]
177177

178178
results = detector.detect(attempt)
179-
assert results[0] is None # None with no patterns
179+
assert results[0] == 0.0 # Safe with no patterns
180180

181181
def test_multiline_flag(self):
182182
"""Test MULTILINE flag for matching at line boundaries"""
@@ -442,7 +442,7 @@ def test_single_string_re_flags_normalized(self):
442442
assert 'MULTILINE' in detector.re_flags
443443

444444
def test_all_invalid_patterns_returns_safe(self):
445-
"""Test that if all patterns are invalid, detector returns None"""
445+
"""Test that if all patterns are invalid, detector returns 0.0 (safe)"""
446446
config = {
447447
'detectors': {
448448
'regex': {
@@ -459,9 +459,9 @@ def test_all_invalid_patterns_returns_safe(self):
459459
# No valid patterns compiled
460460
assert len(detector.compiled_patterns) == 0
461461

462-
# Should return None
462+
# Should return safe (0.0)
463463
attempt = garak.attempt.Attempt(prompt=garak.attempt.Message())
464464
attempt.outputs = [garak.attempt.Message("any text")]
465465

466466
results = detector.detect(attempt)
467-
assert results[0] is None # None when no valid patterns
467+
assert results[0] == 0.0 # Safe when no valid patterns

0 commit comments

Comments
 (0)