unsloth/tests/version_compat
Daniel Han 79a431cd53
tests: pinned-symbol canary for unsloth-zoo save_pretrained_merged guards (#5410) (#5433)
* tests: pinned-symbol canary for unsloth-zoo save_pretrained_merged guards (#5410)

unsloth#5410 was a class of silent-write bug in the
save_pretrained_merged path that the existing CI matrix could not
detect because the merge-helper tests were not wired through the
upstream-drift suite. The full fix lives in unslothai/unsloth-zoo#647
(layout-aware MoE merge helpers, authoritative num_experts resolver,
loud-fail counter, generation_config.json save). This PR adds the
unsloth-side canary that watches for the four guards staying in place
in unsloth-zoo so a future refactor cannot silently regress them.

tests/version_compat/test_unsloth_zoo_save_merged_pinned_symbols.py
fetches unsloth_zoo/saving_utils.py + tests/test_unsloth_zoo_lora_merge.py
from unslothai/unsloth-zoo:main and asserts:

- _MOE_MERGE_STATE / _reset_moe_merge_state / _record_moe_merge_fallback
  are still defined and a `raise RuntimeError(...MoE...)` still fires
  when fallback > 0.
- _detect_moe_lora_layout exists and both "swapped" / "standard" branch
  labels are reachable in the source.
- _resolve_num_experts_from_lora_stats is present AND its base_layer
  walk is bounded by `for _ in range(N):` (a cyclic ParamWrapper chain
  must not hang the merge).
- merge_and_overwrite_lora still calls
  model.generation_config.save_pretrained(...).
- tests/test_unsloth_zoo_lora_merge.py keeps the six PEFT 0.19+
  standard-layout regression tests added in #647.
- Local unsloth/save.py still names save_pretrained_merged and
  routes through merge_and_overwrite_lora (i.e. the entry point still
  reaches the upstream fix).

While #647 is still open, the four symbol tests SKIP cleanly with a
message naming #647. When #647 merges into unsloth-zoo main, the same
tests automatically become hard gates and catch any future regression.
The sixth test (local entry-point grep) passes today.

CPU-only static fetch, ~0.1s. Wired into the existing peft-pinned-symbols
job in .github/workflows/version-compat-ci.yml so it runs on every PR
that touches unsloth/** and on the daily schedule.

Local run: 1 passed, 5 skipped (expected; #647 open).

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

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

* tests/version_compat: relax MoE/generation_config regex to fit zoo#647

zoo#647 landed two layout changes that broke the pinned-symbol
canary's exact-string regex matches but kept the underlying
guarantees intact:

- The post-loop MoE LoRA fallback `raise RuntimeError(...)` wraps
  the "MoE" wording onto a second line; the old `[^\n]*` did not
  cross newlines. Switch to `.*?` + re.DOTALL.

- The generation_config save now binds the attr to a local var
  `gen_cfg = getattr(model, "generation_config", ...)` and calls
  `gen_cfg.save_pretrained(save_directory)`, so a literal
  `generation_config.save_pretrained(` substring no longer matches.
  Anchor on the conceptual operation: a `generation_config` mention
  followed (within a small char window) by a `.save_pretrained(`
  call. That is what the canary actually cares about.

Verified locally:
  pytest tests/version_compat/test_unsloth_zoo_save_merged_pinned_symbols.py
    -> 2 passed (4 deselected)

---------

Co-authored-by: Daniel Han-Chen <info@unsloth.ai>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-05-17 01:35:28 -07:00
..
__init__.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
_fetch.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_bitsandbytes_pinned_symbols.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_peft_pinned_symbols.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_sentence_transformers_pinned_symbols.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_transformers_pinned_symbols.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_trl_grpo_pinned_symbols.py CI: scope GITHUB_TOKEN permissions, add MLX CI, unblock ~60 skipped tests (#5312) 2026-05-11 03:19:13 -07:00
test_unsloth_zoo_save_merged_pinned_symbols.py tests: pinned-symbol canary for unsloth-zoo save_pretrained_merged guards (#5410) (#5433) 2026-05-17 01:35:28 -07:00