unsloth/tests
Daniel Han 12295c1fdb
import_fixes: stub-module injection for peft.utils.transformers_weight_conversion on transformers 4.x (#5416)
* import_fixes: stub transformers.conversion_mapping so peft 0.19.x imports on transformers 4.x

patch_peft_weight_converter_compatibility currently opens with

    try:
        from peft.utils import transformers_weight_conversion as twc
    except (ImportError, AttributeError):
        return

which silently no-ops on (peft 0.19.x, transformers 4.57.x): peft's
transformers_weight_conversion module unconditionally imports two
transformers-v5 submodules at module top

    from transformers.conversion_mapping import ...
    from transformers.core_model_loading import ...

and neither submodule exists on transformers < 5. peft itself only USES
those submodules inside an is_transformers_ge_v5 branch, but the top of
file import still explodes with

    ModuleNotFoundError: No module named 'transformers.conversion_mapping'

The bare except above swallows that, so the weight converter compat
wrap never gets installed, and any downstream code that later does
from peft.utils import transformers_weight_conversion crashes with the
same ModuleNotFoundError.

Fix: synthesise minimal stub modules for transformers.conversion_mapping
and transformers.core_model_loading, install them into sys.modules, and
re-import peft.utils.transformers_weight_conversion so the kwargs compat
wrap can succeed on top. The stubs expose exactly the symbols peft 0.19.x
pulls in at module top (Concatenate / ConversionOps are real subclassable
classes since peft subclasses them as PeftConcatenate / FlattenDims /
PermuteDims), so peft's own class creation succeeds. None of the stubbed
callables actually fire on the 4.x branch because peft's runtime
is_transformers_ge_v5 gate keeps them unreachable.

Gating contract (strict no-op outside the (peft 0.19.x, transformers 4.x)
combination):
  * No-op if peft is not installed.
  * No-op if peft.utils.transformers_weight_conversion already imports
    clean (transformers v5+, or any peft fork off the v5 path).
  * Strictly additive: only stubs submodules that are currently missing
    from sys.modules / find_spec. We never overwrite the real
    transformers.conversion_mapping / transformers.core_model_loading
    on transformers v5+.
  * Idempotent: sentinel attribute (__unsloth_stub__) on the stub modules
    makes a second call return False, a third call return False, etc.
  * Surfaces drift unchanged: if peft fails for some reason OTHER than
    these two specific missing submodules, the original ImportError is
    left for the caller's own try/except to take over.

Forwards / backwards compatibility:
  * transformers 4.57.6 -> install stubs.
  * transformers 5.x (real submodules) -> first-import probe succeeds,
    return False, never touch sys.modules.
  * TRL 0.22 / 0.27 / 1.x -- none of these import either submodule
    directly; they reach the peft conversion module (if at all) through
    peft.tuners.tuners_utils, behind peft's own is_transformers_ge_v5
    gate. Stubs are therefore unreachable from TRL on a 4.x install,
    and on a 5.x install the real submodules win the import race.
  * peft 0.18 / 0.19 / 0.20 -- the symbols stubbed cover the union of
    what peft pulls at module top across the 0.19.x line; older peft
    that doesn't import the v5 submodules at all hits the cheap
    first-import-probe exit and we never touch sys.modules.

Wired into unsloth/_gpu_init.py to run BEFORE
patch_peft_weight_converter_compatibility (otherwise that function's
bare except would still silently no-op). Mirrors the equivalent fix
shipped in unsloth-zoo (the zoo-side stub installs itself via
apply_import_fixes() at zoo import time, but a user can run
unsloth without the zoo fix on an older unsloth_zoo, so the unsloth
side needs to own its own copy of the workaround).

tests/conftest.py is updated to pre-apply this specific fix via the
standalone import-fixes module so the GPU-free drift detector test
(tests/test_import_fixes_drift.py::test_peft_transformers_weight_conversion_importable_and_signature)
sees the same patched state that a real ``import unsloth`` would.
The pattern mirrors unsloth-zoo's tests/conftest.py
_apply_zoo_import_fixes_for_tests helper, scoped to just the peft fix.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-05-14 03:52:06 -07:00
..
notebooks CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
python fix: unblock 4 tests deselected/skipped in #5312 (real bugs) (#5359) 2026-05-11 02:39:17 -07:00
qlora Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" 2025-12-01 07:24:58 -08:00
saving chore: fix typo cleanup across tests and backend strings (#5152) 2026-04-24 12:51:27 +01:00
security security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
sh fix(tests/sh): accept pinned tokenizers line after #5359 (#5361) 2026-05-11 02:58:20 -07:00
studio studio: security and hardening pass (auth rate-limit, sandbox, path containment, schema validation, headers) (#5375) 2026-05-13 06:12:18 -07:00
utils feat: Add cactus QAT scheme support (#4679) 2026-04-15 07:40:03 -07:00
version_compat CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
vllm_compat CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
__init__.py Qwen 3, Bug Fixes (#2445) 2025-04-30 22:38:39 -07:00
_zoo_aggressive_cuda_spoof.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
conftest.py import_fixes: stub-module injection for peft.utils.transformers_weight_conversion on transformers 4.x (#5416) 2026-05-14 03:52:06 -07:00
run_all.sh fix: add tokenizers to no-torch deps and TORCH_CONSTRAINT for arm64 macOS py313+ (#4748) 2026-04-01 06:12:17 -07:00
test_cli_export_unpacking.py studio: stream export worker output into the export dialog (#4897) 2026-04-14 08:55:43 -07:00
test_gemma4_chat_template.py update gema4 chat templates (#5116) 2026-04-22 09:04:08 -07:00
test_get_model_name.py feat: Add support for OLMo-3 model (#4678) 2026-04-15 07:39:11 -07:00
test_loader_glob_skip.py Add unit tests for HfFileSystem glob skip guard (#4854) 2026-04-06 08:54:36 -07:00
test_model_registry.py Revert "[FIX] Vllm guided decoding params (#3662)" 2025-12-01 05:43:45 -08:00
test_multi_image_grpo_chunking.py Multi Image GRPO (#5197) 2026-05-13 04:27:49 -07:00
test_peft_weight_converter_compat.py Patch checkpoint reload init functions to strip unsupported args (#5167) 2026-04-29 02:50:49 -07:00
test_raw_text.py Add Studio PR-time CI: pin enforcement, frontend, backend, wheel smoke (#5298) 2026-05-06 04:41:57 -07:00
test_resolve_model_class.py fix: guard resolve_model_class fallback against unresolvable transformers AutoModel entries (#5155) 2026-04-24 05:59:17 -07:00
test_studio_install_workspace_guard.py studio: security and hardening pass (auth rate-limit, sandbox, path containment, schema validation, headers) (#5375) 2026-05-13 06:12:18 -07:00
test_studio_root_resilience.py install: support STUDIO_HOME / UNSLOTH_STUDIO_HOME for custom install paths (#5190) 2026-05-05 23:17:40 -07:00