Fix string-name normalization in SamplingMetric (inspect.getmembers returns a list, not a dict)#1292
Open
teddytennant wants to merge 1 commit into
Open
Conversation
`inspect.getmembers` returns a list of (name, fn) tuples, but the code treated it as a dict: the `normalize in allowed_normalizations` membership test never matched a plain string and `allowed_normalizations[normalize]` would raise TypeError. As a result, passing any string for `normalize` (a supported public-API form, per the `Callable | str | None` type hint) always raised `ValueError: Unknown normalization function: <name>`, even for valid names like "gsm8k_normalizer". Wrap the getmembers result in `dict()` so `in` checks function names and indexing does a key lookup. Unknown names still fall through to the existing ValueError.
ErenAta16
approved these changes
Jul 10, 2026
ErenAta16
left a comment
There was a problem hiding this comment.
Confirmed the root cause directly: inspect.getmembers() returns a list[tuple[str, Callable]], not a dict, so normalize in allowed_normalizations was checking a string against a list of tuples (always False) and allowed_normalizations[normalize] would have raised TypeError on a list. Wrapping it in dict() is the correct fix, and it means every string-based normalize was silently broken before this, not just some edge case.
The regression test is solid: it checks the resolved function is the actual gsm8k_normalizer (not just that no exception is raised), applies it to confirm the normalization itself works end to end, and keeps the unknown-name path raising ValueError. Looks correct.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Wrap the
inspect.getmembers(...)result indict()insideSamplingMetric.__init__so that anormalizepassed as a string is correctly resolved to the named function inlighteval.metrics.normalizations.Why
SamplingMetric.__init__acceptsnormalize: Callable | str | None. When a string is passed, it is resolved via:But
inspect.getmembersreturns a list of(name, fn)tuples, not a dict. So:normalize in allowed_normalizationsis a membership test of a plain string against a list of tuples — alwaysFalse.allowed_normalizations[normalize]would string-index a list —TypeError.Net effect: passing any string for
normalizealways raisesValueError: Unknown normalization function: <name>, even for valid names such as"gsm8k_normalizer"or"math_normalizer". This affects the base class shared byAvgAtN,MajAtN,PassAtK, andGPassAtK. It stays latent because all built-in metrics pass callables /sample_scoring_function, never a string — only custom-metric users who pass a normalizer by name hit it.Wrapping the result in
dict()makesincheck function names and indexing do a key lookup. Unknown names still fall through to the existingValueError.Testing
Added
tests/test_unit_base_metrics.py::TestBaseMetrics::test_sampling_metric_normalize_by_name, a pure-CPU regression test that:AvgAtN(n=1, normalize="gsm8k_normalizer")and asserts it resolves tonormalizations.gsm8k_normalizer,preprocess("The answer is #### 18") == "18"),ValueError.The test fails before this change (
ValueError: Unknown normalization function: gsm8k_normalizer) and passes after.