Add Windows support#75
Conversation
The CLI was entirely broken on Windows: console.py did unguarded
module-level /, which crashed at CLI
startup (ModuleNotFoundError) since execution.py imports connect_console
at load time. Every test file doing
failed at pytest collection.
Fixes:
- console.py: platform-guard the termios/tty imports; on win32 dispatch
to a new ctypes-based raw-console path in _winconsole.py (CONIN$/CONOUT$
mode save/restore, ENABLE_VIRTUAL_TERMINAL_INPUT raw input, VT output
processing, daemon resize-poll thread replacing SIGWINCH). Piped-stdin
path unchanged and cross-platform.
- _winconsole.py: new stdlib-ctypes Windows console helpers.
- repl.py: defer PromptSession construction from __init__ to run() so
ColabREPL does not require a real console at construction time
(prompt_toolkit Win32Output raised under captured stdout on Windows).
- commands/files.py: edit() now uses NamedTemporaryFile(delete=False) +
close + manual unlink so hashing/reopen/edit don't hit PermissionError
from Windows' exclusive temp-file handle.
- commands/automation.py: replace open('/dev/tty') in drivemount with a
cross-platform helper that falls back to sys.stdin on Windows.
- tests: guard POSIX termios/tty console tests with skipif(win32); add
Windows console-mode tests; add cross-platform /dev/tty fallback tests;
make the help-command parser robust to square Rich boxes and wrapped
description continuation lines.
- README.md / docs/02: document Windows support and the Unix-only
shebang limitation.
Verified on Windows 11 / Python 3.12.10: , ,
, , Usage: edit [OPTIONS] [FILE[:LINE[:COLUMN]]]
Options:
-h, --help Print this help message
-v, --version Print the version number
Arguments:
FILE[:LINE[:COLUMN]] The file to open, optionally with line and column (e.g., foo.txt:123:45)
, ,
Usage: Squirrel.exe command [OPTS]
Manages Squirrel packages
Commands
--install=VALUE Install the app whose package is in the specified
directory
--uninstall Uninstall the app the same dir as Update.exe
--download=VALUE Download the releases specified by the URL and
write new results to stdout as JSON
--checkForUpdate=VALUE Check for one available update and writes new
results to stdout as JSON
--update=VALUE Update the application to the latest remote
version specified by URL
--releasify=VALUE Update or generate a releases directory with a
given NuGet package
--createShortcut=VALUE Create a shortcut for the given executable name
--removeShortcut=VALUE Remove a shortcut for the given executable name
--updateSelf=VALUE Copy the currently executing Update.exe into the
default location
Options:
-h, -?, --help Display Help and exit
-r, --releaseDir=VALUE Path to a release directory to use with releasify
-p, --packagesDir=VALUE Path to the NuGet Packages directory for C# apps
--bootstrapperExe=VALUE
Path to the Setup.exe to use as a template
-g, --loadingGif=VALUE Path to an animated GIF to be displayed during
installation
-i, --icon=VALUE Path to an ICO file that will be used for icon
shortcuts
--setupIcon=VALUE Path to an ICO file that will be used for the
Setup executable's icon
-n, --signWithParams=VALUE Sign the installer via SignTool.exe with the
parameters given
-s, --silent Silent install
-l, --shortcut-locations=VALUE
Comma-separated string of shortcut locations, e.g.
'Desktop,StartMenu'
--no-msi Don't generate an MSI package
--no-delta Don't generate delta packages to save time
--framework-version=VALUE
Set the required .NET framework version, e.g.
net461
--msi-win64 Mark the MSI as 64-bit, which is useful in
Enterprise deployment scenarios
all run; full suite 237 passed, 1 skipped (POSIX termios test).
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
Live end-to-end verification on WindowsVerified against real Colab VMs (free tier) on Windows 11, after Auth (oauth2 remote copy-paste flow) — CPU VM
Free-tier T4 GPU VM
Ephemeral job
Cleanup — Not covered: the interactive (raw-TTY, human-at-keyboard) |
Windows automation support based on upstream PR googlecolab#75
@## What
The CLI was entirely broken on Windows.
src/colab_cli/console.pydid unguarded module-levelimport termios/import tty, and sincecommands/execution.pyimportsconnect_consolefrom it at load time (cli.py:26),import colab_cli.cliraisedModuleNotFoundError: No module named termioson Windows. This killed every command (colab --helpcrashed) and made the entire pytest suite fail at collection (every test file doesfrom colab_cli.cli import app). The README explicitly stated "Windows is not supported at this time."Changes
console.py— platform-guard thetermios/ttyimports (termios = tty = Noneon win32).connect_consolenow dispatches: POSIX keeps the existingtermios/tty/SIGWINCHpath; Windows uses a new ctypes raw-console path. The piped-stdin (isatty() == False) path is unchanged and cross-platform._winconsole.py(new) — stdlib-ctypesWindows console helpers: araw_mode()context manager that saves/restoresCONIN$/CONOUT$modes, enablesENABLE_VIRTUAL_TERMINAL_INPUT(disabling echo/line/processed input) andENABLE_VIRTUAL_TERMINAL_PROCESSINGon output, plusget_console_size()viaGetConsoleScreenBufferInfo. Nopywin32dependency.console.pyresize handling — Windows has noSIGWINCH; a daemon thread pollsGetConsoleScreenBufferInfoevery 0.25s and callssend_terminal_size(ws)on change.repl.py— deferPromptSessionconstruction fromColabREPL.__init__torun()(lazy,if self.session is None).prompt_toolkit'sWin32OutputcallsGetConsoleScreenBufferInfoatPromptSessioninit and raisedctypes.ArgumentErrorunder captured/non-tty stdout on Windows; constructing eagerly brokecolab repland 11 unit tests. Interactive use on a real Windows console is unaffected (run()builds the session against the real console).commands/files.py—edit()switched fromNamedTemporaryFile(delete=True)(held an exclusive handle on Windows →open(path,"rb")for hashing and the editor raisedPermissionError) todelete=False+ close + manualos.unlinkinfinally.commands/automation.py—drivemount'sopen("/dev/tty")(FileNotFoundError on Windows) replaced with_read_line_from_controlling_tty(), which tries/dev/ttyand falls back tosys.stdin.readline()on Windows.termios/ttyconsole tests withskipif(sys.platform == "win32"); added Windows console-mode set/restore tests (against the realCONIN$/CONOUT$); added cross-platform/dev/ttyfallback tests; made_extract_command_namesrobust to both rounded (╭/╰) and square (┌/└) Rich help boxes and to wrapped description continuation lines (Windows renders square boxes and wrapsVM/availableonto their own lines).README.md/docs/02_execution_and_interactive.md— document Windows support and the Unix-only shebang (#!/usr/bin/env -S colab run/chmod +x) limitation.Already Windows-handled (intentionally not touched)
spawn_keep_alive(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP),state.py(filelock.ReadWriteLock, notfcntl),~/.config/colab-clipaths (functional on Windows via~→C:\\Users\\<user>),common.kill_process(SIGTERM→TerminateProcess),auto_update.is_self_install_supported()(deliberately gated).Verification (on Windows 11, Python 3.12.10)
uv run python -c "import colab_cli.cli"→IMPORT OK(was:ModuleNotFoundError: No module named termios)uv run colab --help/version/repl --help/console --help/edit --help/drivemount --help/update→ all run, exit 0uv run pytest tests/ -q→ 237 passed, 1 skipped (was: 15 collection errors). The 1 skip is the POSIXtermios-based console test on Windows.uv run ruff check src/colab_cli tests→ clean_read_line_from_controlling_tty()verified on Windows:open("/dev/tty")raisesOSError→ falls back tosys.stdin.readline()._winconsole.raw_mode()verified against the real Windows console: input mode hasENABLE_VIRTUAL_TERMINAL_INPUTset andENABLE_LINE_INPUTcleared mid-flight, restored on exit.Not verified end-to-end
Interactive
colab console/colab replagainst a live Colab VM require OAuth + a billable VM allocation, which I can't provision autonomously. The raw-console ctypes path and command wiring are unit-tested and--help-verified; a live interactive session should be run by a reviewer on Windows Terminal to confirm end-to-end. Pipedcolab console/repl(non-VM) reach the websocket/prompt layer correctly.Review with
git diff main..windows-support.@