Skip to content
Merged
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release Notes

## Unreleased

### Added
- Stricter validation of input hypotheses and references

## 2.6.0 (2026-01-12)
- Dropped Python 3.8, added Python 3.13 (requires-python = ">=3.9")
- License Format: Changed to PEP 639 bare SPDX format (license = "Apache-2.0")
Expand Down
44 changes: 33 additions & 11 deletions sacrebleu/metrics/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,11 @@ def _check_sentence_score_args(self, hyp: str, refs: Sequence[str]):

if not isinstance(hyp, str):
err_msg = "The argument `hyp` should be a string."
elif isinstance(refs, str) or not isinstance(refs, Sequence):
elif isinstance(refs, (str, bytes)) or not isinstance(refs, Sequence):
err_msg = "The argument `refs` should be a sequence of strings."
elif not isinstance(refs[0], str) and refs[0] is not None:
elif len(refs) == 0:
err_msg = "The argument `refs` should not be empty."
elif any(not isinstance(ref, str) and ref is not None for ref in refs):
err_msg = "Each element of `refs` should be a string."

if err_msg:
Expand All @@ -239,7 +241,7 @@ def _check_corpus_score_args(
):
"""Performs sanity checks on `corpus_score` method's arguments.

:param hypses: A sequence of hypothesis strings.
:param hyps: A sequence of hypothesis strings.
:param refs: A sequence of reference documents with document being
defined as a sequence of reference strings. If `None`, cached references
will be used.
Expand All @@ -248,20 +250,40 @@ def _check_corpus_score_args(
prefix = self.__class__.__name__
err_msg = None

if not isinstance(hyps, Sequence):
if isinstance(hyps, (str, bytes)) or not isinstance(hyps, Sequence):
err_msg = "`hyps` should be a sequence of strings."
elif not isinstance(hyps[0], str):
err_msg = "Each element of `hyps` should be a string."
elif len(hyps) == 0:
err_msg = "`hyps` should not be empty."
elif any(line is None for line in hyps):
err_msg = "Undefined line in hypotheses stream!"
elif any(not isinstance(hyp, str) for hyp in hyps):
err_msg = "Each element of `hyps` should be a string."

if refs is not None:
if refs is not None and err_msg is None:
if not isinstance(refs, Sequence):
err_msg = "`refs` should be a sequence of sequence of strings."
elif not isinstance(refs[0], Sequence):
err_msg = "Each element of `refs` should be a sequence of strings."
elif not isinstance(refs[0][0], str) and refs[0][0] is not None:
err_msg = "`refs` should be a sequence of sequence of strings."
elif len(refs) == 0:
err_msg = "`refs` should not be empty."
else:
for refs_streams in refs:
if isinstance(refs_streams, (str, bytes)) or not isinstance(
refs_streams, Sequence
):
err_msg = (
"Each element of `refs` should be a sequence of strings."
)
elif len(refs_streams) != len(hyps):
err_msg = (
"Each references stream in `refs` must have the same "
"length as `hyps`."
)
elif any(
not isinstance(line, str) and line is not None
for line in refs_streams
):
err_msg = "`refs` should be a sequence of sequence of strings."
if err_msg is not None:
break

if err_msg:
raise TypeError(f"{prefix}: {err_msg}")
Expand Down
Loading
Loading