datagrok-tools 6.2.5 → 6.2.6

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Datagrok-tools changelog
2
2
 
3
+ ## 6.2.6 (2026-05-26)
4
+
5
+ * `grok s tables upload` — accepts `.d42` binary blobs in addition to `.csv`. Content-Type is auto-detected from the file extension (`application/octet-stream` for d42, `text/csv` otherwise); server content-negotiates and persists either form against the same `/public/v1/tables/{name}` endpoint.
6
+
3
7
  ## 6.2.5 (2026-05-21)
4
8
 
5
9
  * `grok report read` — renamed `--extract-actions` to `--extract-client-log`; sidecar is now `<stem>_client_log.json`. The old flag is no longer accepted.
package/GROK_S.md CHANGED
@@ -27,7 +27,7 @@ browser or a logged-in session.
27
27
  | Run a registered function | `grok s functions run 'Pkg:fn(arg1,arg2)'` |
28
28
  | List functions with rich filters | `grok s functions list --type script --language python --package Chem` |
29
29
  | List / browse files in a file share | `grok s files list "System:AppData" -r` |
30
- | Upload / download a table (CSV) | `grok s tables upload <name> file.csv` / `tables download <name> -O out.csv` |
30
+ | Upload / download a table (CSV or d42) | `grok s tables upload <name> file.csv\|file.d42` / `tables download <name> -O out.csv` |
31
31
  | Check whether a package is deployed | `grok s packages list --filter "MyPlugin"` |
32
32
  | Hit any undocumented endpoint | `grok s raw GET /api/users/current` |
33
33
  | Check server + per-module health | `grok s healthcheck [--module <name>]` |
@@ -205,21 +205,26 @@ the `source` before sending).
205
205
 
206
206
  ## Tables
207
207
 
208
- CSV-level table I/O — the shell counterpart to Python's `grok.tables.upload/download`.
208
+ Table I/O — the shell counterpart to Python's `grok.tables.upload/download`.
209
209
  Unlike `files put`, this registers a proper Datagrok table entity (returns `{ID, ...}`).
210
210
 
211
211
  ```bash
212
212
  grok s tables upload MyTable ./data.csv # CSV → table
213
+ grok s tables upload MyTable ./data.d42 # d42 binary → table
213
214
  grok s tables upload MyTable ./data.csv --output json # get ID and markup back
214
215
  grok s tables download MyTable # CSV to stdout (pipe-friendly)
215
216
  grok s tables download MyTable -O ./data.csv # CSV to a local file
216
217
  grok s tables download <uuid> # UUID or namespace:name both work
217
218
  ```
218
219
 
219
- Upload streams raw bytes with `Content-Type: text/csv` so it handles large tables
220
- without loading the whole file into a JSON envelope. `-O` / `--output-file` avoids
221
- colliding with the format flag (`--output table|json|csv|quiet`), which still controls
222
- how the upload result is printed.
220
+ Upload streams raw bytes `Content-Type: text/csv` for `.csv` and
221
+ `application/octet-stream` for `.d42` (auto-detected from the file extension). Both
222
+ formats handle large tables without loading the whole file into a JSON envelope.
223
+ `-O` / `--output-file` avoids colliding with the format flag (`--output
224
+ table|json|csv|quiet`), which still controls how the upload result is printed.
225
+
226
+ Download is CSV-only — the server reads the stored d42 blob and converts. If you
227
+ need the raw d42 bytes, hit `/tables/data/<id>` directly via `grok s raw`.
223
228
 
224
229
  ## Server health
225
230
 
@@ -8,6 +8,7 @@ exports.parseFuncCall = parseFuncCall;
8
8
  exports.resolveManifestSources = resolveManifestSources;
9
9
  exports.server = server;
10
10
  var fs = _interopRequireWildcard(require("fs"));
11
+ var path = _interopRequireWildcard(require("path"));
11
12
  var _nodeDapi = require("../utils/node-dapi");
12
13
  var _serverClient = require("../utils/server-client");
13
14
  var _serverOutput = require("../utils/server-output");
@@ -169,14 +170,15 @@ async function handleTablesDownload(dapi, rest, argv, output) {
169
170
  async function handleTablesUpload(dapi, rest, output) {
170
171
  const [name, localPath] = rest;
171
172
  if (!name || !localPath) {
172
- (0, _serverOutput.printError)(new Error('Usage: grok s tables upload <name> <file.csv>'));
173
+ (0, _serverOutput.printError)(new Error('Usage: grok s tables upload <name> <file.csv|file.d42>'));
173
174
  return false;
174
175
  }
175
176
  if (!fs.existsSync(localPath)) {
176
177
  (0, _serverOutput.printError)(new Error(`Local file not found: ${localPath}`));
177
178
  return false;
178
179
  }
179
- const result = await dapi.tables.upload(name, localPath);
180
+ const ct = path.extname(localPath).toLowerCase() === '.d42' ? 'application/octet-stream' : 'text/csv';
181
+ const result = await dapi.tables.upload(name, localPath, ct);
180
182
  if (output === 'quiet') console.log(result?.ID ?? result?.id ?? '');else (0, _serverOutput.printOutput)(result, output);
181
183
  return true;
182
184
  }
@@ -611,7 +613,7 @@ Special commands:
611
613
  grok s groups list-memberships <group> [--admin] List parent groups
612
614
  grok s users block <id-or-login> Block a user from the platform
613
615
  grok s users unblock <id-or-login> Unblock a previously blocked user
614
- grok s tables upload <name> <file.csv> Upload a CSV as a Datagrok table
616
+ grok s tables upload <name> <file.csv|file.d42> Upload a CSV or d42 binary as a Datagrok table
615
617
  grok s tables download <name-or-id> [-O <file>] Download a table as CSV (stdout by default)
616
618
  grok s batch <entity> <verb> arg1 [arg2 ...] Batch operation (one round-trip)
617
619
  grok s batch <entity> <verb> --json params.json Batch from JSON array
@@ -502,12 +502,16 @@ class NodeTablesDataSource {
502
502
  return result;
503
503
  }
504
504
 
505
- /** POST /public/v1/tables/{name} with raw CSV bytes. Returns `{ID, Grok name, Markup, URL}`. */
506
- async upload(name, localPath) {
505
+ /**
506
+ * POST /public/v1/tables/{name} with raw bytes. Returns `{ID, Grok name, Markup, URL}`.
507
+ * Defaults to `text/csv`; pass `application/octet-stream` to upload a `.d42`
508
+ * binary blob — the server content-negotiates on the header and persists either form.
509
+ */
510
+ async upload(name, localPath, contentType = 'text/csv') {
507
511
  const fs = require('fs');
508
512
  const bytes = fs.readFileSync(localPath);
509
513
  const seg = encodeURIComponent(name.replace(/:/g, '.'));
510
- return this.client.putBytes(`/public/v1/tables/${seg}`, bytes, 'text/csv');
514
+ return this.client.putBytes(`/public/v1/tables/${seg}`, bytes, contentType);
511
515
  }
512
516
  }
513
517
  exports.NodeTablesDataSource = NodeTablesDataSource;
@@ -0,0 +1,67 @@
1
+ # tools/download-demo-datasets.R
2
+ #
3
+ # Выгружает три демо-датасета для ANOVA UI:
4
+ # - InsectSprays (R datasets package) → CSV
5
+ # - ToothGrowth (R datasets package) → CSV
6
+ # - SiRstv (NIST StRD) → CSV
7
+ #
8
+ # Запуск из корня репозитория:
9
+ # Rscript tools/download-demo-datasets.R
10
+ #
11
+ # Результат сохраняется в packages/EDA/demo-data/.
12
+
13
+ OUT_DIR <- "packages/EDA/demo-data"
14
+ dir.create(OUT_DIR, showWarnings = FALSE, recursive = TRUE)
15
+
16
+ # ─── 1. InsectSprays ──────────────────────────────────────────────────
17
+ data(InsectSprays)
18
+ write.csv(InsectSprays,
19
+ file.path(OUT_DIR, "insect-sprays.csv"),
20
+ row.names = FALSE,
21
+ fileEncoding = "UTF-8")
22
+ cat("Wrote insect-sprays.csv (", nrow(InsectSprays), "rows )\n")
23
+
24
+ # ─── 2. ToothGrowth ───────────────────────────────────────────────────
25
+ data(ToothGrowth)
26
+ write.csv(ToothGrowth,
27
+ file.path(OUT_DIR, "tooth-growth.csv"),
28
+ row.names = FALSE,
29
+ fileEncoding = "UTF-8")
30
+ cat("Wrote tooth-growth.csv (", nrow(ToothGrowth), "rows )\n")
31
+
32
+ # ─── 3. SiRstv (NIST StRD) ────────────────────────────────────────────
33
+ # NIST .dat файл имеет большой текстовый header; данные идут после
34
+ # строки "Data: Instrument Resistance" (заголовок встроен в маркер).
35
+ nist_url <- "https://www.itl.nist.gov/div898/strd/anova/SiRstv.dat"
36
+ # На Windows libcurl падает на NIST SSL (CRYPT_E_NO_REVOCATION_CHECK).
37
+ # wininet использует системный HTTP-стек и работает; на других ОС — стандартный путь.
38
+ read_nist <- function(u) {
39
+ if (.Platform$OS.type == "windows") {
40
+ tmp <- tempfile()
41
+ suppressWarnings(download.file(u, tmp, quiet = TRUE, method = "wininet"))
42
+ readLines(tmp)
43
+ } else {
44
+ readLines(url(u))
45
+ }
46
+ }
47
+ lines <- read_nist(nist_url)
48
+ data_start <- grep("^\\s*Data:\\s+Instrument", lines)
49
+ if (length(data_start) != 1)
50
+ stop("Cannot locate 'Data: Instrument' marker in SiRstv.dat")
51
+
52
+ # Пропустить только строку "Data:..." — следующая уже содержит данные.
53
+ data_lines <- lines[(data_start + 1):length(lines)]
54
+ data_lines <- data_lines[nzchar(trimws(data_lines))]
55
+
56
+ # В каждой строке два числа через whitespace: Instrument Resistance
57
+ sirstv <- read.table(text = data_lines,
58
+ col.names = c("Instrument", "Resistance"))
59
+ sirstv$Instrument <- as.integer(sirstv$Instrument)
60
+
61
+ write.csv(sirstv,
62
+ file.path(OUT_DIR, "silicon-resistivity.csv"),
63
+ row.names = FALSE,
64
+ fileEncoding = "UTF-8")
65
+ cat("Wrote silicon-resistivity.csv (", nrow(sirstv), "rows )\n")
66
+
67
+ cat("\nAll three demo datasets written to", OUT_DIR, "\n")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.2.5",
3
+ "version": "6.2.6",
4
4
  "description": "Utility to upload and publish packages to Datagrok",
5
5
  "homepage": "https://github.com/datagrok-ai/public/tree/master/tools#readme",
6
6
  "dependencies": {