Skip to content

Commit 02ada65

Browse files
rahim-bhojaniclaude
andcommitted
fix: address CLI UX feedback — file input, region hints, comment handling
- Add --file flag and stdin support to `dremio query run` so multi-line SQL no longer requires shell escaping (supports --file path, piped stdin, and '-' argument) - Enrich 401 errors with a region hint when the default US endpoint is used, saving EU users from a confusing debugging loop - Put breadcrumb comment on its own line so SQL with -- inline comments is no longer swallowed by the prepended comment - Show config file path and region info in `dremio setup --help` Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 39f8411 commit 02ada65

5 files changed

Lines changed: 40 additions & 4 deletions

File tree

src/drs/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ async def delete_project(self, project_id: str) -> dict:
164164

165165
async def submit_sql(self, sql: str, context: list[str] | None = None) -> dict:
166166
"""Submit a SQL query. Returns job metadata including job_id."""
167-
body: dict[str, Any] = {"sql": f"/* dremio-cli: submitter=cli */ {sql}"}
167+
body: dict[str, Any] = {"sql": f"/* dremio-cli: submitter=cli */\n{sql}"}
168168
if context:
169169
body["context"] = context
170170
return await self._post(self._v0("/sql"), json=body)

src/drs/commands/query.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from __future__ import annotations
1919

2020
import asyncio
21+
import sys
22+
from pathlib import Path
2123
from typing import Any
2224

2325
import httpx
@@ -131,7 +133,8 @@ async def _execute():
131133

132134
@app.command("run")
133135
def cli_run(
134-
sql: str = typer.Argument(help="SQL query to execute"),
136+
sql: str | None = typer.Argument(None, help="SQL query to execute (use '-' to read from stdin)"),
137+
file: Path | None = typer.Option(None, "--file", help="Path to a SQL file to execute"),
135138
context: str = typer.Option(None, help="Dot-separated default schema context (e.g., myspace.folder)"),
136139
fmt: OutputFormat = typer.Option(OutputFormat.json, "--output", "-o", help="Output format"),
137140
fields: str = typer.Option(
@@ -140,10 +143,37 @@ def cli_run(
140143
) -> None:
141144
"""Execute a SQL query, wait for completion, and return results.
142145
146+
SQL can be provided as:
147+
148+
dremio query run "SELECT 1" # inline argument
149+
150+
dremio query run --file query.sql # from a file
151+
152+
cat query.sql | dremio query run - # from stdin
153+
143154
Submits the query, polls until the job completes, then fetches all result
144155
rows. For long-running queries, use 'drs query run' to submit and
145156
'drs query status' to check progress separately.
146157
"""
158+
# Resolve SQL from argument, --file, or stdin
159+
if file and sql:
160+
error("Cannot specify both a SQL argument and --file.")
161+
raise typer.Exit(1)
162+
if file:
163+
if not file.exists():
164+
error(f"File not found: {file}")
165+
raise typer.Exit(1)
166+
sql = file.read_text()
167+
elif sql == "-" or (sql is None and not sys.stdin.isatty()):
168+
sql = sys.stdin.read()
169+
elif sql is None:
170+
error("Provide a SQL query as an argument, --file path, or pipe via stdin (use '-' for stdin).")
171+
raise typer.Exit(1)
172+
173+
if not sql.strip():
174+
error("SQL query is empty.")
175+
raise typer.Exit(1)
176+
147177
client = _get_client()
148178
ctx = context.split(".") if context else None
149179

src/drs/commands/setup.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ def _prompt_project_id(app_url: str) -> str:
147147
def setup_command(
148148
ctx: typer.Context,
149149
) -> None:
150-
"""Interactive setup wizard — configure credentials for Dremio Cloud."""
150+
"""Interactive setup wizard — configure credentials for Dremio Cloud.
151+
152+
Writes configuration to ~/.config/dremioai/config.yaml (or the path
153+
specified with --config). Prompts for region (US/EU), PAT, and project ID.
154+
"""
151155
if not sys.stdin.isatty():
152156
err_console.print(
153157
"[bold]dremio setup[/bold] requires an interactive terminal.\n\n"

src/drs/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ def handle_api_error(exc: httpx.HTTPStatusError) -> DremioAPIError:
202202

203203
if status == 401:
204204
hint = "Authentication failed — check your PAT token"
205+
if "api.dremio.cloud" in url and "api.eu.dremio.cloud" not in url:
206+
hint += ". If you are on Dremio Cloud EU, set uri: https://api.eu.dremio.cloud in your config"
205207
elif status == 403:
206208
hint = "Permission denied — insufficient privileges for this operation"
207209
elif status == 404:

tests/test_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ async def _capture(request: httpx.Request) -> httpx.Response:
119119

120120
await client.submit_sql("SELECT 1")
121121

122-
assert captured["body"]["sql"] == "/* dremio-cli: submitter=cli */ SELECT 1"
122+
assert captured["body"]["sql"] == "/* dremio-cli: submitter=cli */\nSELECT 1"
123123

124124
@pytest.mark.asyncio
125125
async def test_submit_sql_breadcrumb_with_context(self, client: DremioClient) -> None:

0 commit comments

Comments
 (0)