google-colab-cli 0.5.7__tar.gz → 0.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google_colab_cli-0.5.9/PKG-INFO +203 -0
- google_colab_cli-0.5.9/README.md +181 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/02_execution_and_interactive.md +1 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/04_automation_and_utility.md +31 -6
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/05_run_command.md +1 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/README.md +2 -0
- google_colab_cli-0.5.9/integration/repro_bundled_oauth/test.sh +93 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/pyproject.toml +4 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/auth.py +41 -1
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/auto_update.py +21 -5
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/cli.py +5 -1
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/execution.py +6 -1
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/run.py +9 -2
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/session.py +3 -3
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/utility.py +49 -3
- google_colab_cli-0.5.9/src/colab_cli/oauth_config.json +11 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/runtime.py +1 -1
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_auth.py +30 -2
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_auth_adc.py +5 -6
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_exec.py +23 -2
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_ipynb_exec.py +2 -2
- google_colab_cli-0.5.9/tests/test_readme.py +92 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_run.py +25 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_update.py +104 -9
- google_colab_cli-0.5.7/PKG-INFO +0 -126
- google_colab_cli-0.5.7/README.md +0 -104
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/.githooks/pre-commit +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/.gitignore +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/.pre-commit-config.yaml +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/.python-version +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/AGENTS.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/COLAB_SKILL.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/CONTRIBUTING.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/LICENSE +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/cloudbuild.yaml +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/01_session_management.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/03_file_management.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/3042ab12-2026-05-07.png +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/docs/demos.md +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_keep_alive/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_keep_alive_scope/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_piped_console/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_plot_redirection/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_run_command/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/integration/repro_variable_persistence/test.sh +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/client.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/__init__.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/automation.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/commands/files.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/common.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/console.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/contents.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/converter.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/history.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/repl.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/state.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/src/colab_cli/utils.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/conftest.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_automation.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_cli.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_cli_log.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_client.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_console.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_contents.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_history.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_keep_alive.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_log_export.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_pay.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_repl.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_resolution_logic.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_runtime.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_state.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_streaming.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_url.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_utils.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_version.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/tests/test_whoami.py +0 -0
- {google_colab_cli-0.5.7 → google_colab_cli-0.5.9}/uv.lock +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: google-colab-cli
|
|
3
|
+
Version: 0.5.9
|
|
4
|
+
Summary: CLI for interacting with Colab.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: click>=8.0
|
|
8
|
+
Requires-Dist: google-auth-oauthlib>=1.3.0
|
|
9
|
+
Requires-Dist: google-auth>=2.49.1
|
|
10
|
+
Requires-Dist: jupyter-kernel-client
|
|
11
|
+
Requires-Dist: nbformat>=5.10.4
|
|
12
|
+
Requires-Dist: packaging>=24.0
|
|
13
|
+
Requires-Dist: prompt-toolkit>=3.0.52
|
|
14
|
+
Requires-Dist: pydantic>=2.12.5
|
|
15
|
+
Requires-Dist: pygments>=2.19.2
|
|
16
|
+
Requires-Dist: requests>=2.32.5
|
|
17
|
+
Requires-Dist: rich>=14.3.3
|
|
18
|
+
Requires-Dist: typer>=0.24.1
|
|
19
|
+
Requires-Dist: typing-extensions>=4.0
|
|
20
|
+
Requires-Dist: websocket-client>=1.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Colab CLI
|
|
24
|
+
|
|
25
|
+
A command-line interface for Google Colab. Provision high-performance CPU, GPU, and TPU runtimes, execute local code, manage remote files, and orchestrate automated cloud pipelines — directly from your terminal.
|
|
26
|
+
|
|
27
|
+
Designed to support seamless developer productivity, headless automation, and AI agent integrations.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Key Features
|
|
32
|
+
|
|
33
|
+
* **Instant VM Provisioning:** Spin up CPU, GPU (T4, L4, G4, H100, A100), or TPU (v5e1, v6e1) runtimes in seconds.
|
|
34
|
+
* **Robust Code Execution:** Run local Python scripts, Jupyter Notebooks (`.ipynb`), or piped `stdin` code; launch interactive REPLs or raw TTY console shells.
|
|
35
|
+
* **Ephemeral Job Runner (`colab run`):** Provision a fresh VM, execute a local script with forwarded arguments, retrieve output files, and automatically tear down the runtime in a single command.
|
|
36
|
+
* **Automatic Keep-Alive:** Built-in background daemon automatically prevents idle VM termination, keeping resource allocations active without requiring open browser tabs.
|
|
37
|
+
* **Seamless Workspace Automation:** Mount Google Drive, authenticate Google Cloud Platform (GCP) credentials, and install dependencies with high-performance `uv` package management.
|
|
38
|
+
* **State & Log Archival:** Inspect local session states or export interactive history logs to standard Jupyter Notebooks, Markdown, or structured JSONL.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
Install the package using `uv` (recommended) or standard `pip`:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Using uv (recommended)
|
|
48
|
+
uv tool install google-colab-cli
|
|
49
|
+
|
|
50
|
+
# Using pip
|
|
51
|
+
pip install google-colab-cli
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
Run a CPU-based VM runtime, execute some code, and clean up:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 1. Provision a new session
|
|
62
|
+
colab new
|
|
63
|
+
|
|
64
|
+
# 2. Execute code from stdin
|
|
65
|
+
echo "print('Hello from Google Colab!')" | colab exec
|
|
66
|
+
|
|
67
|
+
# 3. Stop and release the VM resource
|
|
68
|
+
colab stop
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> [!NOTE]
|
|
72
|
+
> When only one session is active, you can omit the `-s, --session` option;
|
|
73
|
+
> the CLI automatically knows it.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Command Index
|
|
79
|
+
|
|
80
|
+
Run `colab <command> --help` to view specific options, defaults, and detailed help.
|
|
81
|
+
|
|
82
|
+
### Session Management
|
|
83
|
+
| Command | Description |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `colab new [-s NAME] [--gpu GPU] [--tpu TPU]` | Allocate a new CPU, GPU, or TPU VM runtime |
|
|
86
|
+
| `colab sessions` | List all active sessions currently active on the backend |
|
|
87
|
+
| `colab status [-s NAME]` | Display hardware, status, and local metadata for active sessions |
|
|
88
|
+
| `colab restart-kernel [-s NAME]` | Restart the active session's Jupyter kernel |
|
|
89
|
+
| `colab stop [-s NAME]` | Terminate a session VM and tear down its keep-alive daemon |
|
|
90
|
+
| `colab url [-s NAME] [--open]` | Print or open a browser URL connecting to the active session |
|
|
91
|
+
|
|
92
|
+
### Execution
|
|
93
|
+
| Command | Description |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `colab run [--gpu GPU] [--tpu TPU] [--keep] SCRIPT [ARGS...]` | Run a local script on a fresh VM, forwarding arguments, then release it |
|
|
96
|
+
| `colab exec [-s NAME] [-f FILE] [--output-image PATH]` | Execute Python code from stdin, a local `.py` file, or a `.ipynb` notebook |
|
|
97
|
+
| `colab repl [-s NAME] [--output-image PATH]` | Start an interactive Python REPL on the VM (exits cleanly on piped EOF) |
|
|
98
|
+
| `colab console [-s NAME]` | Connect to a raw interactive TTY shell (tmux) on the remote VM |
|
|
99
|
+
|
|
100
|
+
### File Operations
|
|
101
|
+
| Command | Description |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `colab ls [-s NAME] [PATH]` | List remote files on the VM |
|
|
104
|
+
| `colab upload [-s NAME] LOCAL REMOTE` | Upload a local file to the VM filesystem |
|
|
105
|
+
| `colab download [-s NAME] REMOTE LOCAL` | Download a remote file from the VM filesystem |
|
|
106
|
+
| `colab rm [-s NAME] PATH` | Delete a remote file on the VM filesystem |
|
|
107
|
+
| `colab edit [-s NAME] PATH` | Edit a remote file in-place using your local `$EDITOR` |
|
|
108
|
+
|
|
109
|
+
### Automation & Utilities
|
|
110
|
+
| Command | Description |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `colab auth [-s NAME]` | Authenticate the VM for GCP services (BigQuery, GCS, etc.) |
|
|
113
|
+
| `colab drivemount [-s NAME] [PATH]` | Mount Google Drive on the VM (default: `/content/drive`) |
|
|
114
|
+
| `colab install [-s NAME] [-r FILE \| PKG...]` | Install packages on the VM using `uv` (falls back to `pip`) |
|
|
115
|
+
| `colab log [-s NAME] [-n N] [-o FILE]` | View or export session history (`.ipynb`, `.md`, `.txt`, `.jsonl`) |
|
|
116
|
+
| `colab pay` | Open the Colab subscription page to manage compute units |
|
|
117
|
+
| `colab version` | Print the installed version of the CLI |
|
|
118
|
+
| `colab update [--install]` | Check for a newer release (and optionally upgrade the CLI in place) |
|
|
119
|
+
|
|
120
|
+
### Global Options
|
|
121
|
+
* `--auth {oauth2,adc}` — Authentication strategy for the Colab API (default: `adc`).
|
|
122
|
+
* `-c, --client-oauth-config PATH` — Path to public OAuth client credentials configuration (default: `~/.colab-cli-oauth-config.json`).
|
|
123
|
+
* `--config PATH` — Path to local session metadata storage (default: `~/.config/colab-cli/sessions.json`).
|
|
124
|
+
* `--logtostderr` — Direct debug logging output to stderr.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Practical Examples
|
|
129
|
+
|
|
130
|
+
### Accelerator Training with Checkpoint Retrieval
|
|
131
|
+
|
|
132
|
+
Provision an A100 GPU, install requirements, run a local training script, retrieve the resulting model weights, and terminate the VM:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
colab new -s trainer --gpu A100
|
|
136
|
+
colab install -s trainer torch transformers
|
|
137
|
+
colab exec -s trainer -f train.py
|
|
138
|
+
colab download -s trainer checkpoints/model.bin ./model.bin
|
|
139
|
+
colab stop -s trainer
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Workspace Notebook Execution with Drive Integration
|
|
143
|
+
|
|
144
|
+
Mount Google Drive, run a local notebook against the VM kernel (outputs are written back into `report_output.ipynb`), export a Markdown log of the execution, and clean up:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
colab new -s analysis
|
|
148
|
+
colab drivemount -s analysis
|
|
149
|
+
colab exec -s analysis -f report.ipynb
|
|
150
|
+
colab log -s analysis -o execution_log.md
|
|
151
|
+
colab stop -s analysis
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Usage Notes
|
|
157
|
+
|
|
158
|
+
* **TTY Requirements:** The interactive commands `repl` and `console` require a local TTY. When running inside automated scripts or pipelines, make sure to pipe stdin (e.g., `echo "print(1)" | colab repl`) to trigger non-interactive execution modes.
|
|
159
|
+
* **Transparent Code Execution:** When calling `colab exec -f file.py`, the CLI reads the file locally and transmits its content to the remote kernel. You do not need to manually upload files before execution.
|
|
160
|
+
* **Storage & State Paths:** Session tokens and metadata are stored at `~/.config/colab-cli/sessions.json`. Global CLI settings are located at `~/.config/colab-cli/settings.json`. These can be customized or isolated via the global `--config` flag.
|
|
161
|
+
|
|
162
|
+
### Ephemeral Accelerator Jobs
|
|
163
|
+
|
|
164
|
+
Use `colab run` to run a local script on dedicated hardware without manual session lifecycle management. The CLI handles provisioning, script execution, and immediate VM teardown automatically:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Run train.py on a T4 GPU and release the VM on completion
|
|
168
|
+
colab run --gpu T4 train.py
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Shebang Execution Support
|
|
172
|
+
|
|
173
|
+
To execute a local file directly on a remote accelerator, place the `colab run` interpreter in the shebang line:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
#!/usr/bin/env -S colab run --gpu L4 --keep
|
|
177
|
+
import torch
|
|
178
|
+
|
|
179
|
+
print("L4 GPU Available:", torch.cuda.is_available())
|
|
180
|
+
print("Device Name:", torch.cuda.get_device_name(0))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Make the script executable (`chmod +x script.py`) and run it: `./script.py`. The `--keep` option tells the CLI to preserve the session VM on completion so you can re-execute or inspect logs.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Deep Dive Documentation
|
|
188
|
+
|
|
189
|
+
For comprehensive architectural overviews and deep-dives into specific CLI sub-systems, refer to the detailed documentation:
|
|
190
|
+
|
|
191
|
+
* [Session Management & Keep-Alive Architecture](docs/01_session_management.md)
|
|
192
|
+
* [Interactive & Non-Interactive Execution Design](docs/02_execution_and_interactive.md)
|
|
193
|
+
* [File Management & Jupyter Contents API](docs/03_file_management.md)
|
|
194
|
+
* [Authentication Providers & VM Automation](docs/04_automation_and_utility.md)
|
|
195
|
+
* [Ephemeral Job Runner Design](docs/05_run_command.md)
|
|
196
|
+
|
|
197
|
+
To view interactive walkthroughs of eleven real-world automated scenarios, check out the [Demo Walkthroughs](docs/demos.md).
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Feedback and contributions are welcome! Please read [`CONTRIBUTING.md`](./CONTRIBUTING.md) for details.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Colab CLI
|
|
2
|
+
|
|
3
|
+
A command-line interface for Google Colab. Provision high-performance CPU, GPU, and TPU runtimes, execute local code, manage remote files, and orchestrate automated cloud pipelines — directly from your terminal.
|
|
4
|
+
|
|
5
|
+
Designed to support seamless developer productivity, headless automation, and AI agent integrations.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
* **Instant VM Provisioning:** Spin up CPU, GPU (T4, L4, G4, H100, A100), or TPU (v5e1, v6e1) runtimes in seconds.
|
|
12
|
+
* **Robust Code Execution:** Run local Python scripts, Jupyter Notebooks (`.ipynb`), or piped `stdin` code; launch interactive REPLs or raw TTY console shells.
|
|
13
|
+
* **Ephemeral Job Runner (`colab run`):** Provision a fresh VM, execute a local script with forwarded arguments, retrieve output files, and automatically tear down the runtime in a single command.
|
|
14
|
+
* **Automatic Keep-Alive:** Built-in background daemon automatically prevents idle VM termination, keeping resource allocations active without requiring open browser tabs.
|
|
15
|
+
* **Seamless Workspace Automation:** Mount Google Drive, authenticate Google Cloud Platform (GCP) credentials, and install dependencies with high-performance `uv` package management.
|
|
16
|
+
* **State & Log Archival:** Inspect local session states or export interactive history logs to standard Jupyter Notebooks, Markdown, or structured JSONL.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install the package using `uv` (recommended) or standard `pip`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Using uv (recommended)
|
|
26
|
+
uv tool install google-colab-cli
|
|
27
|
+
|
|
28
|
+
# Using pip
|
|
29
|
+
pip install google-colab-cli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
Run a CPU-based VM runtime, execute some code, and clean up:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 1. Provision a new session
|
|
40
|
+
colab new
|
|
41
|
+
|
|
42
|
+
# 2. Execute code from stdin
|
|
43
|
+
echo "print('Hello from Google Colab!')" | colab exec
|
|
44
|
+
|
|
45
|
+
# 3. Stop and release the VM resource
|
|
46
|
+
colab stop
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> [!NOTE]
|
|
50
|
+
> When only one session is active, you can omit the `-s, --session` option;
|
|
51
|
+
> the CLI automatically knows it.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Command Index
|
|
57
|
+
|
|
58
|
+
Run `colab <command> --help` to view specific options, defaults, and detailed help.
|
|
59
|
+
|
|
60
|
+
### Session Management
|
|
61
|
+
| Command | Description |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `colab new [-s NAME] [--gpu GPU] [--tpu TPU]` | Allocate a new CPU, GPU, or TPU VM runtime |
|
|
64
|
+
| `colab sessions` | List all active sessions currently active on the backend |
|
|
65
|
+
| `colab status [-s NAME]` | Display hardware, status, and local metadata for active sessions |
|
|
66
|
+
| `colab restart-kernel [-s NAME]` | Restart the active session's Jupyter kernel |
|
|
67
|
+
| `colab stop [-s NAME]` | Terminate a session VM and tear down its keep-alive daemon |
|
|
68
|
+
| `colab url [-s NAME] [--open]` | Print or open a browser URL connecting to the active session |
|
|
69
|
+
|
|
70
|
+
### Execution
|
|
71
|
+
| Command | Description |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `colab run [--gpu GPU] [--tpu TPU] [--keep] SCRIPT [ARGS...]` | Run a local script on a fresh VM, forwarding arguments, then release it |
|
|
74
|
+
| `colab exec [-s NAME] [-f FILE] [--output-image PATH]` | Execute Python code from stdin, a local `.py` file, or a `.ipynb` notebook |
|
|
75
|
+
| `colab repl [-s NAME] [--output-image PATH]` | Start an interactive Python REPL on the VM (exits cleanly on piped EOF) |
|
|
76
|
+
| `colab console [-s NAME]` | Connect to a raw interactive TTY shell (tmux) on the remote VM |
|
|
77
|
+
|
|
78
|
+
### File Operations
|
|
79
|
+
| Command | Description |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `colab ls [-s NAME] [PATH]` | List remote files on the VM |
|
|
82
|
+
| `colab upload [-s NAME] LOCAL REMOTE` | Upload a local file to the VM filesystem |
|
|
83
|
+
| `colab download [-s NAME] REMOTE LOCAL` | Download a remote file from the VM filesystem |
|
|
84
|
+
| `colab rm [-s NAME] PATH` | Delete a remote file on the VM filesystem |
|
|
85
|
+
| `colab edit [-s NAME] PATH` | Edit a remote file in-place using your local `$EDITOR` |
|
|
86
|
+
|
|
87
|
+
### Automation & Utilities
|
|
88
|
+
| Command | Description |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `colab auth [-s NAME]` | Authenticate the VM for GCP services (BigQuery, GCS, etc.) |
|
|
91
|
+
| `colab drivemount [-s NAME] [PATH]` | Mount Google Drive on the VM (default: `/content/drive`) |
|
|
92
|
+
| `colab install [-s NAME] [-r FILE \| PKG...]` | Install packages on the VM using `uv` (falls back to `pip`) |
|
|
93
|
+
| `colab log [-s NAME] [-n N] [-o FILE]` | View or export session history (`.ipynb`, `.md`, `.txt`, `.jsonl`) |
|
|
94
|
+
| `colab pay` | Open the Colab subscription page to manage compute units |
|
|
95
|
+
| `colab version` | Print the installed version of the CLI |
|
|
96
|
+
| `colab update [--install]` | Check for a newer release (and optionally upgrade the CLI in place) |
|
|
97
|
+
|
|
98
|
+
### Global Options
|
|
99
|
+
* `--auth {oauth2,adc}` — Authentication strategy for the Colab API (default: `adc`).
|
|
100
|
+
* `-c, --client-oauth-config PATH` — Path to public OAuth client credentials configuration (default: `~/.colab-cli-oauth-config.json`).
|
|
101
|
+
* `--config PATH` — Path to local session metadata storage (default: `~/.config/colab-cli/sessions.json`).
|
|
102
|
+
* `--logtostderr` — Direct debug logging output to stderr.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Practical Examples
|
|
107
|
+
|
|
108
|
+
### Accelerator Training with Checkpoint Retrieval
|
|
109
|
+
|
|
110
|
+
Provision an A100 GPU, install requirements, run a local training script, retrieve the resulting model weights, and terminate the VM:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
colab new -s trainer --gpu A100
|
|
114
|
+
colab install -s trainer torch transformers
|
|
115
|
+
colab exec -s trainer -f train.py
|
|
116
|
+
colab download -s trainer checkpoints/model.bin ./model.bin
|
|
117
|
+
colab stop -s trainer
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Workspace Notebook Execution with Drive Integration
|
|
121
|
+
|
|
122
|
+
Mount Google Drive, run a local notebook against the VM kernel (outputs are written back into `report_output.ipynb`), export a Markdown log of the execution, and clean up:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
colab new -s analysis
|
|
126
|
+
colab drivemount -s analysis
|
|
127
|
+
colab exec -s analysis -f report.ipynb
|
|
128
|
+
colab log -s analysis -o execution_log.md
|
|
129
|
+
colab stop -s analysis
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Usage Notes
|
|
135
|
+
|
|
136
|
+
* **TTY Requirements:** The interactive commands `repl` and `console` require a local TTY. When running inside automated scripts or pipelines, make sure to pipe stdin (e.g., `echo "print(1)" | colab repl`) to trigger non-interactive execution modes.
|
|
137
|
+
* **Transparent Code Execution:** When calling `colab exec -f file.py`, the CLI reads the file locally and transmits its content to the remote kernel. You do not need to manually upload files before execution.
|
|
138
|
+
* **Storage & State Paths:** Session tokens and metadata are stored at `~/.config/colab-cli/sessions.json`. Global CLI settings are located at `~/.config/colab-cli/settings.json`. These can be customized or isolated via the global `--config` flag.
|
|
139
|
+
|
|
140
|
+
### Ephemeral Accelerator Jobs
|
|
141
|
+
|
|
142
|
+
Use `colab run` to run a local script on dedicated hardware without manual session lifecycle management. The CLI handles provisioning, script execution, and immediate VM teardown automatically:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Run train.py on a T4 GPU and release the VM on completion
|
|
146
|
+
colab run --gpu T4 train.py
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Shebang Execution Support
|
|
150
|
+
|
|
151
|
+
To execute a local file directly on a remote accelerator, place the `colab run` interpreter in the shebang line:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
#!/usr/bin/env -S colab run --gpu L4 --keep
|
|
155
|
+
import torch
|
|
156
|
+
|
|
157
|
+
print("L4 GPU Available:", torch.cuda.is_available())
|
|
158
|
+
print("Device Name:", torch.cuda.get_device_name(0))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Make the script executable (`chmod +x script.py`) and run it: `./script.py`. The `--keep` option tells the CLI to preserve the session VM on completion so you can re-execute or inspect logs.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Deep Dive Documentation
|
|
166
|
+
|
|
167
|
+
For comprehensive architectural overviews and deep-dives into specific CLI sub-systems, refer to the detailed documentation:
|
|
168
|
+
|
|
169
|
+
* [Session Management & Keep-Alive Architecture](docs/01_session_management.md)
|
|
170
|
+
* [Interactive & Non-Interactive Execution Design](docs/02_execution_and_interactive.md)
|
|
171
|
+
* [File Management & Jupyter Contents API](docs/03_file_management.md)
|
|
172
|
+
* [Authentication Providers & VM Automation](docs/04_automation_and_utility.md)
|
|
173
|
+
* [Ephemeral Job Runner Design](docs/05_run_command.md)
|
|
174
|
+
|
|
175
|
+
To view interactive walkthroughs of eleven real-world automated scenarios, check out the [Demo Walkthroughs](docs/demos.md).
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Contributing
|
|
180
|
+
|
|
181
|
+
Feedback and contributions are welcome! Please read [`CONTRIBUTING.md`](./CONTRIBUTING.md) for details.
|
|
@@ -26,6 +26,7 @@ Execution involves sending Python code (or shell commands) to the Jupyter kernel
|
|
|
26
26
|
- If file path is local: Read content, send as code.
|
|
27
27
|
- If file path is remote: Execute `!python <path>`.
|
|
28
28
|
- **Multi-Modal Output**: Handle `display_data` messages (e.g., `image/png`, `text/html`). For the CLI, we'll save images to temporary files and print their paths, or if the terminal supports it (e.g., iTerm2), inline them.
|
|
29
|
+
- **Timeout Configuration**: Exposes a `--timeout` flag (default 10s) to allow long-running silent tasks (like model compilation or data downloading) to execute without being prematurely killed.
|
|
29
30
|
|
|
30
31
|
### 3. Console (`colab console`)
|
|
31
32
|
- **Implementation**: Connects directly to the backend terminal endpoint (`/colab/tty`) via WebSockets using `websocket-client`.
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
log:
|
|
3
|
+
2026-06-01: Enabled `colab update --install` self-update on macOS in addition to Linux. Refactored platform check logic to keep the implementation DRY and updated both tests and documentation. Also, on these platforms, an additional message is shown recommending `colab update --install` to upgrade in place, positioned above the standard `pip`/`uv` installation command.
|
|
4
|
+
2026-05-29: Added default OAuth2 client config (`oauth_config.json`) as a bundled package resource and restored fallback loading logic in `get_credentials()`. The CLI now falls back to using these default credentials when no explicit local config is found. Added `integration/repro_bundled_oauth` integration test.
|
|
5
|
+
2026-05-27: Refactored `colab README` and `colab AGENT` to bundle `README.md` and `AGENTS.md` via Hatchling's `force-include` and read them using `importlib.resources` instead of `importlib.metadata`. `colab AGENT` now correctly prints `AGENTS.md`.
|
|
3
6
|
2026-05-27: Extended `colab update --install` to detect if the CLI was installed via `uv tool install` (by checking if `sys.executable` contains `/uv/`) and if so, use `uv tool install -U google-colab-cli` to upgrade.
|
|
4
7
|
2026-05-27: Updated auto-update upgrade hint to recommend `pip install --upgrade google-colab-cli` instead of `colab`, aligning with the PyPI package name.
|
|
5
8
|
2026-05-27: `colab url` now emits BOTH the `?dbu=<urlencoded path>` query parameter (existing) AND a new `#datalabBackendUrl=<full URL>` hash fragment (new). Format: `https://<host>/notebooks/empty.ipynb?dbu=%2Ftun%2Fm%2F<endpoint>#datalabBackendUrl=<host>/tun/m/<endpoint>`. Why both: some Colab frontend code paths consult the hash fragment first and ignore `dbu` entirely, so the previously-emitted query-only form failed silently for those users (the frontend fell through to allocating a fresh VM via `/tun/m/assign`). The fragment value is a FULL URL with scheme + host (NOT just the path) and is emitted RAW (no URL encoding) because browsers don't decode the fragment before passing `location.hash` to page JS — Colab's parser calls `new URL(rawString)` directly. The fragment host always matches `--host` so Colab's same-origin enforcement on embedded backend URLs doesn't block the connection, and sandbox/dev users (`--host https://colab.sandbox.google.com`) get a sandbox fragment automatically. Three new test cases in `tests/test_url.py` cover the raw-encoding requirement (`%3A`/`%2F` must NOT appear in the fragment), the both-signals-present invariant, and `--open` propagating the fragment to `webbrowser.open()`. Integration-verified live against synthetic session state with three host shapes (default, sandbox, trailing-slash); all produced correctly-shaped URLs with no `//` artifacts.
|
|
@@ -22,9 +25,9 @@ backend, selected via the global `--auth=<provider>` flag:
|
|
|
22
25
|
|
|
23
26
|
1. **`oauth2`** (default): Standard public InstalledAppFlow via
|
|
24
27
|
`google-auth-oauthlib`. Opens a browser for consent, caches the refresh
|
|
25
|
-
token at `~/.config/colab-cli/token.json`.
|
|
26
|
-
config at `~/.colab-cli-oauth-config.json
|
|
27
|
-
|
|
28
|
+
token at `~/.config/colab-cli/token.json`. If no local config is provided
|
|
29
|
+
via `-c/--client-oauth-config` or found at `~/.colab-cli-oauth-config.json`,
|
|
30
|
+
it falls back to a bundled `oauth_config.json` containing default OAuth credentials.
|
|
28
31
|
2. **`adc`**: Application Default Credentials via `google.auth.default()`.
|
|
29
32
|
Honors the standard ADC discovery chain
|
|
30
33
|
(`GOOGLE_APPLICATION_CREDENTIALS`, `gcloud auth application-default
|
|
@@ -184,10 +187,12 @@ remediation guidance) rather than silently after ~1 minute via the daemon.
|
|
|
184
187
|
the cache.
|
|
185
188
|
- **Notification**: If a new version is found, a non-intrusive message is
|
|
186
189
|
printed to the console with a `Run 'pip install --upgrade google-colab-cli' to
|
|
187
|
-
update.` hint.
|
|
188
|
-
`
|
|
190
|
+
update.` hint. On Linux and macOS platforms where `--install` self-update is supported,
|
|
191
|
+
an additional hint `You can run 'colab update --install' to upgrade in place.`
|
|
192
|
+
is displayed above the pip/uv install command. The cached banner shown between
|
|
193
|
+
fetches uses the generic `Run 'colab update' to update.` hint.
|
|
189
194
|
- **Self-install (`--install`)**: An opt-in `--install` flag (default
|
|
190
|
-
`False`) makes `colab update` upgrade the CLI in place (**Linux
|
|
195
|
+
`False`) makes `colab update` upgrade the CLI in place (**Linux and macOS**).
|
|
191
196
|
It detects how the CLI was installed:
|
|
192
197
|
- If `sys.executable` contains `/uv/tools` (indicating it was installed via
|
|
193
198
|
`uv tool install`), it runs `uv tool install -U google-colab-cli`.
|
|
@@ -241,6 +246,19 @@ remediation guidance) rather than silently after ~1 minute via the daemon.
|
|
|
241
246
|
- openid
|
|
242
247
|
```
|
|
243
248
|
|
|
249
|
+
### 9. README and AGENT (`colab README`, `colab AGENT`)
|
|
250
|
+
|
|
251
|
+
- **Action**: Print the bundled `README.md` or `AGENTS.md` file.
|
|
252
|
+
- **Implementation**:
|
|
253
|
+
- Uses `importlib.resources.files("colab_cli").joinpath(...)` to read the
|
|
254
|
+
bundled `README.md` (for `colab README`) or `AGENTS.md` (for `colab AGENT`)
|
|
255
|
+
from the package resources.
|
|
256
|
+
- The files are bundled into the package via Hatchling's `force-include`
|
|
257
|
+
configuration in `pyproject.toml`.
|
|
258
|
+
- If reading from resources fails (e.g. during development when not
|
|
259
|
+
installed), it falls back to reading the files from the project root.
|
|
260
|
+
- Prints the content to stdout.
|
|
261
|
+
|
|
244
262
|
## Implementation Details
|
|
245
263
|
|
|
246
264
|
- **Code Injection**: Use a standard `run_code(session, code)` helper via
|
|
@@ -286,3 +304,10 @@ TDD is mandatory for all automation features.
|
|
|
286
304
|
- **Test Case**: `creds.refresh()` is called before `creds.token` is read
|
|
287
305
|
(regression against silently-`None` tokens for service-account /
|
|
288
306
|
GCE-metadata creds).
|
|
307
|
+
|
|
308
|
+
### 4. `README` and `AGENT` Commands
|
|
309
|
+
|
|
310
|
+
- **Test Case**: Verify `colab README` prints the expected content when package metadata is available.
|
|
311
|
+
- **Test Case**: Verify `colab AGENT` prints the same content.
|
|
312
|
+
- **Test Case**: Verify fallback to local `README.md` file when metadata is not available.
|
|
313
|
+
- **Test Case**: Verify error exit when both metadata and local file are unavailable.
|
|
@@ -29,6 +29,7 @@ colab run [OPTIONS] SCRIPT [SCRIPT_ARGS]...
|
|
|
29
29
|
| `--gpu` | str | None | Same set as `colab new --gpu` (T4, L4, G4, H100, A100). |
|
|
30
30
|
| `--tpu` | str | None | Same set as `colab new --tpu` (v5e1, v6e1). |
|
|
31
31
|
| `--keep` | bool | False | Do **not** stop the session after the script finishes. |
|
|
32
|
+
| `--timeout` | float | 10.0 | Timeout in seconds for code execution to prevent hanging on silent tasks. |
|
|
32
33
|
|
|
33
34
|
### Shebang usage
|
|
34
35
|
With `--keep` and `--gpu` baked into the shebang line, an entire one-file workload becomes:
|
|
@@ -16,6 +16,8 @@ End-to-end tests that run against a **live Colab backend** (unlike the mocked un
|
|
|
16
16
|
| `repro_keep_alive_scope/` | Slow soak test (~95s): runs the daemon long enough for one ping past the pre-flight, asserts no `keep_alive_error` events. |
|
|
17
17
|
| `repro_variable_persistence/` | Variables persist across `colab exec` calls in the same session. |
|
|
18
18
|
| `repro_piped_console/` | Fast smoke test (~5s including session creation): `echo cmd \| colab console -s s` runs the command and exits within 30s. Regression test for the 2026-05-07 EOF-handler fix. |
|
|
19
|
+
| `repro_bundled_oauth/` | Fast smoke test (~5s): verifies that the fallback OAuth configuration is loaded and starts the OAuth flow with the default client ID when local config is missing. |
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
## Running
|
|
21
23
|
```bash
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Copyright 2026 Google LLC
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
# Integration Test: Fallback OAuth Configuration Verification
|
|
17
|
+
#
|
|
18
|
+
# This test verifies that the CLI correctly falls back to using the bundled
|
|
19
|
+
# oauth_config.json containing the default client ID when no local config is present.
|
|
20
|
+
# It simulates a fresh user flow by temporarily hiding existing tokens/configs,
|
|
21
|
+
# starting the OAuth flow, and asserting that the printed authorization URL
|
|
22
|
+
# contains the correct Client ID.
|
|
23
|
+
#
|
|
24
|
+
|
|
25
|
+
set -e
|
|
26
|
+
|
|
27
|
+
TOKEN_PATH="$HOME/.config/colab-cli/token.json"
|
|
28
|
+
CONFIG_PATH="$HOME/.colab-cli-oauth-config.json"
|
|
29
|
+
BACKUP_SUFFIX=".backup.$(date +%s)"
|
|
30
|
+
|
|
31
|
+
TOKEN_BACKUP=""
|
|
32
|
+
CONFIG_BACKUP=""
|
|
33
|
+
|
|
34
|
+
cleanup() {
|
|
35
|
+
echo "[*] Cleaning up backups..."
|
|
36
|
+
if [ -n "$TOKEN_BACKUP" ] && [ -f "$TOKEN_BACKUP" ]; then
|
|
37
|
+
mv "$TOKEN_BACKUP" "$TOKEN_PATH"
|
|
38
|
+
echo "[*] Restored token.json"
|
|
39
|
+
fi
|
|
40
|
+
if [ -n "$CONFIG_BACKUP" ] && [ -f "$CONFIG_BACKUP" ]; then
|
|
41
|
+
mv "$CONFIG_BACKUP" "$CONFIG_PATH"
|
|
42
|
+
echo "[*] Restored .colab-cli-oauth-config.json"
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
trap cleanup EXIT
|
|
46
|
+
|
|
47
|
+
# 1. Back up existing configuration files if they exist
|
|
48
|
+
if [ -f "$TOKEN_PATH" ]; then
|
|
49
|
+
TOKEN_BACKUP="${TOKEN_PATH}${BACKUP_SUFFIX}"
|
|
50
|
+
mv "$TOKEN_PATH" "$TOKEN_BACKUP"
|
|
51
|
+
echo "[*] Temporarily backed up token.json to $TOKEN_BACKUP"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ -f "$CONFIG_PATH" ]; then
|
|
55
|
+
CONFIG_BACKUP="${CONFIG_PATH}${BACKUP_SUFFIX}"
|
|
56
|
+
mv "$CONFIG_PATH" "$CONFIG_BACKUP"
|
|
57
|
+
echo "[*] Temporarily backed up .colab-cli-oauth-config.json to $CONFIG_BACKUP"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# 2. Run colab sessions command to trigger the OAuth flow
|
|
61
|
+
echo "[*] Running 'colab --auth=oauth2 sessions' (expecting to trigger browser flow)..."
|
|
62
|
+
# We expect the command to block waiting for authorization, so we run it with a timeout.
|
|
63
|
+
# We redirect output to a file so we can inspect it.
|
|
64
|
+
OUTPUT_LOG=$(mktemp)
|
|
65
|
+
set +e
|
|
66
|
+
PYTHONUNBUFFERED=1 timeout 5 uv run colab --auth=oauth2 sessions > "$OUTPUT_LOG" 2>&1
|
|
67
|
+
EXIT_CODE=$?
|
|
68
|
+
set -e
|
|
69
|
+
|
|
70
|
+
echo "[*] Command exited with code: $EXIT_CODE"
|
|
71
|
+
echo "----------------- CLI Output -----------------"
|
|
72
|
+
cat "$OUTPUT_LOG"
|
|
73
|
+
echo "----------------------------------------------"
|
|
74
|
+
|
|
75
|
+
# 3. Assertions
|
|
76
|
+
EXPECTED_CLIENT_ID="764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com"
|
|
77
|
+
|
|
78
|
+
# The command should have printed the authorization URL
|
|
79
|
+
if ! grep -q "Please visit this URL to authorize this application" "$OUTPUT_LOG"; then
|
|
80
|
+
echo "[FAILURE] OAuth prompt message not found in output."
|
|
81
|
+
rm -f "$OUTPUT_LOG"
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# The URL should contain the correct client ID
|
|
86
|
+
if ! grep -q "client_id=$EXPECTED_CLIENT_ID" "$OUTPUT_LOG"; then
|
|
87
|
+
echo "[FAILURE] Authorization URL does not contain the expected client ID: $EXPECTED_CLIENT_ID"
|
|
88
|
+
rm -f "$OUTPUT_LOG"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
echo "[SUCCESS] Verified that CLI correctly initiated OAuth flow with the fallback Client ID: $EXPECTED_CLIENT_ID"
|
|
93
|
+
rm -f "$OUTPUT_LOG"
|
|
@@ -34,6 +34,10 @@ source = "vcs"
|
|
|
34
34
|
[tool.hatch.build.targets.wheel]
|
|
35
35
|
packages = ["src/colab_cli"]
|
|
36
36
|
|
|
37
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
38
|
+
"README.md" = "colab_cli/README.md"
|
|
39
|
+
"COLAB_SKILL.md" = "colab_cli/COLAB_SKILL.md"
|
|
40
|
+
|
|
37
41
|
[tool.uv]
|
|
38
42
|
package = true
|
|
39
43
|
|
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
import enum
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
|
+
from importlib import resources
|
|
18
19
|
import os
|
|
19
20
|
import warnings
|
|
20
21
|
from typing import Optional
|
|
21
22
|
|
|
22
23
|
import google.auth
|
|
24
|
+
import typer
|
|
23
25
|
from google.auth.transport import requests
|
|
24
26
|
from google.auth.transport.requests import Request
|
|
25
27
|
from google.oauth2.credentials import Credentials
|
|
@@ -43,6 +45,7 @@ PUBLIC_SCOPES = [
|
|
|
43
45
|
"openid",
|
|
44
46
|
"https://www.googleapis.com/auth/userinfo.profile",
|
|
45
47
|
"https://www.googleapis.com/auth/userinfo.email",
|
|
48
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
46
49
|
"https://www.googleapis.com/auth/colaboratory",
|
|
47
50
|
"https://www.googleapis.com/auth/drive.file",
|
|
48
51
|
]
|
|
@@ -60,9 +63,18 @@ def _get_google_auth_credentials(config_path: str) -> Credentials:
|
|
|
60
63
|
if os.path.exists(config_path):
|
|
61
64
|
with open(config_path, "r") as f:
|
|
62
65
|
client_config = json.load(f)
|
|
66
|
+
else:
|
|
67
|
+
# Last resort: try inlined config
|
|
68
|
+
try:
|
|
69
|
+
config_resource = resources.files("colab_cli").joinpath("oauth_config.json")
|
|
70
|
+
if config_resource.is_file():
|
|
71
|
+
client_config = json.loads(config_resource.read_text())
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.debug(f"Failed to load inlined config: {e}")
|
|
74
|
+
|
|
63
75
|
if not client_config:
|
|
64
76
|
raise FileNotFoundError(
|
|
65
|
-
f"Client OAuth config not found at {config_path}. "
|
|
77
|
+
f"Client OAuth config not found at {config_path} and no inlined config available. "
|
|
66
78
|
"Please provide a valid path via -c/--client-oauth-config."
|
|
67
79
|
)
|
|
68
80
|
|
|
@@ -137,6 +149,34 @@ def _get_adc_credentials() -> Credentials:
|
|
|
137
149
|
category=UserWarning,
|
|
138
150
|
)
|
|
139
151
|
creds, _ = google.auth.default(scopes=list(PUBLIC_SCOPES))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if not creds.valid:
|
|
155
|
+
from google.auth import compute_engine
|
|
156
|
+
|
|
157
|
+
if isinstance(creds, compute_engine.Credentials):
|
|
158
|
+
creds = None
|
|
159
|
+
else:
|
|
160
|
+
logger.warning("Failed to obtain valid ADC credentials.")
|
|
161
|
+
try:
|
|
162
|
+
logger.warning("Trying to refresh ADC credentials")
|
|
163
|
+
creds.refresh(Request())
|
|
164
|
+
except Exception as e:
|
|
165
|
+
logger.warning(f"Failed to refresh token: {e}")
|
|
166
|
+
creds = None
|
|
167
|
+
|
|
168
|
+
if not creds:
|
|
169
|
+
typer.echo(
|
|
170
|
+
"No valid default credentials found. To authenticate, run:\n\n"
|
|
171
|
+
" gcloud auth application-default login \\\n"
|
|
172
|
+
" --scopes=openid,"
|
|
173
|
+
"https://www.googleapis.com/auth/cloud-platform,"
|
|
174
|
+
"https://www.googleapis.com/auth/userinfo.email,"
|
|
175
|
+
"https://www.googleapis.com/auth/colaboratory\n",
|
|
176
|
+
err=True,
|
|
177
|
+
)
|
|
178
|
+
exit(1)
|
|
179
|
+
|
|
140
180
|
# Some credential subclasses ignore the `scopes=` kwarg in `default()`
|
|
141
181
|
# (e.g. user creds), so re-apply via `with_scopes` when supported.
|
|
142
182
|
if getattr(creds, "requires_scopes", False):
|