unsloth/tests/python/test_install_python_stack.py
oobabooga 90644db9e8
Studio: repair duplicate package metadata during updates (#8515)
* Studio: repair duplicate package metadata during updates

* Studio: clarify duplicate metadata recovery

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

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

* Studio: preserve metadata repair across install paths

* Studio: complete duplicate metadata repair

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

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

* Studio: harden duplicate metadata repair

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

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

* Studio: reject unreadable package metadata

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

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

* Studio: simplify metadata conflict handling

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

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

* Studio: protect malformed metadata repair on Windows

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

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

* Studio: verify editable foreign environments

* Studio: reject versionless foreign metadata

* Studio: repair malformed package metadata

* Studio: do not read one site-packages twice on a lib64 build

purelib hardcodes lib while platlib follows sys.platlibdir, and venv creates
lib64 as a symlink to lib. On Fedora and SuSE the two schemes are therefore two
names for one directory, and deduplicating the scan roots by string kept both.

installed_versions() then returned every record twice, so metadata_conflict()
was true for every installed package in a perfectly healthy environment: update
would exit 1 telling the user to recreate the venv, and the repair could never
converge because the duplication was an illusion.

Deduplicate on the real path instead.

* Studio: apply the same scan rules to the CLI's own metadata checks

Two changes to _studio_deps, both keeping it consistent with install_manifest:

_scan_paths and _venv_site_packages deduplicate their site-packages roots by
real path, so a lib64 build does not report every installed package as
duplicated, locally or when inspecting a foreign managed venv.

installed_metadata_conflicts grouped on METADATA's Name and dropped records
without one, so a nameless or non-UTF-8 record was invisible to it while
installed_versions() and _distributions_in() both called the same directory a
conflict. It now applies the dist-info filename fallback the manifest already
uses. Such a record is marked unreadable rather than trusted, so
damaged_installed_files keeps skipping it: pip cannot parse it either.

* Studio: fetch the replacement before removing any metadata record

The uninstall loop removes every record it finds, and the reinstall went
through pip_install, which routes failure into run() and exits the process. So
a failure between the two left the venv with no unsloth at all, took the entry
point with it, and never reached the function's own return False.

An unreachable index was one way in; --package with a name that is not on an
index was certain to hit it, since such a package can never be reinstalled by
bare name.

Stage the replacement with pip download --no-deps first, install from that
directory, and report a failed uninstall or install instead of exiting, so the
caller's return 1 runs and the existing install is left alone when the
replacement cannot be obtained.

* Studio: probe for duplicate metadata in install.sh too

install.ps1 and both setup scripts were moved onto installed_version_probe, but
install.sh still reported the installed version through
importlib.metadata.version(), which answers from whichever record the finder
yields first. The same duplicated venv was therefore reported as a conflict on
Windows and as an ordinary version on Linux and macOS.

Both installers also fall back to the plain version lookup when
studio.install_manifest cannot be imported, which is the case when --package
installs something that does not ship studio/: that used to print the version
and would otherwise have started warning that it could not be determined.

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

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

* Studio: make a failed metadata repair non-destructive in both directions

Two gaps in the staging I added, both reproduced.

An unreadable record has to be out of the tree before pip runs, since a
non-UTF-8 METADATA makes pip list, show and uninstall raise for the whole
environment. It was deleted outright, so a package whose ONLY record was
unreadable lost it and was left with files and no install, while the message
said the existing install had been left in place. It is now moved to a
quarantine directory and put back on any outcome short of a completed repair.

pip download leaves an sdist when the source has no compatible wheel, and the
install that follows runs --no-index, so its isolated build could not fetch
setuptools and the package stayed uninstalled. Stage with pip wheel instead,
which builds while the index is still reachable, and require a wheel to be
present before treating the package as staged.

* Studio: apply the repo's kwarg-spacing formatter to the metadata repair changes

* Studio: stage overlay sources too, and put the payload back on a partial uninstall

Three gaps, each reproduced.

--local pulls unsloth-zoo from git, so an overlay is a network fetch just as
much as an index install is, yet the overlay path skipped staging entirely. An
unreachable GitHub therefore left unsloth-zoo uninstalled after the loop had
already removed every record. Stage whichever source will be installed, and let
a failed overlay fall back to the staged artifact, which was built from that
same source so it never substitutes a release.

The uninstall loop returned as soon as one uninstall failed, even though an
earlier successful one had already deleted the package tree, leaving a
surviving dist-info that claimed an installed core package whose files were
gone. It now reinstalls from the staged replacement first.

installed_metadata_conflicts treated a record with a name but no version as
readable, so a single such record was silently trusted while
install_manifest.metadata_conflict called the same directory inconsistent.
Readability now requires both, and the message distinguishes an unreadable
record from a duplicated one.

* Studio: build the foreign venv fixture at the platform's interpreter path

The cross-venv tests write bin/python, which _venv_site_packages only looks at
on POSIX. On Windows the probe has nothing to run, so the fixture falls through
to the glob fallback and the resolution under test never happens: both new
cases failed there while passing on Linux and macOS.

Found by running these files on a windows-latest runner. The repo's Windows
matrix covers three parity files only, so nothing else would have caught it.

* Repair duplicate core metadata again before writing the manifest

The repair pass runs before the core packages are installed, so an
upgrade that itself leaves a superseded .dist-info behind survived it.
write_manifest then recorded a null version and the installer exited
successfully while every later check rejected the environment.

Run the same repair a second time immediately before write_manifest. It
is a no-op when nothing is ambiguous.

* Keep the metadata repair working under uv index and hash policies

Three ways a hardened or privately mirrored machine could defeat the
duplicate-metadata repair:

- pip wheel obeys require-hashes exactly as pip install does, so staging
  a replacement was refused before anything was built and the repair
  aborted on the conflict it exists to remove. Confirmed on pip 26.2.
  _relaxed_pip_policy_env now covers wheel alongside install and download.

- The staged wheel was reinstalled through uv when uv is the package
  manager, and UV_REQUIRE_HASHES rejects the unpinned name after the
  uninstall loop has removed every record, leaving the package gone.
  Both staged reinstalls force pip; the wheel is already built.

- uv has no wheel subcommand, so staging runs pip, which reads none of
  UV_DEFAULT_INDEX, UV_INDEX, UV_INDEX_URL, UV_EXTRA_INDEX_URL or
  UV_FIND_LINKS. A private build could be uninstalled and replaced by a
  public PyPI wheel. Those are now translated into the pip equivalents,
  and only where pip has no setting of its own.

* Keep uv index priority and upload cutoff when staging a repair wheel

Staging runs pip because uv has no wheel subcommand, and the previous
commit handed uv's indexes across as PIP_INDEX_URL plus
PIP_EXTRA_INDEX_URL. That restores the reach but not the semantics. uv's
default index-strategy is first-index: it stops at the first index
carrying the package, which is what stops a public release shadowing a
private one. pip pools its indexes and takes the highest version, so a
newer public wheel could replace a private build.

Offer each index alone instead, in uv's own priority order, and take the
first that can build the wheel. An inherited extra index is cleared for
those attempts so the candidates stay separated.

UV_EXCLUDE_NEWER was ignored the same way. pip's --uploaded-prior-to is
the same upload-time filter and takes the same date spellings, so the
cutoff is passed through. It only exists from pip 25.3; on an older pip
staging refuses rather than install a wheel the cutoff forbids, which
leaves the existing installation intact.

* Only advance past an index that confirmed the package is absent

Staging offers each uv index alone, in uv's priority order. The loop
treated every failure as absence, so a private index that was merely
unreachable or refused the credentials advanced to the public fallback,
which is the dependency confusion first-index exists to prevent.

pip cannot be asked directly: measured on pip 26.2, a refused connection
and an unresolvable host both print the same two no-match ERROR lines a
genuine absence does, above a WARNING about retrying after a broken
connection, and never the Could not fetch URL string. So a no-match is
only believed when no transport, authentication or TLS marker appears
beside it. Anything else stops the loop with the install still intact.

Also honour UV_INDEX_STRATEGY: unsafe-best-match really does pool every
index and take the best version, which is pip's own default, so those
staging attempts are pooled too. first-index and unsafe-first-match both
exhaust one index before the next, which is what the loop already does.

* Ask uv which release and index to stage instead of reconstructing them

Staging must run pip, because uv has no wheel subcommand. Reading uv's
index configuration out of the environment and translating it cannot be
made correct: uv also discovers uv.toml, pyproject [tool.uv] and a user
config, honours UV_CONFIG_FILE, applies an implicit PyPI default, and
resolves under an index-strategy pip has no equivalent for. A private
index configured any of those ways was invisible, so the repair could
uninstall a private build and reinstall the public package.

Ask uv instead. uv pip compile --emit-index-annotation reports the exact
index each package resolved from, under uv's own discovery, priority,
strategy and upload cutoff, and pip is then pointed at that one index
with that one version, for this interpreter. An unreachable
higher-priority index fails the compile outright, which is the behaviour
first-index exists to give, so the pip output markers that approximated
it are gone.

UV_OFFLINE forbids network access and pip has no offline mode, so the
repair refuses rather than reaching the network. Plain pip is unchanged:
it already reads its own configuration, so there is nothing to ask.

* Stage a direct reference as written and replace pip's candidate sources

Two gaps in the uv-resolved staging path.

The overlay paths hand staging a git URL or a local checkout rather than
a bare name. Such a requirement is its own provenance, since no index
chose it, and uv appends the resolved commit to what it emits, so the
name comparison could never match and every local duplicate unsloth-zoo
repair aborted before it started. A direct reference is now staged as
written, without asking uv.

Replaying uv's answer also has to replace pip's candidate sources rather
than add to them. An inherited PIP_NO_INDEX blocked the index uv picked,
and an inherited extra index or find-links directory could satisfy the
same version from a source uv never looked at, which is the provenance
swap this path exists to stop. pip.conf can carry the same three
settings, so it is dropped for that one command exactly as the
pinned-index branch already does.

* Keep pip's transport config and replay uv's artifact policy when staging

Dropping pip.conf to remove its candidate sources took proxy, cert,
client-cert and trusted-host with it, and those are how a private index
is reached at all, so uv could resolve and pip would then fail to fetch,
leaving the repair blocked. The environment overrides cannot do this
alone: measured on pip 26.2, an empty PIP_EXTRA_INDEX_URL does NOT
suppress an extra-index-url set in pip.conf, and pip contacts that index
exactly as it does with the variable unset. So pip's own configuration is
asked for with pip config list and written back minus the four source
keys, which leaves the transport settings in force.

A no-binary or only-binary rule was also ignored, so the repair could
download a wheel under a no-binary rule or build an sdist under an
only-binary one. --emit-build-options carries the uv.toml form through.
Measured on uv 0.10.7, it does not surface the environment-variable
spelling, so UV_NO_BINARY and UV_ONLY_BINARY are translated by hand, and
only where pip has no setting of its own.

* Keep index credentials and let a local checkout stage while offline

uv emits every configured index with its credentials, but strips
userinfo from the annotation that says which one answered. Taking the
annotation at face value handed pip an unauthenticated URL for a private
index, which answers 401 and aborts the repair, and reading only
--index-url named the wrong index entirely when the credentialed one was
configured as an extra. The annotation is now matched back to the
emitted URL that carries the credentials, preferring the credentialed
form when one index is emitted both ways.

The offline refusal also ran before the direct-reference branch, so
--local could not repair a duplicate unsloth record even though its
replacement is a checkout on disk that needs no network. It now applies
only to sources that are not already local. A git reference is still a
network fetch and is still refused.

* Remove the old payload when every metadata record is unreadable

Quarantining the only record left pip nothing to uninstall, so the staged
wheel was laid over the existing tree and any module the new release
dropped stayed on disk and importable while the repair reported success.

Give pip a parseable METADATA beside the intact RECORD instead, so it
removes exactly the files that record lists. Confirmed against a real
venv: with the METADATA corrupted pip show raises UnicodeDecodeError for
the whole environment, and after the rewrite pip uninstalls the package
and its entire payload. Without a usable RECORD this fails closed and
asks for the environment to be recreated, since nothing then knows which
files belong to the package.

A find-links origin also no longer displaces the index. uv annotates a
flat source with a file:// URL, which belongs in PIP_FIND_LINKS, already
set from the emitted find-links lines; an sdist taken from a flat
directory still needs the real index for its build backend.

* Build a local checkout without the network when uv is offline

The offline exemption for a local checkout let staging through, but pip
builds it in an isolated environment and fetches the build backend for
that, which UV_OFFLINE does not reach. Measured: an isolated build of a
local project with no index reachable fails at installing build
dependencies, and this repository pins setuptools and setuptools-scm
exactly, so they would be fetched unless already cached. Either way the
no-network policy was broken or the repair failed for a reason the user
could not see.

Offline local staging now builds against the interpreter's own backend
and forbids the index outright, so no-network means no network. Giving up
isolation is how the pinned build requirements stop being honoured, so it
happens only in that case; every other staging keeps it. If the backend
is not importable the build fails and the installation is left intact.

* Pin the staged artifact by hash and carry uv's no-index policy

Suppressing pip's other candidate sources turned out not to be
achievable. Measured: with PIP_CONFIG_FILE pointed at a sanitised copy,
a venv's own pip.conf is still read and its extra-index-url is still
contacted, and --isolated does not suppress it either. So pip may always
consult a source uv never considered.

Ask uv for hashes instead and let pip enforce them. Whatever source pip
reaches, the artifact has to be the one uv resolved, which is a stronger
guarantee than removing sources and does not depend on suppressing any
configuration. Measured: pip verifies the hashes even with
PIP_REQUIRE_HASHES=0, and rejects an artifact that does not match. They
are only accepted from a requirements file, written into the staging
directory so it is removed with it.

A flat source resolved with no index in play is also what a configured
no-index looks like on the way out: uv emits the find-links entry and no
index line. PIP_NO_INDEX is now carried in that case rather than
cleared, which had handed pip back the default PyPI.

* Apply every usable RECORD and commit each package as it is repaired

Quarantining an unreadable record drops its RECORD on the floor. Where
one sat beside a readable duplicate, the uninstall loop then removed only
what the readable record claimed, so a module existing solely in the
older release stayed on disk and importable while the repair reported
success. Every unreadable record that has a usable RECORD is now made
parseable so pip uninstalls it normally; only what cannot be rewritten is
moved aside, and if that leaves nothing to uninstall the repair fails
closed as before.

The quarantine was also shared across both core packages. If the first
was reinstalled and the second then failed, the rollback restored the
first package's stale record on top of the install that had already
replaced it, reintroducing the conflict and leaving an old RECORD
describing a payload that was gone. Each package now has its own, and it
is discarded as soon as that package is back in place, so rollback only
ever touches the package being repaired.

* Back up rewritten metadata and accept a direct-reference pin from uv

The rewrite has to happen before staging, and staging can still fail.
Overwriting the original METADATA in place left no way back, and what
remained parsed, so the next run would see one readable record, decide
nothing was wrong, and never attempt the payload repair still owed. The
quarantine now keeps a copy of every file it rewrites and puts it back on
any unsuccessful exit, byte for byte, so the conflict is still detected.
A record whose backup fails is quarantined instead of rewritten.

uv also emits a PEP 508 direct reference rather than an == pin when an
override redirects a package to a path, repository or URL. The whole line
was being compared as the name, so the requirement stayed empty and every
repair under that policy aborted. The name is now parsed from either
spelling while the reference itself is staged as written.

* Drop an import left unused by a replaced test

The repo lint blocks on an import the PR adds but does not use. shutil
was needed by a staging test that a later round replaced.

* Pin the scan boundary so a record outside the venv cannot fail it

_installed_version answered from all of sys.path before this branch and now
scans purelib/platlib only. Simulated against a real pip --user install: the
old lookup reports the version, the new one reports nothing. Unreachable in
production, since every caller runs against the managed venv and Studio never
creates one with system site-packages, but nothing pinned the intent.

* Cover the two ways a duplicate record actually appears

pip renames the outgoing distribution to a ~ prefixed sibling during an
upgrade and a kill mid-operation keeps both, which is the documented
real-world source of this state and had no test. The opposite case had none
either: a setuptools editable install resolves to a dist-info in
site-packages plus an egg-info in the checkout, and scanning purelib and
platlib rather than all of sys.path is what stops that reading as a
conflict.

* Tighten four comment blocks without dropping any of their reasoning

* Make an unusable METADATA repairable whether it is corrupt or absent

invalid_metadata_paths returns Path, so _rewrite_minimal_metadata raised
AttributeError on rstrip for every record whose METADATA was present but
unparseable, which is the case the rewrite exists to handle. The surrounding
tests passed str and hid it.

An absent METADATA took a second route to the same end: back_up reported
failure, the rewrite was skipped and the record was quarantined instead, so
the uninstall loop removed only what the readable record claimed and a module
shipped solely by the older release stayed on disk and importable while the
repair reported success. An absent file is now nothing to back up rather than
a failure, and restore removes the synthetic METADATA instead of reinstating
one that never existed.

* Carry uv's keyring provider into the staging pip command

The staging plan already replays uv's chosen index and its userinfo, but an
index authenticated through the keyring CLI reached pip as a bare URL, so
pip could not fetch what uv had just resolved and every repair on a private
index aborted. Verified against the installed tools: uv 0.10.7 exposes
UV_KEYRING_PROVIDER with disabled and subprocess, and pip 26.2.1 accepts both
as PIP_KEYRING_PROVIDER, so the existing artifact-policy translation covers
it unchanged. A uv.toml keyring-provider is not emitted and stays out of
reach, same as the artifact policy.

* Move pip's abandoned backup aside so the uninstall loop can converge

An interrupted pip upgrade leaves the outgoing distribution renamed to a ~
prefixed sibling. Its METADATA still names the project, so installed_versions
counts it as a duplicate, but pip calls the directory an invalid distribution
and skips it, so uninstalling by package name can never consume it. Measured
in a real venv: pip logged Ignoring invalid distribution ~impkg, the loop hit
remaining >= record_count, and the repair returned False with both records
still present, which would abort every future update on the commonest real
cause of this state.

The backup is now found by directory name and quarantined before the loop,
so a failure to stage still restores it. Reported by review.

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

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

* Fail closed on an unrecorded stale record even beside a readable one

_rewrite_minimal_metadata already refuses a record with no RECORD, because
nothing then knows which files that release owned. The repair only honoured
that when no other record survived. With one surviving, the count stayed
nonzero, pip uninstalled just the readable record, and the quarantine was
discarded on success, so whatever the older release owned alone stayed
importable and the directory that was the evidence was deleted for good.

Measured before the change: repair returned True, the stale module was still
importable, and the stale dist-info was gone. Now the repair stops with the
directory untouched, so a later run can still see the conflict.

Four tests built their malformed record without a RECORD and asserted the
repair continued, which is the behaviour above. They use an unversioned
directory name instead, so the rewrite still fails and the quarantine path
they exist to cover is unchanged. Reported by review.

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

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

* Refuse the repair for any record that cannot be made pip-uninstallable

The previous commit only covered records with no RECORD. Any unrewritable
record leaks the same way: quarantining it hides it, pip removes just the
readable records, the quarantine is discarded once the reinstall succeeds,
and whatever that release owned alone stays importable while the repair
reports success and deletes the directory that was the evidence.

The reachable route is a METADATA that exists but cannot be read, as an
elevated install leaves root-owned. Measured in a real venv with the file
unreadable: repair returned True, the stale module was still importable and
its dist-info was gone. It now stops with the tree as found. An unreadable
METADATA that can be rewritten still repairs, as does an ordinary duplicate.

Quarantine-and-proceed had no remaining purpose once nothing runs after an
unusable record, so it is gone and its three tests collapse into one that
pins the invariant. Quarantine itself is still used for pip's ~ leftover,
which is what the restore-on-staging-failure test now covers.

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

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

* Keep the rollback's own metadata when the quarantine unwinds

When the rewritten record has already been uninstalled and a later uninstall
fails, _restore_from_staged reinstalls the package before the finally block
runs quarantine.restore(). If the staged wheel recreates the same dist-info
path, restore then either overwrote the wheel's valid METADATA with the
original corrupt bytes or, where the original was absent, deleted a record
pip had just written, leaving the core package malformed after a recovery
whose whole purpose was to make it whole.

Reproduced as a unit: the repair returned False and reading the resulting
METADATA raised UnicodeDecodeError.

A successful staged reinstall now drops the backed-up copies, since the
wheel's metadata is authoritative. The moved entries are kept, because a
record pip cannot consume still has to go back exactly as found. Reported by
review.

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

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

* Treat a sole pip backup as a metadata conflict for PR #8515

* Mark a foreign venv's sole pip backup as a conflict for PR #8515

* Tighten the docstrings this PR adds without dropping their reasoning

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Daniel Han <danielhanchen@gmail.com>
Co-authored-by: danielhanchen <unslothshared@gmail.com>
2026-08-22 22:15:05 -07:00

2245 lines
106 KiB
Python

"""Tests for install_python_stack._build_uv_cmd torch-backend handling."""
from __future__ import annotations
import ast
import contextlib
import importlib
import inspect
import io
import os
import re
import shutil
import sys
import types
from pathlib import Path
from unittest import mock
import pytest
STUDIO_DIR = Path(__file__).resolve().parents[2] / "studio"
sys.path.insert(0, str(STUDIO_DIR))
import install_python_stack as ips
class TestBuildUvCmdTorchBackend:
"""Verify _build_uv_cmd only adds --torch-backend when UV_TORCH_BACKEND is set."""
def _call(self, args: tuple[str, ...] = ()) -> list[str]:
return ips._build_uv_cmd(args)
def test_default_no_torch_backend(self):
"""Without UV_TORCH_BACKEND env var, no --torch-backend flag."""
env = os.environ.copy()
env.pop("UV_TORCH_BACKEND", None)
with mock.patch.dict(os.environ, env, clear = True):
cmd = self._call(("somepackage",))
assert not any(
a.startswith("--torch-backend") for a in cmd
), f"--torch-backend should not appear by default, got: {cmd}"
def test_uv_torch_backend_auto(self):
"""UV_TORCH_BACKEND=auto adds --torch-backend=auto."""
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": "auto"}):
cmd = self._call(("somepackage",))
assert "--torch-backend=auto" in cmd
def test_uv_torch_backend_cpu(self):
"""UV_TORCH_BACKEND=cpu adds --torch-backend=cpu."""
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": "cpu"}):
cmd = self._call(("somepackage",))
assert "--torch-backend=cpu" in cmd
def test_uv_torch_backend_empty(self):
"""UV_TORCH_BACKEND="" (empty string) should NOT add --torch-backend."""
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": ""}):
cmd = self._call(("somepackage",))
assert not any(
a.startswith("--torch-backend") for a in cmd
), f"Empty UV_TORCH_BACKEND should not add flag, got: {cmd}"
def test_uv_torch_backend_skipped_for_pinned_index(self):
"""A pinned-index command must NOT get --torch-backend: uv's torch backend
redirects torch resolution to its own per-backend index even when
--index-url is given (verified: cu128 pin + backend cpu installs
torch+cpu), defeating the pin."""
for pin_flag in ("--index-url", "--default-index"):
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": "cpu"}):
cmd = self._call(("torch", pin_flag, "https://download.pytorch.org/whl/cu128"))
assert not any(
a.startswith("--torch-backend") for a in cmd
), f"{pin_flag} command must not carry --torch-backend, got: {cmd}"
def test_uv_torch_backend_kept_for_unpinned(self):
"""Non-pinned commands still honour UV_TORCH_BACKEND."""
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": "cpu"}):
cmd = self._call(("somepackage",))
assert "--torch-backend=cpu" in cmd
class TestUvSafePath:
"""_uv_safe_path hands uv a space-free `-c`/`-r` path (issue #6503)."""
def test_passthrough_when_no_space(self):
"""A path without a space is returned unchanged on every platform."""
p = "/tmp/plain/constraints.txt"
assert ips._uv_safe_path(p) == p
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_posix_space_path_preserves_relative_requirements(self, tmp_path):
src = tmp_path / "Open Source" / "constraints.txt"
src.parent.mkdir(parents = True)
src.write_text("-r child.txt\n")
(src.parent / "child.txt").write_text("torch>=2.6\n")
out = ips._uv_safe_path(str(src))
assert " " not in out, f"uv-safe path still has a space: {out!r}"
assert out != str(src)
assert Path(out).read_text() == "-r child.txt\n"
assert (Path(out).parent / "child.txt").read_text() == "torch>=2.6\n"
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_posix_missing_file_falls_back_to_original(self):
"""No file to copy -> return the original path rather than raise."""
p = "/nonexistent dir/constraints.txt"
assert ips._uv_safe_path(p) == p
class TestUvSafePathHardening:
"""Edge cases for uv_safe_path + the UV_OVERRIDE channel (issue #6503)."""
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_tmpdir_with_space_falls_back(self, tmp_path, monkeypatch):
"""A space in the temp root itself -> fall back to the original path."""
from backend.utils import uv_path_safety as uvps
spaced = tmp_path / "tmp dir with space"
spaced.mkdir()
monkeypatch.setattr(uvps.tempfile, "mkdtemp", lambda *a, **k: str(spaced))
src = tmp_path / "Open Source" / "constraints.txt"
src.parent.mkdir(parents = True)
src.write_text("idna\n")
assert uvps.uv_safe_path(str(src)) == str(src)
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_alias_failure_falls_back_to_a_copy(self, tmp_path, monkeypatch):
"""A symlink failure must still hand uv a space-free path, and not orphan the dir."""
from backend.utils import uv_path_safety as uvps
src = tmp_path / "Open Source" / "constraints.txt"
src.parent.mkdir(parents = True)
src.write_text("idna\n")
def boom(*a, **k):
raise OSError("boom")
monkeypatch.setattr(uvps.os, "symlink", boom)
out = uvps.uv_safe_path(str(src))
assert " " not in out
assert Path(out).read_text() == "idna\n"
assert str(Path(out).parent) in uvps._UV_SAFE_PATH_TMPDIRS
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_cleanup_removes_and_clears_registry(self, tmp_path):
"""The atexit-registered cleanup removes the copies and empties the list."""
from backend.utils import uv_path_safety as uvps
src = tmp_path / "Open Source" / "constraints.txt"
src.parent.mkdir(parents = True)
src.write_text("idna\n")
out = uvps.uv_safe_path(str(src))
tmp_dir = Path(out).parents[1]
assert tmp_dir.is_dir() and str(tmp_dir) in uvps._UV_SAFE_PATH_TMPDIRS
uvps._cleanup_uv_safe_path_tmpdirs()
assert not tmp_dir.exists()
assert uvps._UV_SAFE_PATH_TMPDIRS == []
@pytest.mark.skipif(ips.IS_WINDOWS, reason = "POSIX temp-copy fallback")
def test_uv_override_value_is_space_safe(self, tmp_path):
"""The value stored for UV_OVERRIDE must be space-free."""
from backend.utils import uv_path_safety as uvps
overrides = tmp_path / "Open Source" / "overrides-darwin-arm64.txt"
overrides.parent.mkdir(parents = True)
overrides.write_text("transformers>=4.57.6\n")
value = uvps.uv_safe_path(overrides)
assert " " not in value
assert Path(value).read_text() == "transformers>=4.57.6\n"
class TestPinnedIndexClearsUvEnv:
"""A pinned torch install (--index-url / --default-index) must neutralise an
inherited UV_INDEX / UV_EXTRA_INDEX_URL so the pinned wheel index wins.
uv treats the default index (--index-url / --default-index) as LOWEST priority,
so an inherited UV_INDEX / UV_EXTRA_INDEX_URL (a corporate/CPU mirror) would be
searched first and, under uv's default first-index strategy, resolve torch from
the wrong mirror -- after which the marker records a wheel index that was never
used. install.sh (#6898), install.ps1 and setup.ps1 already clear these for
pinned installs; install_python_stack must match (parity across all installers).
"""
UV_VARS = ("UV_DEFAULT_INDEX", "UV_INDEX_URL", "UV_INDEX", "UV_EXTRA_INDEX_URL")
def test_pinned_index_url_strips_uv_index_vars(self):
cmd = [
"uv",
"pip",
"install",
"--force-reinstall",
"torch",
"torchvision",
"torchaudio",
"--index-url",
"https://download.pytorch.org/whl/cu128",
]
with mock.patch.dict(
os.environ,
{
"UV_INDEX": "https://mirror.corp/simple",
"UV_EXTRA_INDEX_URL": "https://mirror.corp/extra",
"UV_INDEX_URL": "https://mirror.corp/root",
"UV_DEFAULT_INDEX": "https://mirror.corp/default",
},
):
env = ips._install_env_for_cmd(cmd)
assert env is not None, "a --index-url install must run with a scrubbed env"
for var in self.UV_VARS:
assert var not in env, f"{var} must be cleared for a pinned-index install"
def test_pinned_default_index_strips_uv_index_vars(self):
# --default-index must be gated too (matches install.sh / install.ps1).
cmd = ["uv", "pip", "install", "torch", "--default-index", "https://x/cu126"]
with mock.patch.dict(os.environ, {"UV_INDEX": "https://mirror.corp/simple"}):
env = ips._install_env_for_cmd(cmd)
assert env is not None
assert "UV_INDEX" not in env
def test_non_pinned_install_keeps_user_mirror(self):
# A plain install (no --index-url) must NOT scrub the env, so a user's mirror
# still applies to base packages.
cmd = ["uv", "pip", "install", "unsloth", "unsloth-zoo"]
with mock.patch.dict(os.environ, {"UV_INDEX": "https://mirror.corp/simple"}):
env = ips._install_env_for_cmd(cmd)
assert env is None, "non-pinned installs must inherit the caller env unchanged"
def test_scrubbed_env_preserves_other_vars(self):
cmd = ["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
with mock.patch.dict(
os.environ,
{"UV_INDEX": "https://mirror.corp/simple", "PATH_SENTINEL_XYZ": "keepme"},
):
env = ips._install_env_for_cmd(cmd)
assert env is not None
assert env.get("PATH_SENTINEL_XYZ") == "keepme", "only uv index vars are removed"
def test_pinned_cmd_strips_pip_extra_index_url(self):
"""PIP_EXTRA_INDEX_URL is stripped for pinned commands so the pip
fallback cannot satisfy torch from an inherited extra index."""
with mock.patch.dict(os.environ, {"PIP_EXTRA_INDEX_URL": "https://mirror/simple"}):
env = ips._install_env_for_cmd(
["pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None and "PIP_EXTRA_INDEX_URL" not in env
def test_pinned_cmd_strips_uv_torch_backend(self):
"""UV_TORCH_BACKEND is stripped for pinned commands so uv cannot read it
from the environment and reroute torch off the pinned index."""
with mock.patch.dict(os.environ, {"UV_TORCH_BACKEND": "cpu"}):
env = ips._install_env_for_cmd(
["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None and "UV_TORCH_BACKEND" not in env
def test_pinned_cmd_disables_uv_config_discovery(self):
"""A DISCOVERED uv.toml / pyproject [tool.uv] outranks the CLI pin too
(verified with uv 0.10: [pip] torch-backend = "cpu" and a non-default
[[index]] both resolve torch+cpu against an explicit --index-url /
--default-index cu126 pin). Pinned commands must run with UV_NO_CONFIG=1
and without an inherited UV_CONFIG_FILE."""
with mock.patch.dict(os.environ, {"UV_CONFIG_FILE": "/etc/uv/uv.toml"}):
env = ips._install_env_for_cmd(
["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None
assert env.get("UV_NO_CONFIG") == "1"
assert "UV_CONFIG_FILE" not in env
def test_pinned_cmd_disables_pip_config_files(self):
"""The pip FALLBACK honours user/site pip config files (pip config set
global.extra-index-url) even with the PIP_* env vars stripped; pip loads
NO configuration files when PIP_CONFIG_FILE is os.devnull. Harmless for
uv, decisive for the fallback."""
env = ips._install_env_for_cmd(
["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None
assert env.get("PIP_CONFIG_FILE") == os.devnull
def test_non_pinned_cmd_keeps_uv_config_discovery(self):
"""Non-pinned installs inherit the caller env unchanged, so a user's uv
configuration still applies to base packages."""
env = ips._install_env_for_cmd(["uv", "pip", "install", "unsloth"])
assert env is None
class TestSdistOnlyBuildArgs:
"""A hardened user config must not be able to fail the extras step.
#8530: `no-build = true` (uv.toml) or `only-binary = :all:` (pip.conf) makes every
wheel-less requirement in extras.txt unresolvable, so the install died at "unsloth
extras". A PACKAGE-SCOPED --no-binary overrides that for those names only -- verified
against uv 0.10 and pip 26: drop one name and that name is refused again.
"""
def test_emits_no_binary_for_every_sdist_only_package(self):
args = ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)
for name in ips.SDIST_ONLY_PACKAGES:
assert ["--no-binary", name] == args[
args.index(name) - 1 : args.index(name) + 1
], f"{name} must be passed as a package-scoped --no-binary, got: {args}"
assert len(args) == 2 * len(ips.SDIST_ONLY_PACKAGES)
def test_openai_whisper_is_covered(self):
"""The package named in the issue, and the transitive one behind omegaconf."""
assert "openai-whisper" in ips.SDIST_ONLY_PACKAGES
# omegaconf==2.3.1 pins antlr4-python3-runtime below the 4.13.2 wheel, so it
# arrives as a transitive sdist and fails no-build even though extras.txt
# never names it.
assert "antlr4-python3-runtime" in ips.SDIST_ONLY_PACKAGES
def test_flags_survive_translation_to_uv(self):
"""uv is the primary path, so the flags must reach _build_uv_cmd intact."""
cmd = ips._build_uv_cmd(tuple(ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)))
for name in ips.SDIST_ONLY_PACKAGES:
assert name in cmd
assert cmd.count("--no-binary") == len(ips.SDIST_ONLY_PACKAGES)
def test_flags_survive_translation_to_pip(self):
"""And the pip FALLBACK must carry them too, for the uv-less/uv-broken case."""
cmd = ips._build_pip_cmd(tuple(ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)))
for name in ips.SDIST_ONLY_PACKAGES:
assert name in cmd
assert cmd.count("--no-binary") == len(ips.SDIST_ONLY_PACKAGES)
@pytest.mark.parametrize(
"is_macos, version, expected",
[
(True, (3, 14, 0), True),
(True, (3, 13, 12), False),
(False, (3, 14, 0), False),
(False, (3, 13, 12), False),
],
)
def test_mecab_is_exempted_only_where_it_has_no_wheel(self, is_macos, version, expected):
"""extras.txt pins MeCab==0.996.5 on macOS cp314+, which ships only an sdist.
MeCab is a C extension, so an unconditional exemption would force a
compiler-dependent build on every other host -- a worse bug than the one being
fixed. Verified against uv 0.10: 0.996.5 is refused under `no-build = true` for
macOS cp314 and resolves with --no-binary MeCab; 0.996.13 stays a wheel elsewhere.
"""
with (
mock.patch.object(ips, "IS_MACOS", is_macos),
mock.patch.object(sys, "version_info", version),
):
names = ips._extras_sdist_only_packages()
assert ("MeCab" in names) is expected
# The unconditional ones are always present.
assert set(ips.SDIST_ONLY_PACKAGES) <= set(names)
def test_the_diffusers_pin_is_exempted_on_the_archive_path(self):
"""The pin is a source ARCHIVE, and uv's no-build refuses to build one, so the
install still died here after extras.txt was fixed.
Guarded on python >= 3.10 because diffusers-pin.txt resolves a released wheel
below that, which must not be forced through a source build.
"""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
for node in ast.walk(tree):
if not (isinstance(node, ast.Call) and getattr(node.func, "id", None) == "pip_install"):
continue
req = next((k for k in node.keywords if k.arg == "req"), None)
if req is None or "diffusers-pin.txt" not in ast.unparse(req.value):
continue
splat = " ".join(ast.unparse(a.value) for a in node.args if isinstance(a, ast.Starred))
assert (
"_sdist_only_build_args('diffusers')" in splat
), f"the diffusers pin at line {node.lineno} must exempt the source archive"
assert "version_info >= (3, 10)" in splat, (
"the exemption must be guarded so the pre-3.10 wheel is not forced "
f"through a source build (line {node.lineno})"
)
return
pytest.fail("no pip_install(req=.../diffusers-pin.txt) call found")
def test_the_extras_step_actually_passes_them(self):
"""The helper existing is not the fix; the extras call site using it is.
extras.txt is the manifest that carries the wheel-less requirements, and its
pip_install() is fatal, so this is the call that #8530 died on.
"""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
for node in ast.walk(tree):
if not (isinstance(node, ast.Call) and getattr(node.func, "id", None) == "pip_install"):
continue
req = next((k for k in node.keywords if k.arg == "req"), None)
if req is None or "extras.txt" not in ast.unparse(req.value):
continue
starred = [ast.unparse(a.value) for a in node.args if isinstance(a, ast.Starred)]
assert any("_sdist_only_build_args(" in s for s in starred), (
f"the extras.txt install at line {node.lineno} must splat "
"_sdist_only_build_args() or a hardened uv.toml fails it again"
)
assert any("_extras_sdist_only_packages()" in s for s in starred), (
"the extras install must use the platform-aware list so the macOS "
"cp314 MeCab sdist is exempted too"
)
return
pytest.fail("no pip_install(req=.../extras.txt) call found")
def test_matches_the_ci_nobuild_allowlists(self):
"""CI already ratifies exactly these as audited pure-Python sdist builds.
If the two lists drift, either CI fails a legitimate build or we exempt a
package nobody audited, so pin them together.
"""
repo = Path(ips.__file__).resolve().parents[1]
shell = (repo / ".github/scripts/clean-machine-assert.sh").read_text(encoding = "utf-8")
allow = shell[shell.index('_allow="$(printf') :]
allow = allow[: allow.index("\n")]
ps1 = (repo / ".github/scripts/assert-nobuild.ps1").read_text(encoding = "utf-8")
for name in ips.SDIST_ONLY_PACKAGES:
assert name in allow, f"{name} missing from clean-machine-assert.sh nobuild allowlist"
assert f"'{name}'" in ps1, f"{name} missing from assert-nobuild.ps1 allowlist"
class TestHardenedPipConfigRelaxation:
"""`require-hashes = true` in pip.conf killed the pip FALLBACK in #8530.
Every requirements file we ship is pinned but unhashed, so hash-required mode can
never be satisfied. pip applies env vars AFTER config files, so PIP_REQUIRE_HASHES=0
in the child env overrides it while pip.conf's index-url, trusted-host, cert and
proxy stay in force. It has no command-line equivalent, hence the env var.
"""
HOSTILE = {
"PIP_REQUIRE_HASHES": "1",
"PIP_ONLY_BINARY": ":all:",
"UV_NO_BUILD": "1",
"UV_EXCLUDE_NEWER": "2024-01-01T00:00:00Z",
}
def test_uv_commands_are_left_alone(self):
"""uv reads none of the PIP_* vars, and its own no-build is handled by the
package-scoped --no-binary, so a uv command must still inherit the env
unchanged -- the mirror contract at test_non_pinned_install_keeps_user_mirror."""
with mock.patch.dict(os.environ, self.HOSTILE):
assert ips._install_env_for_cmd(["uv", "pip", "install", "-r", "extras.txt"]) is None
def test_non_pinned_pip_install_relaxes_hash_mode(self):
with mock.patch.dict(os.environ, self.HOSTILE):
env = ips._install_env_for_cmd(["python", "-m", "pip", "install", "-r", "extras.txt"])
assert env is not None, "the pip fallback must not inherit require-hashes"
assert env["PIP_REQUIRE_HASHES"] == "0"
def test_non_pinned_pip_keeps_the_user_mirror_and_binary_policy(self):
"""Only hash mode is relaxed. The mirror stays, and so does only-binary --
the wheel-less packages are exempted per-package on the command line instead."""
with mock.patch.dict(
os.environ,
dict(self.HOSTILE, PIP_INDEX_URL = "https://mirror.corp/simple"),
):
env = ips._install_env_for_cmd(["python", "-m", "pip", "install", "x"])
assert env["PIP_INDEX_URL"] == "https://mirror.corp/simple"
assert env["PIP_ONLY_BINARY"] == ":all:"
assert "PIP_CONFIG_FILE" not in env, "a non-pinned install must still read pip.conf"
assert "UV_NO_CONFIG" not in env, "a non-pinned install must still read uv.toml"
def test_non_install_commands_are_untouched(self):
"""run() routes EVERY command through this helper, not just installs."""
with mock.patch.dict(os.environ, self.HOSTILE):
assert ips._install_env_for_cmd(["python", "-m", "pip", "--version"]) is None
assert ips._install_env_for_cmd(["python", "-m", "ensurepip", "--upgrade"]) is None
def test_pinned_cmd_strips_restrictive_policy_env(self):
"""The pinned branch neutralises the config FILES, but an env var outranks a
config file, so a hardened shell could still fail a torch repair the pin was
supposed to make deterministic."""
with mock.patch.dict(os.environ, self.HOSTILE):
env = ips._install_env_for_cmd(
["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None
for name in ("PIP_REQUIRE_HASHES", "PIP_ONLY_BINARY", "UV_NO_BUILD", "UV_EXCLUDE_NEWER"):
assert name not in env, f"{name} must be cleared for a pinned install"
# The pre-existing pinned contract is unchanged.
assert env["UV_NO_CONFIG"] == "1" and env["PIP_CONFIG_FILE"] == os.devnull
def test_the_parent_environment_is_never_mutated(self):
"""The relaxation is a child-env override. Leaking it into os.environ would
weaken the user's policy for their own later pip commands in this session."""
with mock.patch.dict(os.environ, self.HOSTILE):
ips._install_env_for_cmd(["python", "-m", "pip", "install", "x"])
ips._install_env_for_cmd(["uv", "pip", "install", "x", "--index-url", "https://y"])
assert os.environ["PIP_REQUIRE_HASHES"] == "1"
assert os.environ["UV_NO_BUILD"] == "1"
def test_the_pip_fallback_receives_the_relaxation(self):
"""End of the real path: uv fails, pip_install falls back through run(), and
that pip command is the one #8530 died on."""
seen: dict = {}
def _fake_run(label, cmd, *a, **kw):
seen["env"] = ips._install_env_for_cmd(cmd)
seen["cmd"] = cmd
with (
mock.patch.object(ips, "USE_UV", True),
mock.patch.object(ips, "subprocess") as sp,
mock.patch.object(ips, "run", _fake_run),
mock.patch.dict(os.environ, self.HOSTILE),
):
sp.run.return_value = mock.Mock(returncode = 1, stdout = "")
sp.PIPE, sp.STDOUT = -1, -2
ips.pip_install("deps", *ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES))
assert seen["env"]["PIP_REQUIRE_HASHES"] == "0"
for name in ips.SDIST_ONLY_PACKAGES:
assert name in seen["cmd"], "the fallback lost the source-build exemptions"
class TestProgressLineNotes:
"""_progress() leaves the cursor mid-line, so anything printed between two
progress steps must close that line first. Before centralising this, a real
install glued the torchao message onto the bar:
deps [=======-------------] 5/14 dependency overrides torch 2.11...
"""
def _render(
self,
emit,
*,
columns = "100",
verbose = False,
color = False,
) -> str:
buf = io.StringIO()
with (
mock.patch.dict(os.environ, {"COLUMNS": columns}),
mock.patch.object(ips, "VERBOSE", verbose),
# _HAS_COLOR is resolved once at import from the tty; pinning it keeps the
# assertions valid under FORCE_COLOR=1 or `pytest -s` in a terminal.
mock.patch.object(ips, "_HAS_COLOR", color),
mock.patch.object(ips, "_TOTAL", 14),
mock.patch.object(ips, "_STEP", 4),
mock.patch.object(ips, "_PROGRESS_LINE_ACTIVE", False),
contextlib.redirect_stdout(buf),
):
emit()
return buf.getvalue()
def test_note_does_not_glue_onto_the_progress_bar(self):
msg = "torch 2.11.0+cu130 detected -- installing torchao==0.17.0"
out = self._render(lambda: (ips._progress("dependency overrides"), ips._note(msg)))
bar_lines = [ln for ln in out.split("\n") if "5/14" in ln]
assert len(bar_lines) == 1, f"expected one bar line, got {bar_lines!r}"
assert msg not in bar_lines[0], f"note glued onto the bar: {bar_lines[0]!r}"
assert any(ln.strip() == msg for ln in out.split("\n")), out
def test_note_aligns_under_the_step_value_column(self):
out = self._render(lambda: (ips._progress("dependency overrides"), ips._note("hello")))
note_line = next(ln for ln in out.split("\n") if ln.strip() == "hello")
assert len(note_line) - len(note_line.lstrip()) == ips._INDENT + ips._COL
def test_note_without_an_active_bar_prints_on_its_own(self):
out = self._render(lambda: ips._note("standalone"))
assert out == f"{' ' * (ips._INDENT + ips._COL)}standalone\n"
def test_step_still_closes_an_active_bar(self):
"""_step() handed its inline line-break logic to _end_progress_line(); it
must keep breaking out of the bar."""
out = self._render(
lambda: (ips._progress("dependency overrides"), ips._step("deps", "installed"))
)
bar_lines = [ln for ln in out.split("\n") if "5/14" in ln]
assert len(bar_lines) == 1 and "installed" not in bar_lines[0], out
def test_progress_line_state_is_cleared(self):
"""A stale _PROGRESS_LINE_ACTIVE blank-lines the next note instead of
closing a bar that is no longer open."""
def emit():
ips._progress("dependency overrides")
ips._note("first")
assert ips._PROGRESS_LINE_ACTIVE is False
ips._note("second")
out = self._render(emit)
assert "\n\n" not in out, out
def test_uv_fallback_warning_does_not_glue_onto_the_bar(self):
"""A real producer, not _note() directly: pip_install() warns on the uv
fallback while the bar for its own step is still open. This path survived
the first pass of the fix, which only converted ' message' call sites."""
fake = mock.Mock(returncode = 1, stdout = "uv output")
with (
mock.patch.object(ips, "USE_UV", True),
mock.patch.object(ips, "subprocess") as sp,
mock.patch.object(ips, "run") as fallback,
):
sp.run.return_value = fake
sp.PIPE, sp.STDOUT = -1, -2
out = self._render(
lambda: (ips._progress("studio deps"), ips.pip_install("Installing studio deps"))
)
assert fallback.called, "expected the pip fallback to run"
bar_lines = [ln for ln in out.split("\n") if "5/14" in ln]
assert len(bar_lines) == 1, f"expected one bar line, got {bar_lines!r}"
assert "uv failed" not in bar_lines[0], f"warning glued onto the bar: {bar_lines[0]!r}"
def test_no_bare_print_calls(self):
"""The line-close lives in _safe_print(), so a direct print() anywhere in
the module silently reintroduces the glued-line bug."""
src = Path(ips.__file__).read_text(encoding = "utf-8")
tree = ast.parse(src)
allowed = [
(n.lineno, n.end_lineno)
for n in ast.walk(tree)
if isinstance(n, ast.FunctionDef) and n.name == "_safe_print"
]
offenders = [
n.func.lineno
for n in ast.walk(tree)
if isinstance(n, ast.Call)
and isinstance(n.func, ast.Name)
and n.func.id == "print"
and not any(lo <= n.func.lineno <= hi for lo, hi in allowed)
]
assert not offenders, (
f"install_python_stack.py:{offenders} call print() directly; "
"use _safe_print() or _note() so an open progress bar line is closed first"
)
def test_no_direct_stdout_writes(self):
"""Copying _progress()'s sys.stdout.write idiom elsewhere would glue onto
the bar again while still passing test_no_bare_print_calls."""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
allowed = [
(n.lineno, n.end_lineno)
for n in ast.walk(tree)
if isinstance(n, ast.FunctionDef) and n.name in {"_progress", "_end_progress_line"}
]
offenders = [
n.lineno
for n in ast.walk(tree)
if isinstance(n, ast.Call)
and isinstance(n.func, ast.Attribute)
and n.func.attr in {"write", "flush"}
and isinstance(n.func.value, ast.Attribute)
and n.func.value.attr == "stdout"
and not any(lo <= n.lineno <= hi for lo, hi in allowed)
]
assert not offenders, (
f"install_python_stack.py:{offenders} write to sys.stdout directly; "
"only _progress()/_end_progress_line() may, everything else uses _safe_print()"
)
def test_no_message_starts_with_a_newline(self):
"""_safe_print() closes the bar itself now, so a message literal still
opening with \\n emits a second newline and a blank line."""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
def leads_with_newline(node) -> bool:
if isinstance(node, ast.Constant) and isinstance(node.value, str):
return node.value.startswith("\n")
if isinstance(node, ast.JoinedStr) and node.values:
return leads_with_newline(node.values[0])
return False
offenders = [
n.lineno
for n in ast.walk(tree)
if isinstance(n, ast.Call)
and isinstance(n.func, ast.Name)
and n.func.id in {"_safe_print", "_note"}
and n.args
and leads_with_newline(n.args[0])
]
assert not offenders, (
f"install_python_stack.py:{offenders} start a message with a newline; "
"_safe_print() already closes the progress bar line, so this blank-lines the output"
)
def test_note_wraps_at_the_value_column_on_a_narrow_terminal(self):
"""Wrapping is all that separates _note() from _safe_print(), and no other
test makes it wrap: every message fits one line at COLUMNS=100."""
msg = (
"AMD GPU detected but ROCm PyTorch could not be auto-installed. Manual install "
"may be required. See: https://docs.unsloth.ai/get-started/install-and-update/amd"
)
out = self._render(lambda: ips._note(msg), columns = "60")
lines = [ln for ln in out.split("\n") if ln.strip()]
assert len(lines) > 1, f"expected the message to wrap, got {out!r}"
for line in lines:
assert len(line) - len(line.lstrip()) == ips._INDENT + ips._COL, repr(line)
assert " ".join(ln.strip() for ln in lines) == msg
# break_long_words = False keeps the URL clickable rather than splitting it.
assert any("https://docs.unsloth.ai" in ln for ln in lines), out
def test_note_falls_back_to_the_flat_indent_in_verbose_mode(self):
"""Verbose prints no bar and no step line, so the value column would indent
under nothing while neighbouring messages sit at column 3."""
out = self._render(lambda: ips._note("hello"), verbose = True)
assert out == " hello\n", repr(out)
def test_note_still_aligns_when_colour_is_on(self):
"""The layout must survive a colour terminal, where every line carries ANSI
codes that occupy no columns."""
out = self._render(lambda: ips._note("hello"), color = True)
assert "\033[" in out, "expected ANSI codes with _HAS_COLOR on"
plain = re.sub(r"\033\[[0-9;]*m", "", out)
assert plain == f"{' ' * (ips._INDENT + ips._COL)}hello\n", repr(plain)
def test_safe_print_to_stderr_survives_a_closed_stdout(self):
"""_safe_print() touches stdout on every call now, so stderr-bound manifest
errors must not die on an unrelated stdout failure."""
closed = io.StringIO()
closed.close()
err = io.StringIO()
with (
mock.patch.object(ips, "VERBOSE", False),
mock.patch.object(ips, "_PROGRESS_LINE_ACTIVE", True),
mock.patch.object(ips.sys, "stdout", closed),
):
ips._safe_print("error: boom", file = err)
assert err.getvalue() == "error: boom\n"
def test_install_entry_clears_a_stale_progress_line(self):
"""_PROGRESS_LINE_ACTIVE outlives an aborted run, and now every _safe_print()
reads it, so a stale flag newlines the next run."""
src = Path(ips.__file__).read_text(encoding = "utf-8")
fn = next(
n
for n in ast.walk(ast.parse(src))
if isinstance(n, ast.FunctionDef) and n.name == "install_python_stack"
)
assert any(
isinstance(n, ast.Global) and "_PROGRESS_LINE_ACTIVE" in n.names for n in ast.walk(fn)
), "install_python_stack() must declare _PROGRESS_LINE_ACTIVE global"
assert any(
isinstance(n, ast.Assign)
and any(isinstance(t, ast.Name) and t.id == "_PROGRESS_LINE_ACTIVE" for t in n.targets)
for n in ast.walk(fn)
), "install_python_stack() must reset _PROGRESS_LINE_ACTIVE"
class TestBuildPipCmdUpgradeIntent:
"""pip has no --upgrade-package, so uv's flag must be translated, not dropped.
Dropping it made the fallback a no-op on the update path: pip saw the named
distributions as already satisfied, installed nothing, and the update
reported success.
"""
def test_update_path_keeps_the_upgrade_intent(self):
cmd = ips._build_pip_cmd(
("--no-cache-dir", "--upgrade-package", "unsloth", "--upgrade-package", "unsloth-zoo")
)
assert "--upgrade" in cmd
assert "unsloth" in cmd and "unsloth-zoo" in cmd
assert "--upgrade-package" not in cmd, "pip does not understand the uv flag"
def test_torch_is_not_dragged_along(self):
# only-if-needed is pip's current default, but it is the load-bearing
# part: eager would re-resolve the existing torch build.
cmd = ips._build_pip_cmd(("--upgrade-package", "unsloth"))
assert cmd[cmd.index("--upgrade-strategy") + 1] == "only-if-needed"
def test_names_already_present_are_not_duplicated(self):
cmd = ips._build_pip_cmd(("--no-deps", "--upgrade-package", "unsloth", "unsloth"))
assert cmd.count("unsloth") == 1
def test_commands_without_the_flag_are_untouched(self):
cmd = ips._build_pip_cmd(("--no-cache-dir", "somepackage"))
assert cmd == [sys.executable, "-m", "pip", "install", "--no-cache-dir", "somepackage"]
class TestDuplicateCoreMetadataRepair:
def test_an_unrewritable_record_stops_the_repair_before_pip_runs(
self, tmp_path, monkeypatch, capsys
):
"""The invariant that replaced quarantine-and-proceed.
A record that cannot be made readable cannot be uninstalled by pip either.
Moving it aside only hid it: pip removed the readable records, the
quarantine was discarded once the reinstall succeeded, and whatever the
quarantined release owned alone stayed importable while the repair
reported success and deleted the directory that was the evidence.
So nothing may run: no staging, no pip, and the tree is left as found.
A non-UTF-8 METADATA also makes pip raise for the whole environment, so
refusing before pip is what that used to need quarantining for.
"""
malformed = tmp_path / "unsloth-2026.8.12.dist-info"
malformed.mkdir()
(malformed / "METADATA").write_bytes(b"\xff\xfe")
(malformed / "RECORD").write_text("unsloth/gone.py,,\n")
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda _n: ["", "2026.8.15"]
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [malformed])
monkeypatch.setattr(ips.install_manifest, "pip_backup_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
# The rewrite is what normally saves this record; deny it to reach the branch.
monkeypatch.setattr(ips, "_rewrite_minimal_metadata", lambda *a, **k: False)
def refuse(*_a, **_k):
raise AssertionError("nothing may run once a record is unusable")
monkeypatch.setattr(ips, "_stage_replacement", refuse)
monkeypatch.setattr(ips, "_run_ok", refuse)
monkeypatch.setattr(ips, "pip_install_try", refuse)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert "cannot be read or rewritten" in capsys.readouterr().err
assert malformed.is_dir()
assert (malformed / "METADATA").read_bytes() == b"\xff\xfe"
def test_an_unrecorded_stale_record_fails_closed_even_beside_a_good_one(
self, tmp_path, monkeypatch, capsys
):
"""No RECORD means nothing knows which files that release owned, which is
why _rewrite_minimal_metadata fails closed. Waiting for record_count to
reach zero missed the case where another record survives: pip uninstalls
only that one, the quarantine is discarded on success, and whatever the
older release owned alone stays importable while the directory that was
the evidence is deleted for good.
"""
unreadable = tmp_path / "unsloth-2026.8.12.dist-info"
unreadable.mkdir()
(unreadable / "METADATA").write_bytes(b"\xff\xfe") # no RECORD beside it
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda _n: ["", "2026.8.15"]
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [unreadable])
monkeypatch.setattr(ips.install_manifest, "pip_backup_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
def fake_stage(*_args, **_kwargs):
raise AssertionError("nothing may be staged once a record is unusable")
monkeypatch.setattr(ips, "_stage_replacement", fake_stage)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert "cannot be read or rewritten" in capsys.readouterr().err
# The evidence stays on disk so a later run can still see the conflict.
assert unreadable.is_dir()
def test_pips_tilde_backup_is_moved_aside_so_the_loop_can_converge(self, tmp_path, monkeypatch):
"""The commonest real conflict: pip renamed the outgoing distribution to a
`~` sibling and was killed. Its METADATA still says Name: unsloth so it
counts as a duplicate, but `pip uninstall unsloth` logs "Ignoring invalid
distribution" and skips it, so the loop never converges and the repair
fails on every future run. Verified in a real venv before this fix.
"""
backup = tmp_path / "~nsloth-2026.8.12.dist-info"
backup.mkdir()
(backup / "METADATA").write_text(
"Metadata-Version: 2.1\nName: unsloth\nVersion: 2026.8.12\n", encoding = "utf-8"
)
# Two records; one once the backup is aside; none after the uninstall; then
# the reinstalled one for the final convergence probe.
probes = iter((["2026.8.12", "2026.8.15"], ["2026.8.15"], [], ["2026.8.15"]))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(
ips.install_manifest, "pip_backup_metadata_paths", lambda _name: [backup]
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
def record_run(_label, _cmd):
# pip only ever sees a tree it can actually act on.
assert not backup.exists()
return True
monkeypatch.setattr(ips, "_run_ok", record_run)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is True
assert not backup.exists()
def test_a_sole_tilde_backup_is_repaired_by_a_fresh_install(self, tmp_path, monkeypatch):
"""pip killed after the rename but before the replacement landed leaves the
backup alone: one readable version, so a version count sees nothing wrong
while the package is genuinely unimportable. Once the backup is aside there
is no payload left to lay a replacement over, so installing fresh is right
and refusing would abort the installer on a trivially fixable state.
"""
backup = tmp_path / "~nsloth-2026.8.12.dist-info"
backup.mkdir()
(backup / "METADATA").write_text(
"Metadata-Version: 2.1\nName: unsloth\nVersion: 2026.8.12\n", encoding = "utf-8"
)
# One record, none once the backup is aside, then the reinstalled one.
probes = iter((["2026.8.12"], [], ["2026.8.15"]))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(
ips.install_manifest, "pip_backup_metadata_paths", lambda _name: [backup]
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
installs = []
monkeypatch.setattr(
ips, "pip_install_try", lambda label, *a, **k: installs.append(label) or True
)
monkeypatch.setattr(
ips, "_run_ok", lambda *_a: pytest.fail("nothing is left for pip to uninstall")
)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is True
assert len(installs) == 1
assert not backup.exists()
def test_every_duplicate_record_is_uninstalled_before_reinstall(self, monkeypatch):
probes = {
"unsloth": iter(
(
["2026.8.12", "2026.8.15"],
["2026.8.15"],
[],
["2026.8.15"],
)
),
"unsloth-zoo": iter((["2026.8.10"],)),
}
installs = []
invalidations = []
commands = []
monkeypatch.setattr(
ips.install_manifest,
"installed_versions",
lambda name: next(probes[name]),
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: invalidations.append(True))
monkeypatch.setattr(
ips,
"_run_ok",
lambda label, cmd: commands.append((label, cmd)) or True,
)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(
ips,
"pip_install_try",
lambda label, *args, **kwargs: installs.append((label, args, kwargs)) or True,
)
assert ips._repair_duplicate_core_metadata(("unsloth", "unsloth-zoo")) is True
assert [command for _label, command in commands] == [
[sys.executable, "-m", "pip", "uninstall", "-y", "unsloth"],
[sys.executable, "-m", "pip", "uninstall", "-y", "unsloth"],
]
assert len(installs) == 1
assert installs[0][1] == (
"--no-cache-dir",
"--no-deps",
"--force-reinstall",
"--no-index",
"--find-links",
"/staged",
"unsloth",
)
assert len(invalidations) == 3
def test_repair_fails_when_uninstall_does_not_remove_a_record(self, monkeypatch, capsys):
probes = iter(
(
["2026.8.12", "2026.8.15"],
["2026.8.12", "2026.8.15"],
)
)
monkeypatch.setattr(
ips.install_manifest,
"installed_versions",
lambda _name: next(probes),
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
installs = []
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: installs.append((a, k)))
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert installs == []
assert "could not remove every metadata record" in capsys.readouterr().err
@pytest.mark.parametrize(
"duplicate, overlay_args",
[
("unsloth", ("--no-cache-dir", "--no-deps", "-e", "/src/unsloth")),
(
"unsloth-zoo",
(
"--no-cache-dir",
"--no-deps",
"--force-reinstall",
"unsloth-zoo @ git+https://github.com/unslothai/unsloth-zoo",
),
),
],
)
def test_local_repair_restores_only_the_source_it_replaced(
self, monkeypatch, duplicate, overlay_args
):
probes = {
name: iter((["old", "new"], ["new"], [], ["new"]) if name == duplicate else (["new"],))
for name in ("unsloth", "unsloth-zoo")
}
installs = []
monkeypatch.setattr(
ips.install_manifest,
"installed_versions",
lambda name: next(probes[name]),
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(
ips,
"pip_install_try",
lambda label, *args, **kwargs: installs.append((label, args, kwargs)) or True,
)
assert ips._repair_duplicate_core_metadata(
("unsloth", "unsloth-zoo"), local_repo = "/src/unsloth"
)
assert len(installs) == 1
assert installs[0][1] == overlay_args
assert installs[0][2]["constrain"] is False
def test_install_pass_hands_local_provenance_to_duplicate_repair(self):
source = inspect.getsource(ips.install_python_stack)
assert "local_repo=local_repo" in source.replace(" ", "")
def test_local_repair_reinstalls_a_custom_package_from_its_normal_source(self, monkeypatch):
probes = iter((["old", "new"], ["new"], [], ["new"]))
installs = []
monkeypatch.setattr(
ips.install_manifest,
"installed_versions",
lambda _name: next(probes),
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(
ips,
"pip_install_try",
lambda label, *args, **kwargs: installs.append((label, args, kwargs)) or True,
)
assert ips._repair_duplicate_core_metadata(("custom-package",), local_repo = "/src/unsloth")
assert len(installs) == 1
assert installs[0][1] == (
"--no-cache-dir",
"--no-deps",
"--force-reinstall",
"--no-index",
"--find-links",
"/staged",
"custom-package",
)
def test_ci_repair_restores_only_the_candidate_unsloth_checkout(self, monkeypatch):
probes = {
"unsloth": iter((["old", "new"], ["new"], [], ["new"])),
"unsloth-zoo": iter((["new"],)),
}
installs = []
monkeypatch.setattr(
ips.install_manifest,
"installed_versions",
lambda name: next(probes[name]),
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(
ips,
"pip_install_try",
lambda label, *args, **kwargs: installs.append((label, args, kwargs)) or True,
)
assert ips._repair_duplicate_core_metadata(
("unsloth", "unsloth-zoo"), ci_source_overlay = "/src/candidate"
)
assert len(installs) == 1
assert installs[0][1] == ("--no-cache-dir", "--no-deps", "-e", "/src/candidate")
assert installs[0][2]["constrain"] is False
def test_the_repair_runs_again_before_the_manifest_is_written(self):
"""The first pass runs before the core packages are installed, so an
upgrade that leaves a superseded record behind would survive it and
write_manifest would record a null version under a successful exit."""
source = inspect.getsource(ips.install_python_stack)
first = source.index("_repair_duplicate_core_metadata")
second = source.index("_repair_duplicate_core_metadata", first + 1)
manifest = source.index("write_manifest(")
assert first < second < manifest, (
"the duplicate-metadata repair must run again after the core-package "
"install and before the manifest is written"
)
def test_staging_relaxes_pip_hash_enforcement(self):
"""require-hashes applies to pip wheel exactly as it does to pip install
(measured on pip 26.2: an unpinned name is refused before anything is
built), so a hardened machine could never stage a replacement and the
repair would abort on the very conflict it exists to remove."""
env = ips._install_env_for_cmd(
[sys.executable, "-m", "pip", "wheel", "--no-deps", "--wheel-dir", "/staged", "unsloth"]
)
assert env is not None and env.get("PIP_REQUIRE_HASHES") == "0"
def _uv_only(self, monkeypatch):
monkeypatch.setattr(ips, "USE_UV", True)
for var in (
"PIP_INDEX_URL",
"PIP_EXTRA_INDEX_URL",
"PIP_FIND_LINKS",
"UV_INDEX",
"UV_EXTRA_INDEX_URL",
"UV_INDEX_URL",
"UV_DEFAULT_INDEX",
"UV_FIND_LINKS",
"UV_EXCLUDE_NEWER",
"UV_INDEX_STRATEGY",
"UV_NO_BINARY",
"UV_ONLY_BINARY",
"PIP_NO_BINARY",
"PIP_ONLY_BINARY",
"UV_KEYRING_PROVIDER",
"PIP_KEYRING_PROVIDER",
):
monkeypatch.delenv(var, raising = False)
UV_COMPILE_OUT = (
b"# This file was autogenerated by uv via the following command:\n"
b"# uv pip compile --no-deps --emit-index-url -\n"
b"--index-url https://pypi.org/simple\n"
b"--extra-index-url https://mirror.corp/simple\n"
b"--find-links /opt/wheels\n"
b"\n"
b"unsloth-zoo==2026.8.15\n"
b" # from https://mirror.corp/simple\n"
)
def _uv_plan(
self,
monkeypatch,
stdout = None,
returncode = 0,
):
calls = []
def fake_run(cmd, **kwargs):
calls.append((cmd, kwargs))
if cmd[:3] == ["uv", "pip", "compile"]:
return types.SimpleNamespace(
returncode = returncode,
stdout = self.UV_COMPILE_OUT if stdout is None else stdout,
stderr = b"",
)
return types.SimpleNamespace(returncode = 1, stdout = b"")
monkeypatch.setattr(ips.subprocess, "run", fake_run)
return calls
def test_the_replacement_is_the_release_and_index_uv_resolved(self, monkeypatch):
"""Staging must run pip, because uv has no wheel subcommand, and uv's index
configuration cannot be reconstructed from the environment: uv also reads
uv.toml, pyproject [tool.uv], a user config and UV_CONFIG_FILE, applies an
implicit PyPI default, and resolves under an index-strategy pip has no
equivalent for. So uv is asked, and its answer is reproduced verbatim."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
self._uv_plan(monkeypatch)
requirement, overrides, _options = ips._uv_staging_plan("unsloth_zoo")
assert requirement == "unsloth-zoo==2026.8.15"
# The annotation names the index the package actually came from, which is the
# one to reproduce -- not --index-url, which is only uv's default.
assert overrides["PIP_INDEX_URL"] == "https://mirror.corp/simple"
assert overrides["PIP_EXTRA_INDEX_URL"] == ""
assert overrides["PIP_FIND_LINKS"] == "/opt/wheels"
def test_the_plan_asks_uv_about_this_interpreter(self, monkeypatch):
"""Markers and ABI tags come from the interpreter being repaired, not from
whichever one uv would discover on its own."""
self._uv_only(monkeypatch)
calls = self._uv_plan(monkeypatch)
ips._uv_staging_plan("unsloth-zoo")
cmd = calls[0][0]
assert cmd[cmd.index("--python") + 1] == sys.executable
assert calls[0][1]["input"] == b"unsloth-zoo"
def test_a_falling_index_aborts_the_repair_rather_than_substituting(self, monkeypatch, capsys):
"""uv fails the compile outright when a higher-priority index is unreachable,
which is the behaviour first-index exists to give: a public release must not
stand in for a private one just because the private mirror was down."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
self._uv_plan(monkeypatch, returncode = 1)
assert ips._stage_replacement("unsloth-zoo") is None
assert "cannot be preserved" in capsys.readouterr().err
def test_offline_uv_leaves_the_install_alone(self, monkeypatch, capsys):
"""UV_OFFLINE forbids network access and pip has no offline mode, so the
repair would have to break the policy to proceed."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
monkeypatch.setenv("UV_OFFLINE", "1")
def fake_run(*args, **kwargs):
raise AssertionError("nothing may run while uv is offline")
monkeypatch.setattr(ips.subprocess, "run", fake_run)
assert ips._stage_replacement("unsloth-zoo") is None
assert "UV_OFFLINE" in capsys.readouterr().err
@pytest.mark.parametrize("value", ("", "0", "false"))
def test_an_unset_or_disabled_offline_flag_is_not_offline(self, monkeypatch, value):
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_OFFLINE", value)
assert ips._uv_is_offline() is False
def test_the_plan_is_skipped_when_uv_is_not_the_package_manager(self, monkeypatch):
"""Plain pip already reads its own configuration, so there is nothing to
translate and no uv to ask."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", False)
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement("unsloth-zoo") is None
assert all(cmd[:1] != ["uv"] for cmd, _ in calls)
assert calls[0][0][-1] == "unsloth-zoo"
@pytest.mark.parametrize(
"requirement",
(
"unsloth-zoo @ git+https://github.com/unslothai/unsloth-zoo",
"https://example.invalid/unsloth_zoo-1.0-py3-none-any.whl",
),
)
def test_a_direct_reference_is_staged_as_written(self, monkeypatch, requirement):
"""The overlay paths hand staging a git URL or a checkout, not a bare name.
Such a requirement is its own provenance -- no index chose it -- and uv
appends the resolved commit to what it emits, so asking uv would compare a
bare spec against a pinned one and never match, aborting every local
duplicate-zoo repair before it started."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement(requirement) is None
assert all(cmd[:3] != ["uv", "pip", "compile"] for cmd, _ in calls)
assert calls[0][0][-1] == requirement
def test_a_local_checkout_is_a_direct_reference(self, tmp_path):
assert ips._is_direct_reference(str(tmp_path)) is True
assert ips._is_direct_reference("unsloth-zoo") is False
def test_replaying_uv_replaces_pips_candidate_sources(self, monkeypatch):
"""Replaying uv's answer means replacing pip's sources, not adding to them.
An inherited PIP_NO_INDEX blocks the index uv picked, and an inherited extra
index or find-links directory can satisfy the same version from somewhere uv
never looked, which is the provenance swap this path exists to stop."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
for var, value in (
("PIP_NO_INDEX", "1"),
("PIP_EXTRA_INDEX_URL", "https://elsewhere/simple"),
("PIP_FIND_LINKS", "/tmp/stale-wheels"),
):
monkeypatch.setenv(var, value)
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement("unsloth-zoo") is None
env = calls[-1][1]["env"]
# Measured on pip 26.2: an empty value reads as unset.
assert env["PIP_NO_INDEX"] == ""
assert env["PIP_EXTRA_INDEX_URL"] == ""
assert env["PIP_FIND_LINKS"] == "/opt/wheels"
assert env["PIP_INDEX_URL"] == "https://mirror.corp/simple"
# pip.conf carries the same three settings, so it is replaced by a copy of
# itself with only those removed.
assert env["PIP_CONFIG_FILE"].endswith("pip.conf")
assert env["PIP_CONFIG_FILE"] != os.devnull
def test_no_find_links_survives_when_uv_emitted_none(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setenv("PIP_FIND_LINKS", "/tmp/stale-wheels")
self._uv_plan(monkeypatch, stdout = b"unsloth-zoo==1.0\n # from https://m/s\n")
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_FIND_LINKS"] == ""
def test_pip_transport_settings_survive_the_source_replacement(self, tmp_path, monkeypatch):
"""Dropping pip.conf wholesale would take proxy, cert, client-cert and
trusted-host with it, and those are how a private index is reached at all, so
uv would resolve and pip would then fail to fetch. The four source keys are
removed and everything else is written back."""
listing = (
b"global.cert='/etc/ssl/corp.pem'\n"
b"global.proxy='http://proxy.corp:8080'\n"
b"global.trusted-host='\\na.corp\\nb.corp'\n"
b"global.index-url='https://bogus/simple'\n"
b"global.extra-index-url='https://elsewhere/simple'\n"
b"global.find-links='/tmp/stale'\n"
b"global.no-index='true'\n"
b"install.no-binary='numpy'\n"
b":env:.config-file='/etc/pip.conf'\n"
)
monkeypatch.setattr(
ips.subprocess,
"run",
lambda *a, **k: types.SimpleNamespace(returncode = 0, stdout = listing),
)
written = Path(ips._pip_config_without_sources(str(tmp_path))).read_text()
assert "proxy = http://proxy.corp:8080" in written
assert "cert = /etc/ssl/corp.pem" in written
# A multi-value setting is spelled back as an indented continuation.
assert "trusted-host =\n a.corp\n b.corp" in written
assert "[install]" in written and "no-binary = numpy" in written
for dropped in ("index-url", "extra-index-url", "find-links", "no-index"):
assert dropped not in written, f"{dropped} must not survive"
# :env: entries come from the environment, which is overridden separately.
assert "config-file" not in written
def test_an_unreadable_pip_config_yields_an_empty_one(self, tmp_path, monkeypatch):
monkeypatch.setattr(
ips.subprocess,
"run",
lambda *a, **k: types.SimpleNamespace(returncode = 1, stdout = b""),
)
assert Path(ips._pip_config_without_sources(str(tmp_path))).read_text() == ""
def test_uv_artifact_policy_is_replayed_from_its_configuration(self, monkeypatch):
"""A no-binary or only-binary rule would otherwise change the artifact type
during the repair: a wheel downloaded under a no-binary rule, or an sdist
built under an only-binary one."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = b"--only-binary :all:\nunsloth-zoo==1.0\n # from https://m/s\n",
)
_requirement, _overrides, options = ips._uv_staging_plan("unsloth-zoo")
assert options == ["--only-binary", ":all:"]
def test_the_env_spelling_of_the_artifact_policy_is_translated(self, monkeypatch):
"""Measured on uv 0.10.7: --emit-build-options surfaces the policy from
uv.toml but not the environment-variable spelling, so that half is
translated by hand."""
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_ONLY_BINARY", ":all:")
monkeypatch.delenv("PIP_ONLY_BINARY", raising = False)
self._uv_plan(monkeypatch)
_requirement, overrides, options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_ONLY_BINARY"] == ":all:"
assert options == []
def test_an_explicit_pip_artifact_policy_is_left_alone(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_ONLY_BINARY", ":all:")
monkeypatch.setenv("PIP_ONLY_BINARY", "numpy")
self._uv_plan(monkeypatch)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides.get("PIP_ONLY_BINARY") is None
def test_the_keyring_provider_is_translated(self, monkeypatch):
"""uv reaches an authenticated index through the keyring CLI (uv 0.10.7:
`--keyring-provider subprocess` uses the `keyring` command). Carrying only
the URL leaves pip unable to fetch what uv just resolved, so every repair
on a private index aborts. pip accepts the same two values.
"""
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_KEYRING_PROVIDER", "subprocess")
monkeypatch.delenv("PIP_KEYRING_PROVIDER", raising = False)
self._uv_plan(monkeypatch)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_KEYRING_PROVIDER"] == "subprocess"
def test_an_explicit_pip_keyring_provider_is_left_alone(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_KEYRING_PROVIDER", "subprocess")
monkeypatch.setenv("PIP_KEYRING_PROVIDER", "import")
self._uv_plan(monkeypatch)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides.get("PIP_KEYRING_PROVIDER") is None
def test_the_staging_command_carries_the_build_options(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
calls = self._uv_plan(
monkeypatch,
stdout = b"--only-binary :all:\nunsloth-zoo==1.0\n # from https://m/s\n",
)
assert ips._stage_replacement("unsloth-zoo") is None
cmd = calls[-1][0]
assert cmd[cmd.index("--only-binary") + 1] == ":all:"
def test_the_annotated_index_is_recovered_with_its_credentials(self, monkeypatch):
"""Measured on uv 0.10.7: the emitted index lines carry userinfo and the
`# from` annotation has it stripped. Taking the annotation at face value
hands pip an unauthenticated URL for a private index, which answers 401 and
aborts the repair."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--index-url https://user:secret@private.corp/simple\n"
b"unsloth-zoo==1.0\n"
b" # from https://private.corp/simple\n"
),
)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_INDEX_URL"] == "https://user:secret@private.corp/simple"
def test_an_authenticated_extra_index_is_recovered_too(self, monkeypatch):
"""uv puts a credentialed --index on the extra line and leaves --index-url as
the public default, so reading only --index-url would name the wrong index."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--index-url https://pypi.org/simple\n"
b"--extra-index-url https://user:secret@private.corp/simple\n"
b"unsloth-zoo==1.0\n"
b" # from https://private.corp/simple\n"
),
)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_INDEX_URL"] == "https://user:secret@private.corp/simple"
def test_the_credentialed_form_wins_over_a_bare_duplicate(self, monkeypatch):
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--index-url https://private.corp/simple\n"
b"--extra-index-url https://user:secret@private.corp/simple\n"
b"unsloth-zoo==1.0\n"
b" # from https://private.corp/simple\n"
),
)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_INDEX_URL"] == "https://user:secret@private.corp/simple"
@pytest.mark.parametrize(
"url, bare",
(
("https://u:p@h/simple", "https://h/simple"),
("https://h/simple", "https://h/simple"),
("https://h/simple?a=b", "https://h/simple?a=b"),
("/local/dir", "/local/dir"),
),
)
def test_userinfo_is_stripped_without_disturbing_the_rest(self, url, bare):
assert ips._strip_userinfo(url) == bare
def test_offline_still_stages_a_local_checkout(self, tmp_path, monkeypatch):
"""--local hands the repair a checkout on disk. It needs no network, so
UV_OFFLINE has nothing to say about it, and refusing left the conflict in
place and failed the update for no reason."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
monkeypatch.setenv("UV_OFFLINE", "1")
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement(str(tmp_path)) is None
# It reached pip rather than refusing, and did not consult uv for a path.
assert calls and all(cmd[:3] != ["uv", "pip", "compile"] for cmd, _ in calls)
assert calls[-1][0][-1] == str(tmp_path)
def test_offline_local_staging_never_reaches_the_index(self, tmp_path, monkeypatch):
"""The checkout needs no network, but pip builds it in an isolated
environment and fetches the build backend for that, which UV_OFFLINE does not
reach. Measured: an isolated build of a local project with no index reachable
fails at installing build dependencies, and this repository pins its build
requirements exactly, so they would be fetched unless already cached."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
monkeypatch.setenv("UV_OFFLINE", "1")
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement(str(tmp_path)) is None
cmd, kwargs = calls[-1]
assert "--no-build-isolation" in cmd
assert kwargs["env"]["PIP_NO_INDEX"] == "1"
def test_online_local_staging_keeps_build_isolation(self, tmp_path, monkeypatch):
"""Isolation is how the pinned build requirements are honoured, so it is only
given up when the alternative is breaking the no-network policy."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
calls = self._uv_plan(monkeypatch)
assert ips._stage_replacement(str(tmp_path)) is None
cmd, kwargs = calls[-1]
assert "--no-build-isolation" not in cmd
assert kwargs["env"] is None or kwargs["env"].get("PIP_NO_INDEX") != "1"
def test_offline_still_refuses_a_git_reference(self, monkeypatch, capsys):
"""A git URL is a network fetch however direct the reference is."""
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
monkeypatch.setenv("UV_OFFLINE", "1")
def fake_run(*args, **kwargs):
raise AssertionError("nothing may run while uv is offline")
monkeypatch.setattr(ips.subprocess, "run", fake_run)
assert ips._stage_replacement("unsloth-zoo @ git+https://example/x") is None
assert "UV_OFFLINE" in capsys.readouterr().err
def test_a_find_links_origin_does_not_displace_the_real_index(self, monkeypatch):
"""uv annotates a flat source with a file:// URL. That belongs in
PIP_FIND_LINKS, which is already set, and must not become PIP_INDEX_URL: an
sdist picked out of a flat directory still needs the index for its build
backend, so staging would abort."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--index-url https://pypi.org/simple\n"
b"--find-links /opt/wheels\n"
b"unsloth-zoo==1.0\n"
b" # from file:///opt/wheels\n"
),
)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_INDEX_URL"] == "https://pypi.org/simple"
assert overrides["PIP_FIND_LINKS"] == "/opt/wheels"
def test_a_sole_unreadable_record_is_made_uninstallable(self, tmp_path):
"""Quarantining the only record leaves pip nothing to uninstall, so the
staged wheel is laid over the existing tree and any module the new release
dropped stays on disk, importable, while the repair reports success.
Verified against a real venv: with the METADATA corrupted pip show raises
UnicodeDecodeError for the whole environment; after this rewrite pip
uninstalls the package and removes its entire payload."""
record = tmp_path / "realpkg-1.2.3.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("realpkg/__init__.py,,\n")
assert ips._rewrite_minimal_metadata(str(record), "realpkg") is True
written = (record / "METADATA").read_text()
assert "Name: realpkg" in written
# The version comes from the directory name, which is where importlib's own
# fallback reads it when METADATA cannot be parsed.
assert "Version: 1.2.3" in written
def test_a_record_without_a_manifest_fails_closed(self, tmp_path):
"""No RECORD means neither pip nor this installer knows which files belong
to the package, so a replacement laid over them would leave whatever the new
release no longer ships behind."""
record = tmp_path / "realpkg-1.2.3.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
assert ips._rewrite_minimal_metadata(str(record), "realpkg") is False
def test_an_unversioned_directory_fails_closed(self, tmp_path):
record = tmp_path / "realpkg.dist-info"
record.mkdir()
(record / "RECORD").write_text("realpkg/__init__.py,,\n")
assert ips._rewrite_minimal_metadata(str(record), "realpkg") is False
def test_a_path_object_is_accepted(self, tmp_path):
"""install_manifest.invalid_metadata_paths() returns Path, and the repair
forwards it verbatim. Passing str here (as the tests around this one do)
hid an AttributeError on every real unreadable record.
"""
record = tmp_path / "realpkg-1.2.3.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("realpkg/__init__.py,,\n")
assert ips._rewrite_minimal_metadata(record, "realpkg") is True
assert "Version: 1.2.3" in (record / "METADATA").read_text()
def test_an_absent_metadata_is_synthesized_not_quarantined(self, tmp_path):
"""A record with an intact RECORD but no METADATA at all.
There is nothing to back up, which is not a failure: quarantining it
instead drops its RECORD, so the uninstall loop removes only what the
readable record claims and a module shipped solely by the older release
stays on disk and importable while the repair reports success.
"""
record = tmp_path / "realpkg-1.2.3.dist-info"
record.mkdir()
(record / "RECORD").write_text("realpkg/__init__.py,,\n")
quarantine = ips._QuarantinedMetadata()
assert quarantine.back_up(record / "METADATA") is True
assert ips._rewrite_minimal_metadata(record, "realpkg") is True
assert "Name: realpkg" in (record / "METADATA").read_text()
# A failure after the rewrite must not leave the synthetic file behind: a
# readable record would tell the next run there is nothing left to repair.
quarantine.restore()
assert not (record / "METADATA").exists()
def test_the_repair_refuses_when_the_only_record_cannot_be_made_usable(
self, tmp_path, monkeypatch, capsys
):
record = tmp_path / "unsloth-2026.8.12.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
# Quarantining the only record leaves nothing behind for pip to uninstall.
probes = iter(([""], []))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _n: next(probes))
monkeypatch.setattr(
ips.install_manifest, "invalid_metadata_paths", lambda _n: [str(record)]
)
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
def fake_stage(*args, **kwargs):
raise AssertionError("nothing may be staged before the records are usable")
monkeypatch.setattr(ips, "_stage_replacement", fake_stage)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert "Recreate the environment" in capsys.readouterr().err
# The record is left where it was, not quarantined into a temporary directory.
assert record.is_dir()
HASHED_OUT = (
b"--index-url https://mirror.corp/simple\n"
b"unsloth-zoo==2026.8.15 \\\n"
b" --hash=sha256:aaaa \\\n"
b" --hash=sha256:bbbb\n"
b" # from https://mirror.corp/simple\n"
)
def test_the_resolved_artifact_is_pinned_by_hash(self, monkeypatch):
"""Neither PIP_CONFIG_FILE nor --isolated suppresses a site pip.conf --
measured: with both, a venv pip.conf's extra-index-url was still contacted.
So pip may consult a source uv never considered, and the hashes are what stop
it accepting a different artifact of the same version from one. pip verifies
them even with PIP_REQUIRE_HASHES=0, which is also measured."""
self._uv_only(monkeypatch)
self._uv_plan(monkeypatch, stdout = self.HASHED_OUT)
requirement, _overrides, _options = ips._uv_staging_plan("unsloth-zoo")
# The pin line is continued with a backslash, which is not part of the pin.
assert requirement.startswith("unsloth-zoo==2026.8.15 \\\n")
assert "--hash=sha256:aaaa" in requirement
assert "--hash=sha256:bbbb" in requirement
def test_a_hashed_requirement_reaches_pip_as_a_file(self, tmp_path):
"""pip only accepts --hash entries from a requirements file."""
requirement = "unsloth-zoo==1.0 \\\n --hash=sha256:aaaa"
args = ips._requirement_args(requirement, str(tmp_path))
assert args[0] == "-r"
assert Path(args[1]).read_text().strip() == requirement
# It lives in the staging directory, so it is removed with it.
assert Path(args[1]).parent == tmp_path
def test_an_unhashed_requirement_is_passed_directly(self, tmp_path):
assert ips._requirement_args("unsloth-zoo", str(tmp_path)) == ["unsloth-zoo"]
assert list(tmp_path.iterdir()) == []
def test_a_flat_source_with_no_index_forbids_the_index(self, monkeypatch):
"""A configured no-index looks like this on the way out: uv emits the
find-links entry and no index line at all. Leaving PIP_NO_INDEX cleared would
hand pip back the default PyPI and let it stage the same name and version
from a source uv was told to exclude."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--find-links /opt/wheels\n"
b"unsloth-zoo==1.0\n"
b" # from file:///opt/wheels\n"
),
)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_NO_INDEX"] == "1"
assert overrides["PIP_FIND_LINKS"] == "/opt/wheels"
assert "PIP_INDEX_URL" not in overrides
def test_an_emitted_index_still_clears_no_index(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setenv("PIP_NO_INDEX", "1")
self._uv_plan(monkeypatch)
_requirement, overrides, _options = ips._uv_staging_plan("unsloth-zoo")
assert overrides["PIP_NO_INDEX"] == ""
def test_every_unreadable_record_with_a_manifest_is_made_uninstallable(
self, tmp_path, monkeypatch
):
"""One unreadable record beside a readable one used to be quarantined and
discarded, so its RECORD was never applied: the uninstall loop removed only
what the readable record claimed, and a module existing solely in the older
release stayed on disk and importable while the repair reported success."""
stale = tmp_path / "unsloth-2026.8.12.dist-info"
stale.mkdir()
(stale / "METADATA").write_bytes(b"\xff\xfe")
(stale / "RECORD").write_text("unsloth/gone.py,,\n")
probes = iter(
(["", "2026.8.15"], ["2026.8.12", "2026.8.15"], ["2026.8.15"], [], ["2026.8.15"])
)
taken = []
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _n: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [str(stale)])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _n: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
monkeypatch.setattr(
ips._QuarantinedMetadata, "take", lambda _self, paths: taken.append(paths) or True
)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is True
# It was rewritten for pip rather than moved aside, so its RECORD is applied
# and nothing is quarantined at all.
assert taken == []
assert "Name: unsloth" in (stale / "METADATA").read_text()
def test_a_repaired_package_is_not_rolled_back_by_a_later_failure(self, monkeypatch):
"""A single quarantine shared across both packages would, when the second
fails, restore the first package's stale record on top of the install that
has already replaced it: the conflict returns, and its old RECORD then
describes a payload that is gone."""
probes = {
"unsloth": iter((["", "2026.8.15"], ["2026.8.15"], [], ["2026.8.15"])),
"unsloth-zoo": iter((["", "2026.8.15"],)),
}
events = []
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda name: next(probes[name])
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
# The second package cannot be staged, so the repair fails after the first
# one has already been reinstalled.
staged = iter(("/staged", None))
monkeypatch.setattr(ips, "_stage_replacement", lambda _n: next(staged))
monkeypatch.setattr(
ips._QuarantinedMetadata, "discard", lambda _self: events.append("discard")
)
monkeypatch.setattr(
ips._QuarantinedMetadata, "restore", lambda _self: events.append("restore")
)
assert ips._repair_duplicate_core_metadata(("unsloth", "unsloth-zoo")) is False
# The first package was committed before the second was attempted, so the
# rollback at the end can only touch the one that failed.
assert events[0] == "discard"
assert events[-1] == "restore"
def test_a_direct_reference_pin_is_recognised(self, monkeypatch):
"""An override can redirect a package to a path, repository or URL, and uv
then emits `name @ reference` rather than `name==version`. Treating the whole
line as the name left the requirement empty and aborted every repair under
that policy."""
self._uv_only(monkeypatch)
self._uv_plan(
monkeypatch,
stdout = (
b"--index-url https://pypi.org/simple\n"
b"unsloth-zoo @ file:///src/zoo\n"
b" # from https://pypi.org/simple\n"
),
)
requirement, _overrides, _options = ips._uv_staging_plan("unsloth_zoo")
# The reference is kept as written; only the name is parsed out of it.
assert requirement == "unsloth-zoo @ file:///src/zoo"
@pytest.mark.parametrize(
"line, name",
(
("six==1.17.0", "six"),
("unsloth-zoo @ git+https://example/x", "unsloth-zoo"),
("unsloth_zoo @ file:///src", "unsloth_zoo"),
),
)
def test_the_name_is_taken_from_either_spelling(self, line, name):
assert ips._requirement_name(line) == name
def test_the_original_metadata_comes_back_when_the_repair_fails(self, tmp_path):
"""The rewrite has to happen before staging, and staging can still fail.
Without a backup the original is gone and what remains parses, so the next
run would see one readable record, decide nothing is wrong, and never attempt
the payload repair that is still owed."""
record = tmp_path / "unsloth-2026.8.12.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("unsloth/gone.py,,\n")
quarantine = ips._QuarantinedMetadata()
assert quarantine.back_up(str(record / "METADATA")) is True
assert ips._rewrite_minimal_metadata(str(record), "unsloth") is True
assert "Name: unsloth" in (record / "METADATA").read_text()
quarantine.restore()
# Byte for byte what was there, so the conflict is still detected next time.
assert (record / "METADATA").read_bytes() == b"\xff\xfe"
def test_a_committed_rewrite_is_not_undone(self, tmp_path):
record = tmp_path / "unsloth-2026.8.12.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("unsloth/gone.py,,\n")
quarantine = ips._QuarantinedMetadata()
quarantine.back_up(str(record / "METADATA"))
ips._rewrite_minimal_metadata(str(record), "unsloth")
quarantine.discard()
quarantine.restore()
assert "Name: unsloth" in (record / "METADATA").read_text()
def test_an_unbackable_metadata_stops_the_repair(self, tmp_path, monkeypatch, capsys):
"""The reachable route to an unrewritable record: a METADATA that exists but
cannot be read, as an elevated install leaves root-owned. back_up fails, so
the rewrite is skipped and the record can never be handed to pip.
Reproduced in a real venv with the file made unreadable: before this refused,
the repair returned True, the module only the stale release shipped stayed
importable, and its dist-info was deleted, so nothing could report it again.
"""
record = tmp_path / "unsloth-2026.8.12.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("unsloth/gone.py,,\n")
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda _n: ["", "2026.8.15"]
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [record])
monkeypatch.setattr(ips.install_manifest, "pip_backup_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips._QuarantinedMetadata, "back_up", lambda _self, _p: False)
def refuse(*_a, **_k):
raise AssertionError("nothing may run once a record is unusable")
monkeypatch.setattr(ips, "_stage_replacement", refuse)
monkeypatch.setattr(ips, "_run_ok", refuse)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert "cannot be read or rewritten" in capsys.readouterr().err
# Untouched, so the next run still sees it.
assert (record / "METADATA").read_bytes() == b"\xff\xfe"
def test_an_unresolvable_name_stages_nothing(self, monkeypatch):
self._uv_only(monkeypatch)
monkeypatch.setattr(ips, "USE_UV", True)
self._uv_plan(monkeypatch, stdout = b"--index-url https://pypi.org/simple\n")
assert ips._uv_staging_plan("unsloth-zoo") is None
def test_a_pin_for_another_package_is_not_mistaken_for_this_one(self, monkeypatch):
self._uv_only(monkeypatch)
self._uv_plan(monkeypatch, stdout = b"unsloth==2026.8.15\n")
assert ips._uv_staging_plan("unsloth-zoo") is None
def test_the_uv_upload_cutoff_reaches_pip(self, monkeypatch):
"""UV_EXCLUDE_NEWER limits candidates by upload time and pip ignores it, so
staging could install a release the user's policy excludes. pip's
--uploaded-prior-to is the same filter and takes the same date spellings
(checked on pip 26.2: a bare 2020-01-01 staged six 1.13.0, not 1.17.0)."""
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_EXCLUDE_NEWER", "2026-01-01")
monkeypatch.setattr(ips, "USE_UV", False)
monkeypatch.setattr(ips, "_pip_supports_upload_cutoff", lambda: True)
captured = {}
def fake_run(cmd, **kwargs):
captured["cmd"] = cmd
return types.SimpleNamespace(returncode = 1, stdout = b"")
monkeypatch.setattr(ips.subprocess, "run", fake_run)
assert ips._stage_replacement("unsloth") is None
assert "--uploaded-prior-to" in captured["cmd"]
assert captured["cmd"][captured["cmd"].index("--uploaded-prior-to") + 1] == "2026-01-01"
def test_an_unhonourable_cutoff_leaves_the_install_alone(self, monkeypatch, capsys):
"""--uploaded-prior-to only exists from pip 25.3. Staging a newer wheel
anyway would silently break the policy, so the repair aborts instead, with
the duplicate still in place and the package still installed."""
self._uv_only(monkeypatch)
monkeypatch.setenv("UV_EXCLUDE_NEWER", "2026-01-01")
monkeypatch.setattr(ips, "USE_UV", False)
monkeypatch.setattr(ips, "_pip_supports_upload_cutoff", lambda: False)
def fake_run(*args, **kwargs):
raise AssertionError("pip must not run when the cutoff cannot be honoured")
monkeypatch.setattr(ips.subprocess, "run", fake_run)
assert ips._stage_replacement("unsloth") is None
assert "UV_EXCLUDE_NEWER" in capsys.readouterr().err
def test_no_cutoff_argument_without_the_variable(self, monkeypatch):
self._uv_only(monkeypatch)
assert ips._uv_upload_cutoff_args() == []
@pytest.mark.parametrize("label", ("_restore_from_staged", "the repair fallback"))
def test_the_staged_wheel_is_reinstalled_with_pip_not_uv(self, monkeypatch, label):
"""UV_REQUIRE_HASHES would reject the unpinned name after the uninstall
loop has already removed every record, leaving the package uninstalled.
The wheel is already built, so pip is both safe and sufficient."""
installs = []
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(
ips,
"pip_install_try",
lambda _label, *args, **kwargs: installs.append(kwargs) or True,
)
if label == "_restore_from_staged":
ips._restore_from_staged("unsloth", "/staged", removed_any = True)
else:
probes = iter((["old", "new"], ["new"], [], ["new"]))
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda _name: next(probes)
)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
assert ips._repair_duplicate_core_metadata(("custom-package",))
assert len(installs) == 1
assert installs[0].get("force_pip") is True
def test_ci_overlay_is_wired_into_duplicate_repair(self):
source = inspect.getsource(ips.install_python_stack).replace(" ", "")
assert 'os.environ.get("UNSLOTH_CI_SOURCE_OVERLAY","")' in source
assert "ci_source_overlay=ci_source_overlay" in source
def test_the_replacement_is_staged_before_any_record_is_removed(self, monkeypatch):
"""The uninstall loop deletes every record, so the replacement has to be
in hand first. Otherwise an index that is unreachable at that moment
leaves the venv with no unsloth and nothing to reinstall from."""
probes = iter((["2026.8.12", "2026.8.15"], ["2026.8.15"], [], ["2026.8.15"]))
order = []
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(
ips, "_stage_replacement", lambda _name: order.append("stage") or "/staged"
)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: order.append("uninstall") or True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: order.append("install") or True)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is True
# Two records, so two uninstalls: pip removes one per invocation.
assert order == ["stage", "uninstall", "uninstall", "install"]
def test_repair_leaves_the_install_alone_when_the_replacement_cannot_be_fetched(
self, monkeypatch, capsys
):
probes = iter((["2026.8.12", "2026.8.15"],))
removals = []
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: None)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: removals.append(a) or True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert removals == []
assert "could not fetch a replacement" in capsys.readouterr().err
def test_a_failed_reinstall_reports_instead_of_exiting(self, monkeypatch, capsys):
probes = iter((["2026.8.12", "2026.8.15"], ["2026.8.15"], []))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: False)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert "no longer installed" in capsys.readouterr().err
def test_a_failed_uninstall_reports_instead_of_exiting(self, monkeypatch, capsys):
probes = iter((["2026.8.12", "2026.8.15"],))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: False)
installs = []
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: installs.append(a))
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert installs == []
assert "could not uninstall" in capsys.readouterr().err
def test_a_rollback_reinstall_keeps_its_own_metadata(self, monkeypatch, tmp_path, capsys):
"""The rewritten record is uninstalled, a later uninstall fails, and
_restore_from_staged puts the package back from the staged wheel. The
finally block then ran quarantine.restore() over the top, either deleting
the wheel's valid METADATA (original absent) or overwriting it with the
original corrupt bytes, leaving the core package malformed after a
recovery that existed to make it whole.
"""
record = tmp_path / "unsloth-2026.8.15.dist-info"
record.mkdir()
(record / "METADATA").write_bytes(b"\xff\xfe")
(record / "RECORD").write_text("unsloth/__init__.py,,\n")
probes = iter((["2026.8.15", "2026.8.15"], ["2026.8.15", "2026.8.15"], ["2026.8.15"]))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _n: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [record])
monkeypatch.setattr(ips.install_manifest, "pip_backup_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _n: str(tmp_path / "staged"))
runs = {"n": 0}
def uninstall(_label, _cmd):
runs["n"] += 1
if runs["n"] == 1:
# pip removed the rewritten record's whole directory.
shutil.rmtree(record)
return True
return False # the next one fails, triggering the rollback
monkeypatch.setattr(ips, "_run_ok", uninstall)
def reinstall(*_a, **_k):
# The staged wheel recreates the same path with its own valid metadata.
record.mkdir(exist_ok = True)
(record / "METADATA").write_text(
"Metadata-Version: 2.1\nName: unsloth\nVersion: 2026.8.15\n", encoding = "utf-8"
)
return True
monkeypatch.setattr(ips, "pip_install_try", reinstall)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
# Whatever the rollback put back must survive the quarantine unwinding.
assert record.is_dir()
assert (record / "METADATA").read_text().startswith("Metadata-Version")
assert "Name: unsloth" in (record / "METADATA").read_text()
def test_a_quarantined_backup_is_restored_when_staging_fails(self, monkeypatch, tmp_path):
"""Quarantine's remaining user is pip's ~ leftover, moved aside so the
uninstall loop can converge. Moving it and then failing to fetch the
replacement would leave the venv worse than it was found, so a failed
staging has to put it back.
"""
backup = tmp_path / "~nsloth-2026.8.12.dist-info"
backup.mkdir()
(backup / "METADATA").write_text(
"Metadata-Version: 2.1\nName: unsloth\nVersion: 2026.8.12\n", encoding = "utf-8"
)
probes = iter((["2026.8.12", "2026.8.15"], ["2026.8.15"]))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _n: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _n: [])
monkeypatch.setattr(ips.install_manifest, "pip_backup_metadata_paths", lambda _n: [backup])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _n: None)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert backup.is_dir()
assert "Name: unsloth" in (backup / "METADATA").read_text()
def test_staging_builds_a_wheel_so_the_offline_install_can_work(self):
"""pip download leaves an sdist for a source-only index, and the install
that follows runs --no-index, so its isolated build cannot fetch
setuptools and the package stays uninstalled."""
source = inspect.getsource(ips._stage_replacement).replace(" ", "")
assert '"wheel",\n"--no-deps",' in source
assert '"--wheel-dir",\nstaging,' in source
assert '"download"' not in source
assert 'glob.glob(os.path.join(staging,"*.whl"))' in source
def test_a_git_overlay_is_staged_before_the_uninstall_loop(self, monkeypatch):
"""--local pulls unsloth-zoo from git, so an overlay is a network fetch
too. Skipping staging for it meant an unreachable GitHub left the
package uninstalled."""
probes = {"unsloth-zoo": iter((["old", "new"], ["new"], [], ["new"]))}
order = []
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda name: next(probes[name])
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(
ips, "_stage_replacement", lambda spec: order.append(("stage", spec)) or "/staged"
)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: order.append(("uninstall",)) or True)
monkeypatch.setattr(
ips, "pip_install_try", lambda label, *a, **k: order.append(("install",)) or True
)
assert ips._repair_duplicate_core_metadata(("unsloth-zoo",), local_repo = "/src/unsloth")
assert order[0] == ("stage", "unsloth-zoo @ git+https://github.com/unslothai/unsloth-zoo")
assert order[1] == ("uninstall",)
def test_an_editable_overlay_stages_the_checkout(self, monkeypatch):
probes = {"unsloth": iter((["old", "new"], ["new"], [], ["new"]))}
staged_for = []
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda name: next(probes[name])
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(
ips, "_stage_replacement", lambda spec: staged_for.append(spec) or "/staged"
)
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
assert ips._repair_duplicate_core_metadata(("unsloth",), local_repo = "/src/unsloth")
assert staged_for == ["/src/unsloth"]
def test_a_failed_overlay_falls_back_to_the_staged_source(self, monkeypatch):
probes = {"unsloth-zoo": iter((["old", "new"], ["new"], [], ["new"]))}
installs = []
monkeypatch.setattr(
ips.install_manifest, "installed_versions", lambda name: next(probes[name])
)
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _spec: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "_overlay_local_core_package", lambda *a, **k: False)
monkeypatch.setattr(
ips, "pip_install_try", lambda label, *a, **k: installs.append(a) or True
)
assert ips._repair_duplicate_core_metadata(("unsloth-zoo",), local_repo = "/src/unsloth")
assert installs and "--find-links" in installs[0]
def test_a_partial_uninstall_restores_the_payload(self, monkeypatch, capsys):
"""The first uninstall deletes the package tree. Returning after a later
one fails would leave a dist-info claiming an install whose files are
gone."""
probes = iter((["a", "b", "c"], ["b", "c"]))
uninstalls = iter([True, False])
installs = []
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _spec: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: next(uninstalls))
monkeypatch.setattr(
ips, "pip_install_try", lambda label, *a, **k: installs.append(a) or True
)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert installs and "--find-links" in installs[0]
assert "restored unsloth from the staged replacement" in capsys.readouterr().err
def test_nothing_is_restored_when_no_record_was_removed(self, monkeypatch):
probes = iter((["a", "b"],))
installs = []
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips.install_manifest, "invalid_metadata_paths", lambda _name: [])
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _spec: "/staged")
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: False)
monkeypatch.setattr(ips, "pip_install_try", lambda label, *a, **k: installs.append(a))
assert ips._repair_duplicate_core_metadata(("unsloth",)) is False
assert installs == []
def test_staging_directories_are_cleaned_up(self, monkeypatch, tmp_path):
staged = tmp_path / "staged"
staged.mkdir()
probes = iter((["2026.8.12", "2026.8.15"], ["2026.8.15"], [], ["2026.8.15"]))
monkeypatch.setattr(ips.install_manifest, "installed_versions", lambda _name: next(probes))
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(ips.importlib, "invalidate_caches", lambda: None)
monkeypatch.setattr(ips, "_stage_replacement", lambda _name: str(staged))
monkeypatch.setattr(ips, "_run_ok", lambda *a, **k: True)
monkeypatch.setattr(ips, "pip_install_try", lambda *a, **k: True)
assert ips._repair_duplicate_core_metadata(("unsloth",)) is True
assert not staged.exists()
def test_normal_local_overlay_still_applies_both_sources(self, monkeypatch):
installs = []
monkeypatch.setattr(ips, "_step", lambda *a, **k: None)
monkeypatch.setattr(
ips,
"pip_install",
lambda label, *args, **kwargs: installs.append((label, args, kwargs)),
)
ips._overlay_local_core_packages("/src/unsloth")
assert [call[1] for call in installs] == [
("--no-cache-dir", "--no-deps", "-e", "/src/unsloth"),
(
"--no-cache-dir",
"--no-deps",
"--force-reinstall",
"unsloth-zoo @ git+https://github.com/unslothai/unsloth-zoo",
),
]
assert all(call[2]["constrain"] is False for call in installs)
class TestDesktopBackendVersionConstraint:
"""Verify that UNSLOTH_DESKTOP_BACKEND_VERSION adds the floor pin when upgrading unsloth."""
def test_spec_includes_floor_when_env_set(self):
with mock.patch.dict(os.environ, {"UNSLOTH_DESKTOP_BACKEND_VERSION": "2026.8.15"}):
desktop_min_ver = os.environ.get("UNSLOTH_DESKTOP_BACKEND_VERSION", "").strip()
package_name = "unsloth"
unsloth_spec = (
f"{package_name}>={desktop_min_ver}"
if (desktop_min_ver and package_name == "unsloth")
else package_name
)
assert unsloth_spec == "unsloth>=2026.8.15"
def test_spec_bare_when_env_unset(self):
with mock.patch.dict(os.environ, {}, clear = True):
desktop_min_ver = os.environ.get("UNSLOTH_DESKTOP_BACKEND_VERSION", "").strip()
package_name = "unsloth"
unsloth_spec = (
f"{package_name}>={desktop_min_ver}"
if (desktop_min_ver and package_name == "unsloth")
else package_name
)
assert unsloth_spec == "unsloth"