duckhaven-cli 0.3.0__tar.gz → 0.4.0__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.
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/CHANGELOG.md +11 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/PKG-INFO +9 -1
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/README.md +8 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/_version.py +2 -2
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/query.py +1 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/execute.py +17 -4
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/repl.py +1 -1
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/.gitignore +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/LICENSE +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/pyproject.toml +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/__init__.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/__init__.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/admin.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/api.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/auth.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/catalog.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/dbt.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/grant.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/health.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/profile.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/saved.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/commands/session.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/config.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/context.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/errors.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/introspect.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/main.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/output/__init__.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/resolve.py +0 -0
- {duckhaven_cli-0.3.0 → duckhaven_cli-0.4.0}/src/dh/rest.py +0 -0
|
@@ -6,6 +6,17 @@ All notable changes to `duckhaven-cli` are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `dh sql` and the REPL ask the server to hold the submit for up to two seconds, so a quick
|
|
14
|
+
query finishes in one request instead of a submit and a poll. `--no-wait` still returns at
|
|
15
|
+
once. A server that predates the hold ignores it.
|
|
16
|
+
- Ready for DuckHaven `api_version` 3: `DECIMAL` and wide integers, which it sends as
|
|
17
|
+
strings, print as before in table and CSV output and stay exact strings with
|
|
18
|
+
`--format json`.
|
|
19
|
+
|
|
9
20
|
## [0.3.0] - 2026-10-13
|
|
10
21
|
|
|
11
22
|
Brings the CLI up to date with the DuckHaven server's result cache, DuckLake catalogs,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: duckhaven-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: dh — the command-line interface for DuckHaven
|
|
5
5
|
Project-URL: Homepage, https://github.com/tamasmrtn/duckhaven-clients
|
|
6
6
|
Project-URL: Source, https://github.com/tamasmrtn/duckhaven-clients
|
|
@@ -77,6 +77,14 @@ maintenance recommendations (`dh admin maintenance recommendations|apply`), and
|
|
|
77
77
|
private editor tabs (`dh worksheet`). Against an older server these commands answer with the
|
|
78
78
|
server's own not-found or validation error.
|
|
79
79
|
|
|
80
|
+
## Exact numbers
|
|
81
|
+
|
|
82
|
+
A DuckHaven with `api_version` 3 or later sends `DECIMAL` values and 64-bit-or-wider integers
|
|
83
|
+
(`BIGINT`, `HUGEINT`, `count(*)`) as strings, because JSON numbers lose precision past about
|
|
84
|
+
16 digits. `dh` prints them exactly as before in table and CSV output. With `--format json`
|
|
85
|
+
they stay strings (`"12.50"`, `"9007199254740993"`), exact. Scripts reading `dh` JSON should
|
|
86
|
+
convert those columns themselves rather than expect JSON numbers.
|
|
87
|
+
|
|
80
88
|
## Documentation
|
|
81
89
|
|
|
82
90
|
- [Command-line quickstart](https://tamasmrtn.github.io/duckhaven/getting-started/cli-quickstart/) — install, sign in,
|
|
@@ -48,6 +48,14 @@ maintenance recommendations (`dh admin maintenance recommendations|apply`), and
|
|
|
48
48
|
private editor tabs (`dh worksheet`). Against an older server these commands answer with the
|
|
49
49
|
server's own not-found or validation error.
|
|
50
50
|
|
|
51
|
+
## Exact numbers
|
|
52
|
+
|
|
53
|
+
A DuckHaven with `api_version` 3 or later sends `DECIMAL` values and 64-bit-or-wider integers
|
|
54
|
+
(`BIGINT`, `HUGEINT`, `count(*)`) as strings, because JSON numbers lose precision past about
|
|
55
|
+
16 digits. `dh` prints them exactly as before in table and CSV output. With `--format json`
|
|
56
|
+
they stay strings (`"12.50"`, `"9007199254740993"`), exact. Scripts reading `dh` JSON should
|
|
57
|
+
convert those columns themselves rather than expect JSON numbers.
|
|
58
|
+
|
|
51
59
|
## Documentation
|
|
52
60
|
|
|
53
61
|
- [Command-line quickstart](https://tamasmrtn.github.io/duckhaven/getting-started/cli-quickstart/) — install, sign in,
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.4.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 4, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""One-shot query execution: submit, wait, fetch.
|
|
2
2
|
|
|
3
|
-
`POST /workspaces/{workspace}/queries`
|
|
4
|
-
|
|
3
|
+
`POST /workspaces/{workspace}/queries` holds the call briefly for the run to finish
|
|
4
|
+
and otherwise answers **202** with a query still running, which the caller polls.
|
|
5
|
+
This is that loop, done once and correctly.
|
|
5
6
|
|
|
6
7
|
It is deliberately not the connector's code path. `duckhaven-sql-connector`
|
|
7
8
|
speaks the *session* API (`connect()` opens one), and sessions are disabled by
|
|
@@ -34,6 +35,11 @@ _MAX_DELAY = 2.0
|
|
|
34
35
|
#: above still paces the loop. Well under the client's socket timeout.
|
|
35
36
|
_HOLD_S = 5.0
|
|
36
37
|
|
|
38
|
+
#: How long the submit itself asks the server to hold for a finish. Shorter than
|
|
39
|
+
#: `_HOLD_S`: until the submit answers, the query's id is unknown, so a Ctrl-C in
|
|
40
|
+
#: this window cannot cancel the query the way one during polling does.
|
|
41
|
+
_SUBMIT_HOLD_S = 2.0
|
|
42
|
+
|
|
37
43
|
#: The server caps `limit` here; asking for more is rejected, not truncated.
|
|
38
44
|
_MAX_PAGE = 1000
|
|
39
45
|
|
|
@@ -62,13 +68,20 @@ def submit(
|
|
|
62
68
|
timeout_s: float | None = None,
|
|
63
69
|
saved_query_id: str | None = None,
|
|
64
70
|
use_cache: bool | None = None,
|
|
71
|
+
hold: bool = True,
|
|
65
72
|
) -> dict[str, Any]:
|
|
66
73
|
"""Hand the SQL to the server. Returns the accepted query.
|
|
67
74
|
|
|
68
|
-
|
|
69
|
-
`
|
|
75
|
+
Already `done` when it finished within the hold or was answered from the result
|
|
76
|
+
cache; otherwise still running, for `wait` to follow. `use_cache=False` always
|
|
77
|
+
executes it. `hold=False` answers at once, for a caller that will not wait.
|
|
70
78
|
"""
|
|
71
79
|
body: dict[str, Any] = {"sql": sql}
|
|
80
|
+
if hold:
|
|
81
|
+
# A query that finishes inside the hold comes back done on this call, with
|
|
82
|
+
# nothing to poll. A server too old to know the field ignores it and
|
|
83
|
+
# answers 202 at once, as before.
|
|
84
|
+
body["wait_timeout_s"] = _SUBMIT_HOLD_S
|
|
72
85
|
if agent:
|
|
73
86
|
body["agent_id"] = agent
|
|
74
87
|
if catalog:
|
|
@@ -144,7 +144,7 @@ def _run_one_shot(cli, settings, sql: str, agent: str | None) -> None:
|
|
|
144
144
|
agent=chosen,
|
|
145
145
|
catalog=settings.get("catalog"),
|
|
146
146
|
)
|
|
147
|
-
finished = execute.wait(client, submitted["id"], timeout=1200)
|
|
147
|
+
finished = execute.wait(client, submitted["id"], timeout=1200, known=submitted)
|
|
148
148
|
execute.raise_for_status(finished)
|
|
149
149
|
page = execute.fetch_rows(client, finished["id"])
|
|
150
150
|
cli.emit({"columns": page["columns"], "rows": page["rows"], "total": page["total"]})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|