Skip to content

tests: import_fixes drift detectors (HARD GATE on Core matrix)#5414

Merged
danielhanchen merged 3 commits into
mainfrom
sec/import-fixes-drift-detectors
May 14, 2026
Merged

tests: import_fixes drift detectors (HARD GATE on Core matrix)#5414
danielhanchen merged 3 commits into
mainfrom
sec/import-fixes-drift-detectors

Conversation

@danielhanchen
Copy link
Copy Markdown
Member

Summary

Adds tests/test_import_fixes_drift.py -- 18 drift detectors that fail loudly when an upstream pathology unsloth/import_fixes.py works around becomes active without a corresponding patch landing. Wires it into the Core matrix as a HARD GATE (no continue-on-error).

Mirrors the same pattern just landed on unslothai/unsloth-zoo#637 (commit ff5a3d8).

Why

import_fixes.py is a 1932-line catalog of patches for upstream regressions. Today the fixes run unconditionally at unsloth import; this is defensively correct but it means:

  • A fix becoming a no-op (upstream silently fixed itself) is invisible.
  • A fix becoming needed-but-broken (upstream drifted in a NEW way the workaround doesn't match) only surfaces as a downstream user crash.

The new suite is the drift detector: one test per fix_* / patch_* function, asserting the healthy upstream shape absent the regression. When the pathology is active, pytest.fail("DRIFT DETECTED: ...") -- never pytest.skip -- so the matrix cell goes RED and the maintainer triages on this PR, not in production.

What's covered (18 tests)

Upstream pathology import_fixes.py function Line range
protobuf MessageFactory drift fix_message_factory_issue 264-308
datasets 4.4.x recursion patch_datasets 574-586
TRL tuple-vs-bool _*_available (x2) fix_trl_vllm_ascend 493-516
PreTrainedModel.enable_input_require_grads source pattern (x2) patch_enable_input_require_grads 609-670
transformers torchcodec available disable_torchcodec_if_broken 1291-1317
transformers causal_conv1d available _disable_transformers_causal_conv1d 1881-1895
transformers + accelerate is_wandb_available (x2) disable_broken_wandb 1320-1372
peft transformers_weight_conversion import patch_peft_weight_converter_compatibility 1375-1454
triton 3.6+ CompiledKernel.num_ctas / cluster_dims fix_triton_compiled_kernel_missing_attrs 923-968
torch / torchvision pinned compat torchvision_compatibility_check 708-798
vllm GuidedDecodingParams / StructuredOutputsParams fix_vllm_guided_decoding_params 446-490
vllm aimv2 ovis config version fix_vllm_aimv2_issue 404-443
huggingface_hub is_offline_mode / HF_HUB_OFFLINE fix_huggingface_hub 913-920
torch.nn.init.trunc_normal_ presence patch_trunc_normal_precision_issue 971-1050
xformers post-num_splits-key fix version fix_xformers_performance_issue 312-341

Test plan

  • Verify locally: pytest tests/test_import_fixes_drift.py -v shows 15 passed + 3 failed on a current install (the 3 failures are real active drifts).
  • Verify the new import_fixes drift detectors (18 tests, HARD GATE) Core matrix step runs in each of the 3 cells (HF=4.57.6 + TRL<1, HF=default + TRL=default, HF=latest + TRL=latest).
  • Confirm the matrix cell goes RED when one of the 3 active drifts fires (proves the hard-gate works).
  • Once the active drifts are patched (either upstream resolves them or unsloth's import_fixes ships a compatible workaround), confirm all 18 tests pass and the matrix returns to green.

Ports zoo PR #637's drift-detector pattern to unsloth as a new
test file + Core matrix step.

Background
  unsloth/import_fixes.py is a 1932-line catalog of hand-rolled
  patches for upstream regressions: protobuf MessageFactory drift,
  datasets 4.4.x recursion, TRL tuple-vs-bool _*_available caching,
  transformers PreTrainedModel.enable_input_require_grads source
  pattern flip, triton CompiledKernel num_ctas missing, peft
  weight-converter ctor compat, torch/torchvision pairing, vllm
  guided_decoding params, etc. Today each fix runs unconditionally
  at unsloth import; that's defensively correct but it means:
    a fix becoming a no-op (upstream silently fixed itself) is
      invisible.
    a fix becoming needed-but-broken (upstream drifted in a new
      way the workaround doesn't match) only surfaces as a
      downstream crash.

tests/test_import_fixes_drift.py (18 tests)
  One drift detector per fix_* / patch_* function in import_fixes.py.
  Each test asserts the HEALTHY upstream shape absent the regression.
  When the pathology is currently ACTIVE, fires
  pytest.fail("DRIFT DETECTED: <fix function> needed because
  <observation>") -- NEVER pytest.skip. CI must go RED so the
  maintainer triages on the next PR.

  First run on the current install surfaces 3 active drifts:
    peft.utils.transformers_weight_conversion unimportable
      (transformers.conversion_mapping missing) -- patch_peft_
      weight_converter_compatibility will silently no-op.
    triton 3.5.1 CompiledKernel lacks num_ctas + cluster_dims --
      fix_triton_compiled_kernel_missing_attrs is live-needed.
    vllm exposes only StructuredOutputsParams, not
      GuidedDecodingParams -- fix_vllm_guided_decoding_params
      is live-needed.

CI wiring (.github/workflows/consolidated-tests-ci.yml)
  New step `import_fixes drift detectors (18 tests, HARD GATE)`
  added to the Core matrix BEFORE the Bucket-A tests, so the matrix
  cell fails fast on a real upstream regression. No
  continue-on-error: a drift detection MUST go red.

This mirrors the same change just landed on
unslothai/unsloth-zoo#637 (commit ff5a3d8). Same fail-loud-on-drift
semantic; same set of fix functions covered; same 1:1 mapping
between test + import_fixes.py source-of-truth function.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive suite of drift detectors in tests/test_import_fixes_drift.py to monitor upstream library regressions that Unsloth currently patches. The feedback identifies several critical issues where the tests as written will cause permanent CI failures even when Unsloth's workarounds are successfully active. Specifically, several tests rely on version checks or string matching that don't account for the fact that the code has been monkey-patched or rewritten by Unsloth. Additionally, there is a recommendation to avoid broad exception handling in the TRL accessor check to prevent masking actual bugs.

Comment on lines +203 to +204
if not isinstance(result, bool):
bad[name] = (type(result).__name__, result)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The broad except Exception: continue block silently ignores any accessor that raises an error. While this is intended to skip functions with required arguments, it also masks potential bugs or new types of drift where an accessor might crash (e.g., due to a broken internal dependency or a regression in trl itself). It is safer to catch specific expected exceptions (like TypeError from signature mismatch) or log the exception to aid in debugging, as per the general rules.

References
  1. When handling exceptions, avoid broad except Exception: pass clauses. Instead, catch specific exceptions and log them (at least at a debug level) to aid in troubleshooting.


if "for module in self.modules()" in src:
pytest.fail(
"DRIFT DETECTED: PreTrainedModel.enable_input_require_grads now "
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test will fail even when the patch_enable_input_require_grads workaround is successfully applied. The workaround (defined in unsloth/import_fixes.py at line 636) uses the for module in self.modules() pattern but wraps the call in a try...except NotImplementedError block. Since this test checks for the presence of that string in the source of the patched method, it will trigger a pytest.fail even if the pathology has been safely mitigated. Consider updating the check to distinguish between the problematic upstream implementation and the safe Unsloth replacement (e.g., by checking for the presence of the NotImplementedError handler).

Comment on lines +426 to +427

pytest.fail(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This check targets the CompiledKernel class, but the corresponding fix in import_fixes.py (lines 957-964) only injects the missing attributes into instances via a patched __init__. Consequently, on Triton 3.6.0+, this test will always fail because the class itself still lacks the attributes, even if the workaround is active and effective for instances. To accurately detect drift while allowing the workaround to pass, consider verifying an instance or checking if __init__ has been monkey-patched by Unsloth.

"fix_vllm_aimv2_issue rewrites ovis.py to skip the duplicate "
'AutoConfig.register("aimv2", ...) call.'
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test performs a strict version check (vllm_v < cutoff) and fails if the version is old. However, unsloth/import_fixes.py provides a workaround for these older versions by rewriting the ovis.py config file. As a result, this test will cause a permanent CI failure for environments using these supported (but patched) vLLM versions. To function as a true drift detector that allows the matrix to return to green when a workaround is present, the test should check for the actual presence of the problematic code in ovis.py rather than just the package version. The same applies to test_xformers_is_post_num_splits_key_fix_or_not_installed at line 654.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18ebd816a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/test_import_fixes_drift.py Outdated
Comment on lines +426 to +427
if hasattr(ck_cls, "num_ctas"):
return # healthy: old-style triton with direct attr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check cluster_dims before declaring Triton healthy

For Triton builds that restore CompiledKernel.num_ctas but still lack cluster_dims, this early return marks the stack healthy even though the workaround and the docstring both require cluster_dims as well. Because fix_triton_compiled_kernel_missing_attrs also no-ops when num_ctas exists, this detector would miss exactly the partial upstream drift that can still leave torch.compile launcher paths crashing; verify both attributes before returning.

Useful? React with 👍 / 👎.

Comment on lines +393 to +394
expected_params = {"weight_conversions", "adapter_name"}
actual_params = set(sig.parameters)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require peft_config in the PEFT signature check

If PEFT removes or renames the optional peft_config parameter while leaving weight_conversions and adapter_name, this test still passes, but patch_peft_weight_converter_compatibility always calls the original build_peft_weight_mapping(weight_conversions, adapter_name, peft_config), so the wrapper would start raising TypeError at runtime. Include peft_config in the expected signature so the detector catches that drift.

Useful? React with 👍 / 👎.

Strictly comment / docstring trims. AST-verified comment-only.

* Module header: 36 lines -> 7 lines.
* Per-test docstring: collapse each 7-15 line prose block to a 1-3
  line lead naming the import_fixes.py function + line range plus
  the one-sentence why; pytest.fail messages stay verbatim so a
  red CI cell still names the upstream regression.
* Helper docstrings (_safe_version, _is_custom_torch_build): drop.
* Inline narrative comments inside test bodies: drop.
* Section dividers and licence header: untouched.

Net: 700 -> 537 lines, zero behaviour changes.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c38b8f709

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# HARD GATE: a red cell here is a real upstream regression
# without a corresponding zoo / unsloth-side workaround.
run: |
python -m pytest -v --tb=short tests/test_import_fixes_drift.py
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Install optional deps before hard-gating their drift checks

In the Core job this command runs in an environment whose install step adds torch/transformers/trl/peft/etc. but not vllm or xformers (I checked the workflow install block and repo-wide rg only finds those names in comments). The new vLLM detectors call pytest.importorskip("vllm"), and the xformers detector skips when find_spec("xformers") is None, so every matrix cell silently skips the advertised vLLM/aimv2 and xformers drift coverage while this step is labeled a hard gate. Install those optional packages for this step or remove/split those detectors so the gate can actually catch those regressions.

Useful? React with 👍 / 👎.

@danielhanchen danielhanchen merged commit 1343de1 into main May 14, 2026
10 of 15 checks passed
@danielhanchen danielhanchen deleted the sec/import-fixes-drift-detectors branch May 14, 2026 11:36
pull Bot pushed a commit to TKaxv-7S/unsloth that referenced this pull request May 14, 2026
…thai#5414)

* tests: import_fixes drift detectors (HARD GATE on Core matrix)

Ports zoo PR unslothai#637's drift-detector pattern to unsloth as a new
test file + Core matrix step.

Background
  unsloth/import_fixes.py is a 1932-line catalog of hand-rolled
  patches for upstream regressions: protobuf MessageFactory drift,
  datasets 4.4.x recursion, TRL tuple-vs-bool _*_available caching,
  transformers PreTrainedModel.enable_input_require_grads source
  pattern flip, triton CompiledKernel num_ctas missing, peft
  weight-converter ctor compat, torch/torchvision pairing, vllm
  guided_decoding params, etc. Today each fix runs unconditionally
  at unsloth import; that's defensively correct but it means:
    a fix becoming a no-op (upstream silently fixed itself) is
      invisible.
    a fix becoming needed-but-broken (upstream drifted in a new
      way the workaround doesn't match) only surfaces as a
      downstream crash.

tests/test_import_fixes_drift.py (18 tests)
  One drift detector per fix_* / patch_* function in import_fixes.py.
  Each test asserts the HEALTHY upstream shape absent the regression.
  When the pathology is currently ACTIVE, fires
  pytest.fail("DRIFT DETECTED: <fix function> needed because
  <observation>") -- NEVER pytest.skip. CI must go RED so the
  maintainer triages on the next PR.

  First run on the current install surfaces 3 active drifts:
    peft.utils.transformers_weight_conversion unimportable
      (transformers.conversion_mapping missing) -- patch_peft_
      weight_converter_compatibility will silently no-op.
    triton 3.5.1 CompiledKernel lacks num_ctas + cluster_dims --
      fix_triton_compiled_kernel_missing_attrs is live-needed.
    vllm exposes only StructuredOutputsParams, not
      GuidedDecodingParams -- fix_vllm_guided_decoding_params
      is live-needed.

CI wiring (.github/workflows/consolidated-tests-ci.yml)
  New step `import_fixes drift detectors (18 tests, HARD GATE)`
  added to the Core matrix BEFORE the Bucket-A tests, so the matrix
  cell fails fast on a real upstream regression. No
  continue-on-error: a drift detection MUST go red.

This mirrors the same change just landed on
unslothai/unsloth-zoo#637 (commit ff5a3d8). Same fail-loud-on-drift
semantic; same set of fix functions covered; same 1:1 mapping
between test + import_fixes.py source-of-truth function.

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

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

* chore: trim verbose docstrings in import_fixes drift detectors

Strictly comment / docstring trims. AST-verified comment-only.

* Module header: 36 lines -> 7 lines.
* Per-test docstring: collapse each 7-15 line prose block to a 1-3
  line lead naming the import_fixes.py function + line range plus
  the one-sentence why; pytest.fail messages stay verbatim so a
  red CI cell still names the upstream regression.
* Helper docstrings (_safe_version, _is_custom_torch_build): drop.
* Inline narrative comments inside test bodies: drop.
* Section dividers and licence header: untouched.

Net: 700 -> 537 lines, zero behaviour changes.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
pull Bot pushed a commit to steelburn/unsloth that referenced this pull request May 14, 2026
…ai#5423)

PR unslothai#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 unslothai#5376's Repo tests (CPU) failure was a triple:
  - triton + enable_input_require_grads: fixed by merging current main
    (PR unslothai#5421's relaxed triton predicate + conftest 'import unsloth').
  - torchcodec: fixed by THIS PR.
josephGuo pushed a commit to josephGuo/unsloth that referenced this pull request May 15, 2026
…xes_drift.py) (unslothai#5428)

* tests: ship public-api surface drift detector + wire into Core matrix

Companion to tests/test_import_fixes_drift.py (PR unslothai#5414): that file
catches drift in THIRD-PARTY libs (transformers / trl / triton / peft /
vllm / torchcodec / xformers); this file catches drift in unsloth's
OWN public-surface API -- the top-9 classmethods + symbols that
unslothai/notebooks calls at ~2000 cumulative sites.

Closes the gap where a refactor on this repo (e.g. renaming
FastLanguageModel.from_pretrained -> .load) would pass unsloth CI
green and surface only on the next unslothai/notebooks CI run, or
worse, on a user's Colab crash report.

Coverage (call-site counts measured against unslothai/notebooks main):
  test_fast_language_model_class_present
  test_fast_language_model_from_pretrained_kwargs        506 sites
  test_fast_language_model_get_peft_model_kwargs         304 sites
  test_fast_language_model_for_inference_callable        370 sites
  test_fast_vision_model_class_and_methods         (4 methods)
  test_fast_vision_model_get_peft_model_vision_kwargs    (4 kwargs)
  test_fast_model_class_and_methods                (2 methods)
  test_fast_model_from_pretrained_kwargs                 103 sites
  test_is_bf16_supported_or_alias_callable        48 + 8 sites

Each test asserts the healthy public shape via inspect.signature; on
regression fires pytest.fail("DRIFT DETECTED: ...") -- never
pytest.skip -- so the Core matrix cell goes red. Mirrors the same
skeleton used by tests/test_import_fixes_drift.py.

Wired as a new step in consolidated-tests-ci.yml right after the
import_fixes drift step, inside every Core matrix cell.

Local verification on transformers 4.57.6 + unsloth main:
  pytest tests/test_public_api_surface.py -v
  -> 9 passed in 0.02s

* [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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant