Skip to content

fix(url): also emit #datalabBackendUrl=<full URL> fragment - #27

Merged
teeler merged 1 commit into
googlecolab:mainfrom
teeler:fix-url-fragment
May 27, 2026
Merged

teeler merged 1 commit into
googlecolab:mainfrom
teeler:fix-url-fragment

Conversation

@teeler

@teeler teeler commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

colab url previously emitted only ?dbu=<urlencoded path>. Some Colab frontend code paths consult #datalabBackendUrl=<full URL> first and ignore dbu — for those users the printed URL silently fell through to allocating a fresh VM via /tun/m/assign instead of attaching to the existing session. Now we emit BOTH signals.

New output format:

https://<host>/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2F<endpoint>#datalabBackendUrl=<host>/tun/m/<endpoint>

Design points

  • Fragment value is a full URL (scheme + host), not just the path.
  • Fragment is raw (no URL encoding) because browsers don't decode the fragment before passing location.hash to page JS, and Colab's parser calls new URL(rawString) directly. Encoding : → %3A here would break the parser.
  • Fragment host always matches --host so same-origin enforcement passes, and --host https://colab.sandbox.google.com users get a sandbox fragment automatically.
  • Existing ?dbu= param is kept for backwards compatibility.

Tests

3 new test cases in tests/test_url.py:

  1. test_url_fragment_is_not_url_encoded — asserts %3A / %2F are NOT in the fragment, and literal :// IS.
  2. test_url_both_signals_present — invariant: every URL has BOTH ?dbu= and #datalabBackendUrl=.
  3. test_url_open_flag_includes_fragment — --open propagates the fragment to webbrowser.open().

4 existing tests updated to assert the fragment value alongside their existing dbu assertions.

Verification

  • uv run pytest tests/ — 201 passed (was 198)
  • uv run ruff check . — clean
  • Integration-verified live against synthetic session state with three host shapes:
$ colab url -s fake
https://colab.research.google.com/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2Fm-s-rtp1#datalabBackendUrl=https://colab.research.google.com/tun/m/m-s-rtp1

$ colab url -s fake --host https://colab.sandbox.google.com
https://colab.sandbox.google.com/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2Fm-s-rtp1#datalabBackendUrl=https://colab.sandbox.google.com/tun/m/m-s-rtp1

$ colab url -s fake --host https://colab.research.google.com/   # trailing slash
https://colab.research.google.com/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2Fm-s-rtp1#datalabBackendUrl=https://colab.research.google.com/tun/m/m-s-rtp1

All three: no // artifacts, fragment host matches page origin, fragment is raw not encoded.

`colab url` previously emitted only `?dbu=<urlencoded path>`, which the
Colab frontend's `Traits.getDatalabBackendUrl` reads. But some frontend
code paths consult the hash-fragment form `#datalabBackendUrl=<full URL>`
first and ignore `dbu`, so the query-only form silently failed for those
users (the frontend fell through to allocating a fresh VM via
`/tun/m/assign` instead of attaching to the existing session).

New output format:
  https://<host>/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2F<endpoint>#datalabBackendUrl=<host>/tun/m/<endpoint>

Key design points:

- Fragment value is a FULL URL (with scheme + host), not just the path.
- Fragment is emitted RAW (no URL encoding) because browsers don't
  decode the fragment before passing `location.hash` to page JS, and
  Colab's parser calls `new URL(rawString)` directly. Percent-encoding
  `:` or `/` here would break the parser.
- Fragment host always matches `--host` so Colab's same-origin
  enforcement on embedded backend URLs doesn't block the connection,
  and `--host https://colab.sandbox.google.com` users get a sandbox
  fragment automatically.
- The existing `?dbu=` param is kept for backwards compatibility and
  to handle frontend code paths that consult it instead.

Three new test cases in tests/test_url.py:

1. test_url_fragment_is_not_url_encoded - asserts %3A and %2F are
   NOT present in the fragment, and the literal `://` IS.
2. test_url_both_signals_present - invariant: every URL has BOTH
   `?dbu=` and `#datalabBackendUrl=`.
3. test_url_open_flag_includes_fragment - --open propagates the
   fragment to webbrowser.open() (otherwise the launch attaches to
   a fresh VM).

Existing tests updated to assert the fragment value alongside the
existing `dbu` assertions (4 tests touched).

Integration-verified live against synthetic session state with three
host shapes (default research.google.com, sandbox.google.com, and
trailing-slash); all produced correctly-shaped URLs with no `//`
artifacts and host-matching fragments.
@teeler
teeler requested a review from sethtroisi May 27, 2026 16:46
@teeler
teeler merged commit 8a350c1 into googlecolab:main May 27, 2026
6 checks passed
@teeler
teeler deleted the fix-url-fragment branch May 27, 2026 17:24
sethtroisi pushed a commit that referenced this pull request May 27, 2026
…oup (#29)

These three packages were declared in [project].dependencies, which
forced every consumer that ran `pip install google-colab-cli` to also
install the entire pytest test framework plus its transitive deps
(coverage, iniconfig, pluggy) -- ~2.5MB of test machinery that user
code never imports.

The correct semantic for test dependencies is [dependency-groups].dev
(PEP 735), which `uv sync` populates by default for contributors but
is NOT advertised in the published wheel's metadata as a runtime
requirement.

Concrete impact measured by installing the resulting wheel into a
fresh py3.13 venv (`uv pip install dist/*.whl`):

  Before:  57 packages, 200 MB site-packages
  After:   51 packages, 197 MB site-packages
  Gone:    pytest, pytest-cov, pytest-mock, coverage, iniconfig, pluggy

Beyond size, removing pytest from runtime deps stops dependency
scanners (pipdeptree, pip-audit, dependabot, snyk) from treating
pytest version pins as user-facing constraints -- previously, any
downstream environment that pinned pytest 8.x for plugin compat
would conflict with our floor of pytest>=9.0.2 even though no
user code imports pytest.

Verified:
- `uv sync` + `uv run pytest tests/` -> 201 passed (dev group still
  installs everything contributors need)
- `uv run ruff check .` -> clean
- Built wheel + installed into fresh venv: no pytest/coverage/pluggy
  in site-packages, `colab version` works, `colab url` works
  (verifies #27 fragment fix is intact in the install path).
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