diff --git a/tests/test_import_fixes_drift.py b/tests/test_import_fixes_drift.py index 7f8402135f..f90556bf66 100644 --- a/tests/test_import_fixes_drift.py +++ b/tests/test_import_fixes_drift.py @@ -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." ) diff --git a/unsloth/import_fixes.py b/unsloth/import_fixes.py index e6d81b2f8c..8476edc40a 100644 --- a/unsloth/import_fixes.py +++ b/unsloth/import_fixes.py @@ -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.