Skip to content

gate on min uv version and shortcut python candidate search if known#4489

Merged
danielhanchen merged 12 commits into
unslothai:mainfrom
mmathew23:fix/install_minuv
Mar 22, 2026
Merged

gate on min uv version and shortcut python candidate search if known#4489
danielhanchen merged 12 commits into
unslothai:mainfrom
mmathew23:fix/install_minuv

Conversation

@mmathew23
Copy link
Copy Markdown
Collaborator

Gate uv min version in addition to uv presence. torch_backend isn't an available option in older uv versions so install might allow the older uv to pass but not recognize the --torch_backend flag. Gating on min uv version triggers a uv download.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the installation process by ensuring compatibility with the uv package manager and optimizing Python version selection. It prevents issues arising from outdated uv versions and streamlines the setup by allowing a pre-selected Python interpreter to be used directly, improving overall reliability and efficiency of the setup scripts.

Highlights

  • UV Version Gating: Implemented a minimum version check for the uv package manager (0.7.14) during installation. If uv is not present or its version is below the minimum, it will be downloaded and installed. This addresses issues with older uv versions not supporting the --torch_backend flag.
  • Optimized Python Candidate Search: Introduced a mechanism to pass a REQUESTED_PYTHON_VERSION from install.sh to studio/setup.sh. If this variable is set and points to an executable Python, studio/setup.sh will directly use it, bypassing the potentially time-consuming search for suitable Python binaries.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d30c50b11

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

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

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

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread install.sh Outdated
_uv_version_ok() {
_ver=$("$1" --version 2>/dev/null | awk '{print $2}') || return 1
[ -n "$_ver" ] || return 1
_oldest=$(printf '%s\n%s\n' "$UV_MIN_VERSION" "$_ver" | sort -V | head -n1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace GNU-only sort -V in uv version check

The new _uv_version_ok helper relies on sort -V, which is a GNU extension and is not available in the default BSD sort on macOS. In that environment this check fails and the script always treats uv as too old, forcing an unnecessary reinstall attempt; this can make installs fail in offline or restricted environments even when a sufficiently new uv is already present.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces two main changes: it enforces a minimum version for the uv package manager in install.sh, and it adds a shortcut in studio/setup.sh to use a pre-selected Python interpreter, avoiding a potentially slow search. The changes are logical and well-implemented. I have one suggestion to improve code clarity in install.sh.

Comment thread install.sh Outdated
UV_MIN_VERSION="0.7.14"

_uv_version_ok() {
_ver=$("$1" --version 2>/dev/null | awk '{print $2}') || return 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The || return 1 at the end of this line is unlikely to ever be triggered. The exit code of a pipeline is that of its last command (awk here), which will succeed even with empty input (e.g., if the uv --version command fails). The next line [ -n "$_ver" ] || return 1 already correctly handles the case of an empty version string. Removing the redundant || return 1 would improve code clarity.

Suggested change
_ver=$("$1" --version 2>/dev/null | awk '{print $2}') || return 1
_ver=$("$1" --version 2>/dev/null | awk '{print $2}')

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 885bf7312a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

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

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

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread install.sh Outdated
Comment on lines +191 to +195
if [ "$_a_part" -gt "$_b_part" ] 2>/dev/null; then
return 0
fi
if [ "$_a_part" -lt "$_b_part" ] 2>/dev/null; then
return 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize uv semver parts before numeric comparison

The new version_ge logic assumes each dot-separated token is purely numeric, so versions like 0.7.13-rc1 or 0.7.13+build make both integer comparisons fail here and the function eventually returns success. That causes _uv_version_ok to treat an older uv as meeting UV_MIN_VERSION, skipping the reinstall path and allowing the later uv pip install ... --torch-backend=auto step to fail on unsupported uv builds.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

@danielhanchen danielhanchen left a comment

Choose a reason for hiding this comment

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

Review of PR #4489

Thanks for the PR. The direction is good -- gating on a minimum uv version, making the llama.cpp build non-fatal, and shortcutting the Python search are all worthwhile. However there are a few issues that need fixing before merge.

Bug 1 (HIGH): TTY detection change breaks curl | sh install path

The autolaunch condition was changed from [ -t 0 ] to [ -t 1 ] && [ -t 2 ].

When installed via curl -fsSL url | sh:

  • fd 0 (stdin) = pipe from curl, NOT a TTY
  • fd 1 (stdout) = user terminal, IS a TTY
  • fd 2 (stderr) = user terminal, IS a TTY

The original [ -t 0 ] correctly detected the piped install and skipped autolaunch. The new condition passes in the curl | sh case, so Studio auto-launches unexpectedly when the user merely ran the one-line install.

Suggested fix: Use [ -t 0 ] && [ -t 1 ] (both stdin and stdout must be TTYs) to correctly handle both curl | sh and ./install.sh > log.txt cases.

Also: printing "To launch, run: ..." instructions right before auto-launching is redundant and confusing -- the instructions should only appear in the non-interactive branch.

Bug 2 (MEDIUM): version_ge fails open on pre-release/suffixed versions

When a version segment contains non-numeric characters (e.g. 0.7.13-rc1, 0.7.14-dev), both [ -gt ] and [ -lt ] fail silently due to 2>/dev/null. The loop falls through without returning, and the function returns 0 (passes).

Concrete example: version_ge "0.7.13-rc1" "0.7.14" returns success, so a pre-release uv would incorrectly pass the minimum version gate.

Suggested fix: Strip pre-release suffixes in _uv_version_ok before passing to version_ge:

_uv_version_ok() {
    _ver=$("$1" --version 2>/dev/null | awk '{print $2}') || return 1
    [ -n "$_ver" ] || return 1
    # Strip pre-release/build suffixes
    case "$_ver" in
        ''|*[!0-9.]*) _ver=${_ver%%[-+]*} ;;
    esac
    case "$_ver" in
        ''|*[!0-9.]*) return 1 ;;
    esac
    version_ge "$_ver" "$UV_MIN_VERSION"
}

Bug 3 (MEDIUM): REQUESTED_PYTHON_VERSION shortcut bypasses version range validation

The new shortcut path only checks if the binary is executable (-x) but skips the 3.11 <= minor <= 3.13 range check that the normal discovery loop enforces. If REQUESTED_PYTHON_VERSION points to an out-of-range interpreter, it gets accepted and the "compatible (3.11.x - 3.13.x)" message is printed incorrectly.

While install.sh currently always passes a 3.13 venv Python, this env var is a general mechanism and should enforce the same contract as the discovery loop.

Suggested fix: After accepting the executable, validate its version:

if [ -n "${REQUESTED_PYTHON_VERSION:-}" ] && [ -x "$REQUESTED_PYTHON_VERSION" ]; then
    _req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
    _req_minor=$(echo "$_req_ver" | cut -d. -f2)
    if [ "$_req_minor" -ge "$MIN_PY_MINOR" ] 2>/dev/null && \
       [ "$_req_minor" -le "$MAX_PY_MINOR" ] 2>/dev/null; then
        BEST_PY="$REQUESTED_PYTHON_VERSION"
        echo "Using requested Python version: $BEST_PY"
    else
        echo "Ignoring requested Python $REQUESTED_PYTHON_VERSION ($_req_ver) -- outside supported range"
    fi
fi

Code quality: run_quiet / run_quiet_no_exit duplication

The two functions are identical except for exit vs return. This duplicates ~14 lines. Consider consolidating into a single helper with a mode parameter:

_run_quiet() {
    local on_fail="$1"; local label="$2"; shift 2
    local tmplog; tmplog=$(mktemp)
    if "$@" > "$tmplog" 2>&1; then rm -f "$tmplog"; return 0; fi
    local exit_code=$?
    echo "Failed: $label (exit code $exit_code):"; cat "$tmplog"; rm -f "$tmplog"
    [ "$on_fail" = "exit" ] && exit "$exit_code" || return "$exit_code"
}
run_quiet() { _run_quiet exit "$@"; }
run_quiet_no_exit() { _run_quiet return "$@"; }

That said, the fix itself (using return instead of exit so || BUILD_OK=false actually fires) is correct and a good catch -- the old run_quiet with exit made the || fallback dead code.

Minor: naming convention

version_ge lacks the underscore prefix used by other private helpers in install.sh (_is_pkg_installed, _smart_apt_install, _uv_version_ok). Should be _version_ge for consistency.

Minor: debug leftover

echo "finished finding best python" at line 251 of studio/setup.sh is a development leftover (pre-existing, not introduced by this PR, but worth cleaning up since this area is being touched).

@mmathew23
Copy link
Copy Markdown
Collaborator Author

@danielhanchen for the first one I was under the impression we wanted curl install.sh | sh to auto launch. But if that's not the case I'll revert. Then I'll address the remaining comments.

Copy link
Copy Markdown
Member

@danielhanchen danielhanchen left a comment

Choose a reason for hiding this comment

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

Thank you for the PR! The goal of this PR is to harden the installer and Studio setup by gating on a minimum uv version, shortcutting Python discovery, making llama.cpp builds non-fatal, and adding auto-port selection. As a summary, this PR adds a version_ge() helper to enforce uv >= 0.7.14, introduces REQUESTED_PYTHON_VERSION to skip redundant Python discovery in studio/setup.sh, refactors run_quiet into _run_quiet/run_quiet_no_exit so llama.cpp build failures don't abort setup, and auto-selects a free port in 8888-8898 for Studio launch.

Reviewers Severity Finding
8/8 High REQUESTED_PYTHON_VERSION only validates minor version -- a hypothetical Python 4.x would pass
8/8 High exit 1 on port exhaustion (8888-8898) fails an otherwise successful install
7/8 Medium [ -t 1 ] && [ -t 2 ] (was [ -t 0 ]) now auto-launches under `curl
8/8 Medium _run_quiet() drops local declarations, leaking on_fail/label/tmplog/exit_code into global scope

Concrete suggestions for each finding below.

Comment thread studio/setup.sh
Comment on lines +214 to +217
_req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
_req_minor=$(echo "$_req_ver" | cut -d. -f2)
if [ "$_req_minor" -ge "$MIN_PY_MINOR" ] 2>/dev/null && \
[ "$_req_minor" -le "$MAX_PY_MINOR" ] 2>/dev/null; then
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[8/8 reviewers] High -- REQUESTED_PYTHON_VERSION only validates the minor version, not the major version. A hypothetical Python 4.12.x would pass the _req_minor range check and be accepted.

Extract _req_major and add a [ "$_req_major" -eq 3 ] guard:

Suggested change
_req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
_req_minor=$(echo "$_req_ver" | cut -d. -f2)
if [ "$_req_minor" -ge "$MIN_PY_MINOR" ] 2>/dev/null && \
[ "$_req_minor" -le "$MAX_PY_MINOR" ] 2>/dev/null; then
_req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
_req_major=$(echo "$_req_ver" | cut -d. -f1)
_req_minor=$(echo "$_req_ver" | cut -d. -f2)
if [ "$_req_major" -eq 3 ] 2>/dev/null && \
[ "$_req_minor" -ge "$MIN_PY_MINOR" ] 2>/dev/null && \
[ "$_req_minor" -le "$MAX_PY_MINOR" ] 2>/dev/null; then

Comment thread install.sh Outdated
Comment on lines +287 to +303
STUDIO_PORT=$(find_open_port "$START_PORT" "$END_PORT") || {
echo "Error: could not find an open port for Unsloth Studio between 8888 and 8898."
echo " To launch, free port 8888 and run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p 8888"
echo ""
exit 1
}
echo " To launch, run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p ${STUDIO_PORT}"
echo ""
echo "==> Auto Launching Unsloth Studio..."
echo ""
exec "$VENV_NAME/bin/unsloth" studio -H 0.0.0.0 -p 8888
exec "$VENV_NAME/bin/unsloth" studio -H "$STUDIO_HOST" -p "$STUDIO_PORT"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[8/8 reviewers] High -- exit 1 here causes the entire installer to report failure when no port in 8888-8898 is free, even though the install itself succeeded. CI pipelines and wrapper scripts will see a non-zero exit code and treat the run as broken.

Replace with a non-fatal fallback that prints manual instructions and skips auto-launch. Also adds </dev/tty to the exec so Studio gets a proper tty when invoked via curl | sh:

Suggested change
STUDIO_PORT=$(find_open_port "$START_PORT" "$END_PORT") || {
echo "Error: could not find an open port for Unsloth Studio between 8888 and 8898."
echo " To launch, free port 8888 and run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p 8888"
echo ""
exit 1
}
echo " To launch, run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p ${STUDIO_PORT}"
echo ""
echo "==> Auto Launching Unsloth Studio..."
echo ""
exec "$VENV_NAME/bin/unsloth" studio -H 0.0.0.0 -p 8888
exec "$VENV_NAME/bin/unsloth" studio -H "$STUDIO_HOST" -p "$STUDIO_PORT"
STUDIO_PORT=$(find_open_port "$START_PORT" "$END_PORT") || STUDIO_PORT=""
if [ -n "$STUDIO_PORT" ]; then
echo " To launch, run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p ${STUDIO_PORT}"
echo ""
echo "==> Auto Launching Unsloth Studio..."
echo ""
exec "$VENV_NAME/bin/unsloth" studio -H "$STUDIO_HOST" -p "$STUDIO_PORT" </dev/tty
else
echo ""
echo "Note: could not find an open port for Unsloth Studio between ${START_PORT} and ${END_PORT}."
echo " To launch manually, free a port and run:"
echo ""
echo " source ${VENV_NAME}/bin/activate"
echo " unsloth studio -H ${STUDIO_HOST} -p 8888"
echo ""
fi

Comment thread install.sh Outdated
# in non-interactive environments (Docker, CI, cloud-init) just print instructions.
if [ -t 0 ]; then
echo "==> Launching Unsloth Studio..."
if [ -t 1 ] && [ -t 2 ]; then
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[7/8 reviewers] Medium -- The old guard was [ -t 0 ] (stdin is a tty), which prevented auto-launch under curl | sh since stdin is a pipe. The new guard [ -t 1 ] && [ -t 2 ] checks stdout/stderr but not stdin, so curl https://... | sh will now trigger auto-launch.

If this is intentional (so curl | sh users get Studio automatically), consider adding a brief inline comment so future readers don't "fix" it back to [ -t 0 ]:

Suggested change
if [ -t 1 ] && [ -t 2 ]; then
if [ -t 1 ] && [ -t 2 ]; then # stdout+stderr only; intentionally skips stdin for curl|sh

Comment thread studio/setup.sh Outdated
Comment on lines +12 to +25
on_fail=$1
label=$2
shift 2

tmplog=$(mktemp) || {
printf '%s\n' "Failed to create temporary file" >&2
[ "$on_fail" = "exit" ] && exit 1 || return 1
}

if "$@" >"$tmplog" 2>&1; then
rm -f "$tmplog"
return 0
else
local exit_code=$?
echo "❌ $label failed (exit code $exit_code):"
cat "$tmplog"
exit_code=$?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[8/8 reviewers] Medium -- _run_quiet() declares on_fail, label, tmplog, and exit_code without local, leaking them into the caller's (and global) scope. The original run_quiet() used local for all of these. Restore local to prevent variable pollution:

Suggested change
on_fail=$1
label=$2
shift 2
tmplog=$(mktemp) || {
printf '%s\n' "Failed to create temporary file" >&2
[ "$on_fail" = "exit" ] && exit 1 || return 1
}
if "$@" >"$tmplog" 2>&1; then
rm -f "$tmplog"
return 0
else
local exit_code=$?
echo "$label failed (exit code $exit_code):"
cat "$tmplog"
exit_code=$?
local on_fail=$1
local label=$2
shift 2
local tmplog
tmplog=$(mktemp) || {
printf '%s\n' "Failed to create temporary file" >&2
[ "$on_fail" = "exit" ] && exit 1 || return 1
}
if "$@" >"$tmplog" 2>&1; then
rm -f "$tmplog"
return 0
else
local exit_code=$?

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

- Remove find_open_port, TTY-gated autolaunch, and </dev/tty
  redirection from install.sh; just print launch instructions
- Remove unused BEST_MAJOR variable from studio/setup.sh
- Remove stray "finished finding best python" debug echo
- Fix stale comment "below 3.12" to "below 3.11"
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4db3bef01f

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread studio/setup.sh

# If the caller (e.g. install.sh) already chose a Python, use it directly.
if [ -n "${REQUESTED_PYTHON_VERSION:-}" ] && [ -x "$REQUESTED_PYTHON_VERSION" ]; then
_req_ver=$("$REQUESTED_PYTHON_VERSION" --version 2>&1 | awk '{print $2}')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle failing requested Python probe gracefully

With set -euo pipefail, the command substitution $("$REQUESTED_PYTHON_VERSION" --version ...) will terminate the whole script if that executable exits non-zero. That means a bad-but-executable REQUESTED_PYTHON_VERSION (for example a wrapper script that fails at runtime) now aborts setup before the existing fallback search can run, even though other valid Python 3.11–3.13 interpreters may be available.

Useful? React with 👍 / 👎.

@danielhanchen
Copy link
Copy Markdown
Member

/gemini review

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several improvements to the installation scripts. It adds a version check for the uv package manager to ensure a minimum required version is present, which is crucial for compatibility with features like --torch_backend. The Python discovery in setup.sh is now shortcut if a specific Python version is provided, speeding up the setup process. A significant bug fix has been made by refactoring the run_quiet helper function, which now correctly allows the GGUF build process to continue even if some steps fail, preventing the setup from exiting prematurely. The pull request also removes the automatic launching of Unsloth Studio in interactive terminals, which makes the installer's behavior more consistent and predictable. Additionally, a comment highlights a potential issue in install.sh regarding numeric comparisons that hide errors, suggesting to let the script fail loudly for easier debugging.

Comment thread install.sh Outdated
Comment on lines +191 to +196
if [ "$_a_part" -gt "$_b_part" ] 2>/dev/null; then
return 0
fi
if [ "$_a_part" -lt "$_b_part" ] 2>/dev/null; then
return 1
fi
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The redirection to /dev/null in the numeric comparisons (-gt, -lt) hides potential errors if a version component is not an integer. While _uv_version_ok validates the version string, it's safer to let the script fail loudly if a non-numeric value ever reaches this point. This would make debugging easier if the validation logic changes in the future. Given set -e is active, an error here would correctly halt execution.

Suggested change
if [ "$_a_part" -gt "$_b_part" ] 2>/dev/null; then
return 0
fi
if [ "$_a_part" -lt "$_b_part" ] 2>/dev/null; then
return 1
fi
if [ "$_a_part" -gt "$_b_part" ]; then
return 0
fi
if [ "$_a_part" -lt "$_b_part" ]; then
return 1
fi

Let non-numeric version parts surface errors on stderr
instead of being silently swallowed.
@danielhanchen danielhanchen merged commit 4c1a6cb into unslothai:main Mar 22, 2026
1 check passed
shibizhao pushed a commit to shibizhao/unsloth-npu that referenced this pull request Apr 7, 2026
…nslothai#4489)

* gate on min uv version and shortcut python candidate search if known

* fix sort -V cross compat issue, run_quiet early exit on llamacpp, autolaunch

* update launch message

* Fix PR comments

* auto launch and find open port

* remove dev install

* Fix review findings: major-version guard, non-fatal port fallback, tty comment, restore local

* Remove autolaunch, clean up dead state and debug noise

- Remove find_open_port, TTY-gated autolaunch, and </dev/tty
  redirection from install.sh; just print launch instructions
- Remove unused BEST_MAJOR variable from studio/setup.sh
- Remove stray "finished finding best python" debug echo
- Fix stale comment "below 3.12" to "below 3.11"

* Reject prerelease uv at exact minimum version boundary

* Remove 2>/dev/null from version_ge numeric comparisons

Let non-numeric version parts surface errors on stderr
instead of being silently swallowed.

---------

Co-authored-by: Daniel Han <danielhanchen@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants