datagrok-tools 6.3.1 → 6.3.3

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,7 +1,12 @@
1
1
  # Datagrok-tools changelog
2
2
 
3
- ## 6.3.1 (WIP)
3
+ ## 6.3.3 (2026-06-16)
4
4
 
5
+ * Fixed Celery Docker image generation — the image wasn't built locally on publish.
6
+
7
+ ## 6.3.2 (2026-06-15)
8
+
9
+ * `func-gen` webpack plugin — generated RichFunctionView model inputs now use the script-form names (argument bounds/step `_t0`/`_t1`/`_h`, loop count `_count`) instead of the deprefixed forms, so the run, fitting, and sensitivity-analysis paths share one set of input names with diff-grok's pipeline. Fixes `Inconsistent inputs: "_t0" is missing` when starting fitting/SA from a Rich Function View.
5
10
  * `func-gen` webpack plugin — the generated RichFunctionView model output annotation appends the `DiffStudio Facet` viewer (last), alongside Grid and Line chart.
6
11
  * `grok stresstest` — run the ApiTests Node test runner directly via tsx (`src/package-test-node.ts`) instead of a compiled `dist-node` bundle; dropped the obsolete `npm run build-node` step and the `tsconfig-paths-bootstrap.js` / `dist-node` invocation.
7
12
 
@@ -8,6 +8,7 @@ exports.generateCeleryArtifacts = generateCeleryArtifacts;
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
  var _path = _interopRequireDefault(require("path"));
10
10
  var color = _interopRequireWildcard(require("./color-utils"));
11
+ var _utils = require("./utils");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  // Header tags recognized in Python function metadata comments (ported from ScriptParser.headerTags)
13
14
  const headerTags = ['name', 'description', 'help-url', 'input', 'output', 'tags', 'sample', 'language', 'endpoint', 'requiresServer', 'param-csrfmiddlewaretoken', 'returns', 'test', 'sidebar', 'condition', 'top-menu', 'environment', 'require', 'editor-for', 'schedule', 'schedule.runAs', 'reference', 'editor'];
@@ -191,13 +192,16 @@ function copyDirContents(src, dest) {
191
192
  function useConda(dir) {
192
193
  return _fs.default.existsSync(_path.default.join(dir, 'environment.yaml')) || _fs.default.existsSync(_path.default.join(dir, 'environment.yml'));
193
194
  }
194
- function deployFolder(packageDir, folderPath, dirName) {
195
+
196
+ // `dockerSubfolder` is the dockerfiles/ subdirectory name; the published image is
197
+ // `<base>-<dockerSubfolder>` (see publish.discoverDockerfiles).
198
+ function deployFolder(packageDir, folderPath, dockerSubfolder, base) {
195
199
  const tasks = scanPythonFunctions(folderPath, folderPath);
196
200
  if (tasks.length === 0) {
197
- color.log(`No annotated Python functions found in ${dirName}`);
201
+ color.log(`No annotated Python functions found in ${dockerSubfolder}`);
198
202
  return false;
199
203
  }
200
- const dockerfilesDir = _path.default.join(packageDir, 'dockerfiles', dirName);
204
+ const dockerfilesDir = _path.default.join(packageDir, 'dockerfiles', dockerSubfolder);
201
205
  _fs.default.mkdirSync(dockerfilesDir, {
202
206
  recursive: true
203
207
  });
@@ -211,8 +215,9 @@ function deployFolder(packageDir, folderPath, dirName) {
211
215
  tasks
212
216
  }, null, 2));
213
217
 
214
- // Generate Celery entry point
215
- const celeryName = dirName.replace(/-/g, '_');
218
+ // Entry point file name must equal $DATAGROK_CELERY_NAME (the image name, '-' -> '_'),
219
+ // so `celery -A $DATAGROK_CELERY_NAME` resolves it.
220
+ const celeryName = `${base}-${dockerSubfolder}`.replace(/-/g, '_');
216
221
  _fs.default.writeFileSync(_path.default.join(dockerfilesDir, celeryName + '.py'), TEMPLATE_PYTHON_ENTRY);
217
222
 
218
223
  // Copy Python source files
@@ -222,26 +227,27 @@ function deployFolder(packageDir, folderPath, dirName) {
222
227
  const containerJsonSrc = _path.default.join(folderPath, 'container.json');
223
228
  const containerJsonDest = _path.default.join(dockerfilesDir, 'container.json');
224
229
  if (_fs.default.existsSync(containerJsonSrc) && !_fs.default.existsSync(containerJsonDest)) _fs.default.copyFileSync(containerJsonSrc, containerJsonDest);
225
- color.log(`Generated Celery Docker artifacts in dockerfiles/${dirName}/`);
230
+ color.log(`Generated Celery Docker artifacts in dockerfiles/${dockerSubfolder}/`);
226
231
  return true;
227
232
  }
228
233
  function generateCeleryArtifacts(packageDir) {
229
234
  const pythonDir = _path.default.join(packageDir, 'python');
230
235
  if (!_fs.default.existsSync(pythonDir)) return false;
236
+ const packageJson = JSON.parse(_fs.default.readFileSync(_path.default.join(packageDir, 'package.json'), 'utf-8'));
237
+ const base = (0, _utils.removeScope)(packageJson.name).toLowerCase();
231
238
  const entries = _fs.default.readdirSync(pythonDir, {
232
239
  withFileTypes: true
233
240
  });
234
- const isNested = entries.length > 0 && entries.every(e => e.isDirectory);
241
+ const isNested = entries.length > 0 && entries.every(e => e.isDirectory());
235
242
  let generated = false;
236
243
  if (isNested) {
237
244
  for (const entry of entries) {
238
245
  if (!entry.isDirectory()) continue;
239
246
  const folderPath = _path.default.join(pythonDir, entry.name);
240
- if (deployFolder(packageDir, folderPath, entry.name)) generated = true;
247
+ if (deployFolder(packageDir, folderPath, `${entry.name.toLowerCase()}-celery`, base)) generated = true;
241
248
  }
242
249
  } else {
243
- const dirName = _path.default.basename(packageDir).toLowerCase();
244
- if (deployFolder(packageDir, pythonDir, dirName)) generated = true;
250
+ if (deployFolder(packageDir, pythonDir, 'celery', base)) generated = true;
245
251
  }
246
252
  return generated;
247
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.3.1",
3
+ "version": "6.3.3",
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": {
@@ -48,20 +48,19 @@ function preparseIvpModel(parser, text) {
48
48
  }
49
49
  if (!ivp || !ivp.name) return null;
50
50
 
51
- // User-facing input names carry no `_` prefix, so that `propagateChoice` lookups can map their
52
- // dataframe columns to inputs by exact name. `scriptKey` is the name the generated DiffStudio
53
- // script expects (arg bounds/step and the loop count are `_`-prefixed there) and is used only
54
- // when forwarding values to `runDiffStudioModel`.
51
+ // Input names use the script-form names (arg bounds/step `_`-prefixed, loop count `_count`) so the
52
+ // run path, the diff-grok fitting/SA pipeline, and `propagateChoice` lookups all agree on one set
53
+ // of names. `scriptKey` mirrors `name`; it is kept only for the value-forwarding map below.
55
54
  const mk = (type, name, scriptKey, input) =>
56
55
  ({tsType: 'number', name, scriptKey,
57
56
  annotation: `//input: ${type} ${name} = ${input.value} ${input.annot ?? ''}`.trim()});
58
57
 
59
58
  const inputs = [];
60
59
  const a = ivp.arg.name;
61
- if (ivp.loop) inputs.push(mk('int', 'count', '_count', ivp.loop.count));
62
- inputs.push(mk('double', `${a}0`, `_${a}0`, ivp.arg.initial));
63
- inputs.push(mk('double', `${a}1`, `_${a}1`, ivp.arg.final));
64
- inputs.push(mk('double', 'h', '_h', ivp.arg.step));
60
+ if (ivp.loop) inputs.push(mk('int', '_count', '_count', ivp.loop.count));
61
+ inputs.push(mk('double', `_${a}0`, `_${a}0`, ivp.arg.initial));
62
+ inputs.push(mk('double', `_${a}1`, `_${a}1`, ivp.arg.final));
63
+ inputs.push(mk('double', '_h', '_h', ivp.arg.step));
65
64
  for (const [k, v] of ivp.inits) inputs.push(mk('double', k, k, v));
66
65
  if (ivp.params) for (const [k, v] of ivp.params) inputs.push(mk('double', k, k, v));
67
66