Merge remote-tracking branch 'origin/main' into docker-blackwell-build

This commit is contained in:
Daniel Han 2026-07-27 13:18:15 +00:00
commit a34b22390f
265 changed files with 33897 additions and 1883 deletions

View file

@ -40,7 +40,7 @@ def _registrations(source):
def test_cpo_registration_matches_orpo():
regs = _registrations(open(RL_PATH).read())
regs = _registrations(open(RL_PATH, encoding = "utf-8").read())
shared = {"orpo_trainer_text_tokenizer", "orpo_trainer_processor_pad_token"}
assert shared <= set(regs.get("orpo_trainer", []))
assert shared <= set(regs.get("cpo_trainer", []))
@ -48,7 +48,7 @@ def test_cpo_registration_matches_orpo():
def _load_pad_rewriter():
"""Exec orpo_trainer_processor_pad_token (+ _PAD_FALLBACK) without importing unsloth."""
tree = ast.parse(open(RL_PATH).read())
tree = ast.parse(open(RL_PATH, encoding = "utf-8").read())
nodes = []
for n in tree.body:
if isinstance(n, ast.Assign) and any(

View file

@ -11,7 +11,7 @@ RL_PATH = os.path.join(REPO_ROOT, "unsloth", "models", "rl_replacements.py")
def _load_helpers():
src = open(RL_PATH).read()
src = open(RL_PATH, encoding = "utf-8").read()
tree = ast.parse(src)
import torch as _torch

View file

@ -193,7 +193,7 @@ class TestBeforeAfterImportChain:
mm = types.ModuleType('model_mappings')
mm.MODEL_TO_TEMPLATE_MAPPER = {{}}
sys.modules['model_mappings'] = mm
source = open({str(before_file)!r}).read()
source = open({str(before_file)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
exec(source)
@ -215,7 +215,7 @@ class TestBeforeAfterImportChain:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(before_file)!r}).read())
exec(open({str(before_file)!r}, encoding = "utf-8").read())
""")
result = _run_in_sandbox(no_torch_venv, code)
assert result.returncode != 0, "BEFORE data_collators.py should crash without torch"
@ -284,7 +284,7 @@ class TestBeforeAfterImportChain:
it = types.ModuleType('iterable')
it.is_streaming_dataset = lambda *a, **k: False
sys.modules['iterable'] = it
source = open({str(CHAT_TEMPLATES)!r}).read()
source = open({str(CHAT_TEMPLATES)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
source = source.replace('from .iterable import', 'from iterable import')
@ -304,7 +304,7 @@ class TestBeforeAfterImportChain:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
print("OK")
""")
result = _run_in_sandbox(no_torch_venv, code)
@ -382,7 +382,7 @@ class TestDataclassInstantiation:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = DataCollatorSpeechSeq2SeqWithPadding(processor=None)
assert obj.processor is None
print("OK")
@ -397,7 +397,7 @@ class TestDataclassInstantiation:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = DeepSeekOCRDataCollator(processor=None)
assert obj.processor is None
assert obj.max_length == 2048
@ -414,7 +414,7 @@ class TestDataclassInstantiation:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = VLMDataCollator(processor=None)
assert obj.processor is None
assert obj.max_length == 2048
@ -441,7 +441,7 @@ class TestDataclassInstantiation:
it.is_streaming_dataset = lambda *a, **k: False
sys.modules['iterable'] = it
ns = {{}}
source = open({str(CHAT_TEMPLATES)!r}).read()
source = open({str(CHAT_TEMPLATES)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
source = source.replace('from .iterable import', 'from iterable import')
@ -473,7 +473,7 @@ class TestEdgeCasesBrokenTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
exec(open({str(sandbox_dir / 'data_collators.py')!r}).read())
exec(open({str(sandbox_dir / 'data_collators.py')!r}, encoding = "utf-8").read())
obj = DataCollatorSpeechSeq2SeqWithPadding(processor=None)
print("OK: data_collators works despite broken torch on sys.path")
""")
@ -495,7 +495,7 @@ class TestEdgeCasesBrokenTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
source = open({str(HARDWARE_PY)!r}).read()
source = open({str(HARDWARE_PY)!r}, encoding = "utf-8").read()
ns = {{'__name__': '__test__'}}
exec(source, ns)
result = ns['detect_hardware']()
@ -530,7 +530,7 @@ class TestEdgeCasesBrokenTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
source = open({str(HARDWARE_PY)!r}).read()
source = open({str(HARDWARE_PY)!r}, encoding = "utf-8").read()
ns = {{'__name__': '__test__'}}
exec(source, ns)
result = ns['detect_hardware']()
@ -559,7 +559,7 @@ class TestEdgeCasesBrokenTorch:
sys.modules['iterable'] = it
ns = {{}}
source = open({str(CHAT_TEMPLATES)!r}).read()
source = open({str(CHAT_TEMPLATES)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
source = source.replace('from .iterable import', 'from iterable import')
@ -604,7 +604,7 @@ class TestHardwareDetectionNoTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
source = open({str(HARDWARE_PY)!r}).read()
source = open({str(HARDWARE_PY)!r}, encoding = "utf-8").read()
ns = {{'__name__': '__test__'}}
exec(source, ns)
device = ns['detect_hardware']()
@ -624,7 +624,7 @@ class TestHardwareDetectionNoTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
source = open({str(HARDWARE_PY)!r}).read()
source = open({str(HARDWARE_PY)!r}, encoding = "utf-8").read()
ns = {{'__name__': '__test__'}}
exec(source, ns)
versions = ns['get_package_versions']()
@ -651,7 +651,7 @@ class TestHardwareDetectionNoTorch:
code = textwrap.dedent(f"""\
import sys
sys.path.insert(0, {str(sandbox_dir)!r})
source = open({str(hw_sandbox / 'hardware.py')!r}).read()
source = open({str(hw_sandbox / 'hardware.py')!r}, encoding = "utf-8").read()
ns = {{'__name__': '__test__'}}
exec(source, ns)
assert callable(ns['detect_hardware'])

View file

@ -14,7 +14,7 @@ UTILS_PATH = REPO_ROOT / "unsloth" / "models" / "_utils.py"
def _source(path):
return path.read_text()
return path.read_text(encoding = "utf-8")
def _class_method(tree, class_name, method_name):

View file

@ -12,7 +12,7 @@ LLAMA_PATH = REPO_ROOT / "unsloth" / "models" / "llama.py"
def _source(path):
return path.read_text()
return path.read_text(encoding = "utf-8")
def _class_method(tree, class_name, method_name):

View file

@ -17,13 +17,13 @@ def _find_geteuid_guard(tree: ast.AST):
def test_gpu_init_has_geteuid_guard():
tree = ast.parse(GPU_INIT.read_text())
tree = ast.parse(GPU_INIT.read_text(encoding = "utf-8"))
guard = _find_geteuid_guard(tree)
assert guard is not None, "_gpu_init.py must guard ldconfig recovery on os.geteuid()"
def test_ldconfig_calls_only_inside_geteuid_guard():
src = GPU_INIT.read_text()
src = GPU_INIT.read_text(encoding = "utf-8")
tree = ast.parse(src)
guard = _find_geteuid_guard(tree)
assert guard is not None
@ -39,6 +39,6 @@ def test_ldconfig_calls_only_inside_geteuid_guard():
def test_non_root_branch_warns_when_bnb_present():
src = GPU_INIT.read_text()
src = GPU_INIT.read_text(encoding = "utf-8")
assert "elif bnb is not None" in src
assert "sudo ldconfig" in src

View file

@ -9,7 +9,7 @@ SOURCE_PATH = os.path.join(REPO_ROOT, "unsloth", "models", "rl_replacements.py")
def _read_source() -> str:
with open(SOURCE_PATH, "r") as fh:
with open(SOURCE_PATH, "r", encoding = "utf-8") as fh:
return fh.read()

View file

@ -10,7 +10,7 @@ RL_PATH = os.path.join(REPO_ROOT, "unsloth", "models", "rl_replacements.py")
def _load_orpo_rewriter(name = "orpo_trainer_text_tokenizer"):
src = open(RL_PATH).read()
src = open(RL_PATH, encoding = "utf-8").read()
tree = ast.parse(src)
ns = {"re": re}
# Materialise sibling module-level _-prefixed assignments the rewriter may reference.

View file

@ -21,7 +21,7 @@ WANTED = {
def _load_pad_helpers():
"""Exec only the pad-token helpers with a stub logger (no heavy imports)."""
tree = ast.parse(open(TOK_PATH).read())
tree = ast.parse(open(TOK_PATH, encoding = "utf-8").read())
nodes = []
for node in tree.body:
if isinstance(node, ast.Assign):

View file

@ -148,7 +148,7 @@ class TestDataCollatorsNoTorchVenv:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
print("OK: exec succeeded")
""")
result = subprocess.run(
@ -168,7 +168,7 @@ class TestDataCollatorsNoTorchVenv:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = DataCollatorSpeechSeq2SeqWithPadding(processor=None)
assert obj.processor is None, "processor should be None"
print("OK: DataCollatorSpeechSeq2SeqWithPadding instantiated")
@ -190,7 +190,7 @@ class TestDataCollatorsNoTorchVenv:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = DeepSeekOCRDataCollator(processor=None)
assert obj.processor is None, "processor should be None"
assert obj.max_length == 2048, "default max_length should be 2048"
@ -212,7 +212,7 @@ class TestDataCollatorsNoTorchVenv:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({str(DATA_COLLATORS)!r}).read())
exec(open({str(DATA_COLLATORS)!r}, encoding = "utf-8").read())
obj = VLMDataCollator(processor=None)
assert obj.processor is None
assert obj.mask_input_tokens is True, "default mask_input_tokens should be True"
@ -259,7 +259,7 @@ class TestChatTemplatesNoTorchVenv:
sys.modules['iterable'] = iterable
# Read and transform the source: replace relative imports with absolute
source = open({str(CHAT_TEMPLATES)!r}).read()
source = open({str(CHAT_TEMPLATES)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
source = source.replace('from .iterable import', 'from iterable import')
@ -305,7 +305,7 @@ class TestChatTemplatesNoTorchVenv:
sys.modules['iterable'] = iterable
ns = {{}}
source = open({str(CHAT_TEMPLATES)!r}).read()
source = open({str(CHAT_TEMPLATES)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .model_mappings import', 'from model_mappings import')
source = source.replace('from .iterable import', 'from iterable import')
@ -402,7 +402,7 @@ class TestFormatConversionNoTorchVenv:
sys.modules['utils.hardware'] = hardware_mod
# Read and exec format_conversion.py
source = open({str(FORMAT_CONVERSION)!r}).read()
source = open({str(FORMAT_CONVERSION)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .iterable import', 'from iterable import')
ns = {{'__name__': '__test__'}}
@ -463,7 +463,7 @@ class TestFormatConversionNoTorchVenv:
sys.modules['utils'] = utils_mod
sys.modules['utils.hardware'] = hardware_mod
source = open({str(FORMAT_CONVERSION)!r}).read()
source = open({str(FORMAT_CONVERSION)!r}, encoding = "utf-8").read()
source = source.replace('from .format_detection import', 'from format_detection import')
source = source.replace('from .iterable import', 'from iterable import')
ns = {{'__name__': '__test__'}}
@ -517,7 +517,7 @@ class TestNegativeControls:
loggers = types.ModuleType('loggers')
loggers.get_logger = lambda n: None
sys.modules['loggers'] = loggers
exec(open({temp_file!r}).read())
exec(open({temp_file!r}, encoding = "utf-8").read())
""")
result = subprocess.run(
[no_torch_venv, "-c", code],

View file

@ -88,11 +88,21 @@ class TestStructuralTorchConstraint:
"""$TORCH_CONSTRAINT must appear in a uv pip install line."""
assert '"$TORCH_CONSTRAINT"' in self._sh
def test_hardcoded_torch_constraint_only_once(self):
"""The hard-coded torch>=2.4,<2.11.0 string should appear exactly once
in install.sh (the default assignment), not in pip install lines."""
count = self._sh.count('"torch>=2.4,<2.11.0"')
assert count == 1, f"Expected 1, found {count}"
def test_hardcoded_torch_constraint_only_on_assignments(self):
"""The hard-coded torch>=2.4,<2.11.0 string must only appear on
TORCH_CONSTRAINT= assignment lines, never on a pip/uv install line
(those must reference $TORCH_CONSTRAINT). Two assignments are expected:
the default, and the gfx906 (MI50) reroute that restores the default
<2.11 window after the rocm7.2 floor bump raised it to 2.11."""
hits = [ln for ln in self._sh.splitlines() if '"torch>=2.4,<2.11.0"' in ln]
assert hits, "default constraint literal missing from install.sh"
for ln in hits:
assert (
"TORCH_CONSTRAINT=" in ln
), f"torch>=2.4,<2.11.0 hardcoded off a TORCH_CONSTRAINT= assignment: {ln.strip()!r}"
assert (
"pip install" not in ln
), f"torch>=2.4,<2.11.0 hardcoded on a pip install line: {ln.strip()!r}"
def test_tightening_guarded_by_skip_torch(self):
"""The block must check SKIP_TORCH=false."""

View file

@ -29,7 +29,7 @@ RL_PY = Path(__file__).resolve().parents[2] / "unsloth" / "models" / "rl.py"
def _extract_mixed_precision_code() -> str:
lines = RL_PY.read_text().split("\n")
lines = RL_PY.read_text(encoding = "utf-8").split("\n")
try:
start = next(i for i, l in enumerate(lines) if "mixed_precision = (" in l)
except StopIteration:

View file

@ -37,7 +37,7 @@ def test_vlm_lora_regex_respects_language_only_with_explicit_targets():
def test_fast_vision_model_wraps_explicit_targets_when_layer_filters_are_used():
source = Path("unsloth/models/vision.py").read_text()
source = Path("unsloth/models/vision.py").read_text(encoding = "utf-8")
assert "target_modules = get_peft_regex(" in source
assert "target_modules = list(target_modules)" in source