unsloth/tests/test_missing_torchvision_vlm.py
Daniel Han 7b208bc35c
Fix misleading 'only for image models' error for Qwen3-VL when torchvision is missing (#6525)
* Fix misleading 'only for image models' error for Qwen3-VL when torchvision is missing

transformers >= 5.4 hard-requires torchvision for VLM image/video processors and
no longer falls back to a slow processor. Without torchvision the processor load
raises ImportError, unsloth degrades to a text-only tokenizer, and the vision data
collator later fails with 'UnslothVisionDataCollator is only for image models!'.

Detect this case at load time and raise a clear, actionable error pointing at the
missing torchvision dependency instead.

Fixes unslothai/unsloth#4202

* Apply kwarg-spacing format hook to vision torchvision guard (pre-commit)

* Make torchvision-missing detection precise: check availability first, match specific error text

* Tighten code comments (no logic change)

* Make missing-torchvision VLM error version-agnostic

The raise also fires on transformers 4.57.x for VLMs with a video processor
(Qwen2.5-VL, Qwen3-VL), where AutoVideoProcessor requires torchvision. The old
message claimed 'transformers >= 5.4 requires torchvision', which is inaccurate
on 4.57.x. Reword to state torchvision is required for this model's vision
processors without a version-specific claim.

---------

Co-authored-by: danielhanchen <michaelhan2050@gmail.com>
2026-06-23 01:28:09 -07:00

30 lines
1.2 KiB
Python

"""Regression test for unsloth#4202: detect missing torchvision so the loader can
surface the real cause instead of a misleading collator error."""
import importlib.util
from unittest import mock
from unsloth.models.vision import _missing_torchvision_error
def test_error_text_mentions_torchvision_is_detected():
err = ImportError("Qwen3VLVideoProcessor requires the Torchvision library but ...")
assert _missing_torchvision_error(err) is True
def test_torchvision_missing_is_detected_without_error():
with mock.patch.object(importlib.util, "find_spec", return_value = None):
assert _missing_torchvision_error(None) is True
def test_torchvision_present_unrelated_error_is_not_flagged():
sentinel = object()
with mock.patch.object(importlib.util, "find_spec", return_value = sentinel):
assert _missing_torchvision_error(ValueError("unrelated")) is False
assert _missing_torchvision_error(None) is False
def test_matches_real_environment():
# find_spec is the source of truth when no error is supplied.
expected = importlib.util.find_spec("torchvision") is None
assert _missing_torchvision_error(None) is expected