import_fixes + drift detectors: cover transformers 5.x drift (#5423)

PR #5414's drift detectors and the corresponding import_fixes helpers
were written against transformers 4.x. The Repo tests (CPU) step (which
installs transformers>=4.51,<5.5 and currently resolves to 5.4.0)
surfaces three real predicate gaps:

  * test_pretrained_model_enable_input_require_grads_uses_old_pattern
    fires DRIFT DETECTED whenever the source contains
    "for module in self.modules()". But the unsloth replacement that
    patch_enable_input_require_grads installs ALSO uses that pattern --
    deliberately, just wrapped in try / except NotImplementedError. So
    the predicate cannot distinguish broken upstream from the working
    patch. Accept either pre-HF#41993 shape (no self.modules() loop) or
    the post-patch shape (loop + NotImplementedError handler).

  * test_transformers_torchcodec_available_flag_is_present asserts the
    pre-5.x module-level _torchcodec_available flag. transformers 5
    replaced it with an lru_cache'd is_torchcodec_available() callable.
    Accept either symbol. Also update disable_torchcodec_if_broken to
    actually disable on 5.x: clear the cache and rebind the function to
    return False.

Local verification:

  * transformers 4.57.6 + trl 0.25.1 + peft 0.19.1 + triton 3.5.1 +
    vllm 0.15.1+cu130 (the Core HF=4.57.6 cell shape): 18 passed.
  * transformers 5.8.1 + peft 0.19.1 + torch 2.9 CPU (the Repo tests
    (CPU) shape, drop trl / vllm / datasets / xformers): 12 passed,
    6 skipped on missing optional libs, 0 failed.

PR #5376's Repo tests (CPU) failure was a triple:
  - triton + enable_input_require_grads: fixed by merging current main
    (PR #5421's relaxed triton predicate + conftest 'import unsloth').
  - torchcodec: fixed by THIS PR.
This commit is contained in:
Daniel Han 2026-05-14 05:14:21 -07:00 committed by GitHub
commit 770714acc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 18 deletions

View file

@ -175,10 +175,12 @@ def test_trl_cached_available_flags_are_not_tuples():
def test_pretrained_model_enable_input_require_grads_uses_old_pattern():
"""``patch_enable_input_require_grads`` (import_fixes.py 609-670).
HF PR #41993 rewrote enable_input_require_grads to iterate
"""``patch_enable_input_require_grads`` (import_fixes.py 609-670). HF
PR #41993 rewrote enable_input_require_grads to iterate
``self.modules()`` and call ``get_input_embeddings`` on every
submodule; vision submodules then raise NotImplementedError."""
submodule; vision submodules then raise NotImplementedError. Healthy
state: either the upstream rewrite isn't present (pre-HF#41993), OR
the patch installed a NotImplementedError-tolerant replacement."""
pytest.importorskip("transformers")
from transformers import PreTrainedModel
@ -187,24 +189,34 @@ def test_pretrained_model_enable_input_require_grads_uses_old_pattern():
except Exception as exc:
pytest.skip(f"could not getsource(enable_input_require_grads): {exc!r}")
if "for module in self.modules()" in src:
pytest.fail(
"DRIFT DETECTED: PreTrainedModel.enable_input_require_grads now "
"iterates self.modules() (post HF#41993). "
"patch_enable_input_require_grads has to install a "
"NotImplementedError-tolerant replacement."
)
if "for module in self.modules()" not in src:
return # healthy: pre-HF#41993 shape
if "NotImplementedError" in src:
return # healthy: unsloth's tolerant replacement is installed
pytest.fail(
"DRIFT DETECTED: PreTrainedModel.enable_input_require_grads now "
"iterates self.modules() (post HF#41993) and has NOT been "
"wrapped by patch_enable_input_require_grads; vision submodules "
"(e.g. GLM V4.6's self.visual) will raise NotImplementedError "
"from get_input_embeddings and crash the whole call."
)
def test_transformers_torchcodec_available_flag_is_present():
"""``disable_torchcodec_if_broken`` (import_fixes.py 1291-1317).
Flips ``transformers.utils.import_utils._torchcodec_available`` to
False when torchcodec is installed but its FFmpeg deps are broken."""
"""``disable_torchcodec_if_broken`` (import_fixes.py 1291-1317). Needs
either the pre-5.x module-level ``_torchcodec_available`` flag, or
the 5.x ``is_torchcodec_available`` public function; one of the two
is the patch site the fix monkey-patches when FFmpeg is missing."""
tf_iu = pytest.importorskip("transformers.utils.import_utils")
assert hasattr(tf_iu, "_torchcodec_available"), (
"transformers.utils.import_utils._torchcodec_available was "
"removed/renamed upstream; disable_torchcodec_if_broken can no "
"longer disable a broken torchcodec install."
has_flag = hasattr(tf_iu, "_torchcodec_available")
has_func = callable(getattr(tf_iu, "is_torchcodec_available", None))
assert has_flag or has_func, (
"transformers.utils.import_utils dropped both "
"``_torchcodec_available`` (pre-5.x) AND "
"``is_torchcodec_available`` (>=5.x); "
"disable_torchcodec_if_broken can no longer disable a broken "
"torchcodec install."
)

View file

@ -1298,6 +1298,13 @@ def disable_torchcodec_if_broken():
This function tests if torchcodec can actually load and if not, patches
transformers to think torchcodec is unavailable so it falls back to librosa.
Two shapes to cover:
* transformers < 5: a module-level ``_torchcodec_available`` flag
cached in ``transformers.utils.import_utils``; flip it to False.
* transformers >= 5: a public ``is_torchcodec_available()`` callable
wrapped with ``functools.lru_cache``; replace it with a stub that
returns False and clear the cache so subsequent callers see it.
"""
try:
import importlib.util
@ -1311,11 +1318,25 @@ def disable_torchcodec_if_broken():
# torchcodec cannot load - disable it in transformers
try:
import transformers.utils.import_utils as tf_import_utils
except ImportError:
return
# transformers < 5 path: module-level cached flag.
try:
tf_import_utils._torchcodec_available = False
except (ImportError, AttributeError):
except AttributeError:
pass
# transformers >= 5 path: public lru_cache'd function. Clear any
# cached True result then rebind to a stub that returns False.
is_avail = getattr(tf_import_utils, "is_torchcodec_available", None)
if is_avail is not None:
try:
is_avail.cache_clear()
except AttributeError:
pass
tf_import_utils.is_torchcodec_available = lambda: False
def disable_broken_wandb():
"""Disable wandb if it's installed but cannot actually import.