Handle null and populated extra_special_tokens

Coerce extra_special_tokens null to {} quietly (vanilla transformers also
crashes on null via .keys(), so it must be handled, but it is not a malformed
array worth warning about). For a populated list, log the dropped entries so
the coercion is not silent.
This commit is contained in:
Daniel Han 2026-06-28 03:09:32 +00:00
commit 961b814c0d
2 changed files with 28 additions and 9 deletions

View file

@ -91,7 +91,17 @@ def test_patched_coerces_non_empty_list(recording_logger):
d = _make_mixin()
d._set_model_specific_special_tokens(["<extra>"]) # must not raise
assert d.extra_special_tokens == {}
# Dropped entries are named in the warning so the loss is not silent.
assert len(recording_logger.warnings) == 1
assert "<extra>" in recording_logger.warnings[0]
def test_patched_coerces_none_quietly(recording_logger):
install_extra_special_tokens_compat()
d = _make_mixin()
d._set_model_specific_special_tokens(None) # null == absent; must not raise
assert d.extra_special_tokens == {}
assert recording_logger.warnings == [] # no false-positive warning for null
def test_patched_preserves_valid_dict(recording_logger):

View file

@ -36,18 +36,27 @@ def install_extra_special_tokens_compat() -> bool:
return True
def _patched(self, special_tokens):
if not isinstance(special_tokens, dict):
logger.warning(
"Coercing malformed extra_special_tokens (%s) to {}; "
"tokenizer_config.json should use an object, not an array.",
type(special_tokens).__name__,
if isinstance(special_tokens, dict):
return orig(self, special_tokens)
# A non-dict value (a JSON array, or null) crashes vanilla transformers on
# .keys(); coerce to {} so the model still loads. null is treated as absent;
# for a populated list we log the dropped entries so the loss is not silent.
if special_tokens is not None:
entries = (
list(special_tokens)
if isinstance(special_tokens, (list, tuple, set))
else special_tokens
)
special_tokens = {}
try:
self.extra_special_tokens = {}
except Exception:
pass
return orig(self, special_tokens)
logger.warning(
"Coercing malformed extra_special_tokens to {} (%s=%r); "
"tokenizer_config.json should use an object, not an array.",
type(special_tokens).__name__, entries,
)
try:
self.extra_special_tokens = {}
except Exception:
pass
return orig(self, {})
_patched.__wrapped__ = orig # keep original reachable
mixin._set_model_specific_special_tokens = _patched