Commit graph

2 commits

Author SHA1 Message Date
Daniel Han
c4b777263d
fix(studio/colab): fix OutStream startup crash and tidy the notebook cards (#7404)
* fix(studio/colab): survive ipykernel OutStream close() during startup

Unsloth Studio crashed at server startup on Colab with:

  Unsloth Studio failed to start: 'OutStream' object has no attribute
  'watch_fd_thread'

Root cause:
- Colab's ipykernel OutStream is created with watchfd=False, so it never
  gains a watch_fd_thread. The OutStream.close() in the affected ipykernel
  versions joins that thread unconditionally and raises AttributeError
  (ipython/ipykernel#867).
- _setup_server_disk_logging() replaces sys.stdout/sys.stderr with a tee.
  That changes the console object identity, so Colab's absl logging handler
  (which captured the original OutStream and whose close() deliberately skips
  sys.stdout/sys.stderr) no longer treats it as the live console.
- run_server builds uvicorn.Config(...), whose configure_logging runs
  logging.config.dictConfig -> logging.shutdown, closing every existing
  handler. The absl handler then calls close() on the orphaned OutStream and
  the AttributeError propagates out of uvicorn.Config and aborts startup.

Fix:
- Before installing the tee, harden the displaced console streams' close() so
  only the ipykernel#867 AttributeError is swallowed; a healthy close() runs
  unchanged and any other error still propagates. The buggy close() raises
  before it nulls pub_thread, so the stream stays fully usable.
- Give _TeeStream its own close() that flushes the log copy and forwards
  close() to the wrapped console stream best-effort, so a handler that
  captured the tee cannot crash startup either.

Add regression tests reproducing the exact path (an absl-style handler closing
a watchfd=False OutStream stand-in during logging.shutdown) and asserting the
tee/console path survives and keeps logging.

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

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

* Show the Colab login password in the shareable link card

* Tighten Colab card comments for PR #7404

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

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

* Make the Colab tunnel URL clickable and emphasise the password

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

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

* Narrow the console close() hardening to the watch_fd_thread AttributeError

* Put the Colab password on its own line so selection excludes the label

* Keep the Colab password as plain selectable text

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-07-25 04:11:03 -07:00
Souravrajvi0
d17567af3e
fix(studio/colab): restore blank Colab iframe embed (#7344) (#7349)
* fix(studio/colab): restore iframe embed via serve_kernel_port_as_iframe

Colab's output sanitizer often strips custom <iframe> tags from
IPython.display.HTML without raising, leaving a blank cell even though
display() succeeded. The kernel-port helper is the supported embedding
path and registers the proxy correctly.

- Prefer serve_kernel_port_as_iframe; keep raw HTML iframe as fallback
- Always show the clickable link card via show_link() so the proxy URL
  is visible even when iframe embedding fails
- Add regression tests for embed ordering and URL truncation

Fixes #7344

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

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

* fix(studio/colab): harden iframe embed fallbacks per Codex review

Guard show_link so a display failure cannot skip embedding, and only use
serve_kernel_port_as_iframe when get_colab_url returned a real Colab proxy
URL so localhost/colabtools environments still get the HTML iframe path.

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

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

* fix(studio/colab): stop opening Colab proxy URLs in a new tab (#7349)

Colab *.prod.colab.dev proxy hosts are session-scoped and return HTTP 404
when opened as a top-level tab or from another device. Replace the
clickable Open button for those URLs with an in-notebook ready card, keep
serve_kernel_port_as_iframe for the UI, and point users at
start(cloudflare=True) for a real shareable / new-window link.

* fix(studio/colab): use kernel iframe on real Colab when eval_js fails (#7349)

Gate serve_kernel_port_as_iframe on COLAB_RELEASE_TAG + google.colab import
instead of a successful proxyPort URL. When eval_js fails and get_colab_url
falls back to localhost, real Colab notebooks still embed via the kernel helper
(port-only). colabtools without COLAB_RELEASE_TAG keeps the HTML iframe path.

Thanks @mfielding92 for the runtime diagnosis.

* Mock top-level google package in Colab embed tests

* test(studio/colab): mock top-level google package in Colab tests

Patching only sys.modules["google.colab"] fails when no google namespace
is installed: import google.colab resolves the parent first and returns
False in _is_colab_runtime(). Add a shared helper that mocks both google
and google.colab for deterministic tests across environments.

* Tighten comments in Colab embed helpers and tests

* fix(studio/colab): default Cloudflare on Colab with durable login credentials

Colab proxy iframes often load an empty document even when the kernel helper
appends the frame, leaving users unable to reach Studio to change the bootstrap
password and blocking start(cloudflare=True).

On real Colab runtime:
- Default cloudflare to True (pass cloudflare=False to opt out)
- Finalize the random admin password and print credentials in the notebook
- Persist credentials across cell re-runs after interrupt
- Show Cloudflare link before login credentials; skip blank proxy iframe when ready
- Reuse main._IS_COLAB for runtime detection (not COLAB_RELEASE_TAG alone)
- Only trust serve_kernel_port_as_iframe on real Colab; colabtools falls back to HTML
- Keep embedding when the link card display fails

Addresses Codex review feedback on #7349 and @mfielding92's catch-22 report.

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

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

* fix(studio/colab): skip credential finalize when cloudflare=False

Only call _finalize_colab_admin_password() when opening a Cloudflare
tunnel. start(cloudflare=False) should not clear the bootstrap-password
gate or show a login card that references a missing tunnel link.

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

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

* fix(studio/colab): drop stale cached Colab credentials after password change

On a Colab rerun the finalize path redisplayed the cached first-run
password whenever the bootstrap gate was already cleared. If the admin
changed the password through the app, that cached copy no longer
authenticates, so the notebook printed dead credentials. Validate the
cached password against the current stored hash before redisplaying and
drop the cache when it no longer matches.

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

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

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Daniel Han <danielhanchen@gmail.com>
2026-07-24 02:23:24 -07:00