jupyterlab-ipyflow 0.0.154 → 0.0.156

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.
Files changed (2) hide show
  1. package/lib/index.js +97 -50
  2. package/package.json +12 -9
package/lib/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ICommandPalette } from '@jupyterlab/apputils';
2
2
  import { CodeCell } from '@jupyterlab/cells';
3
3
  import { INotebookTracker } from '@jupyterlab/notebook';
4
+ import _ from 'lodash';
4
5
  const IPYFLOW_KERNEL_NAME = 'ipyflow';
5
6
  const waitingClass = 'waiting-cell';
6
7
  const readyClass = 'ready-cell';
@@ -9,7 +10,7 @@ const readyMakingInputClass = 'ready-making-input-cell';
9
10
  const linkedWaitingClass = 'linked-waiting';
10
11
  const linkedReadyMakerClass = 'linked-ready-maker';
11
12
  // ipyflow frontend state
12
- let dirtyCells = new Set();
13
+ const dirtyCells = new Set();
13
14
  let waitingCells = new Set();
14
15
  let readyCells = new Set();
15
16
  let waiterLinks = {};
@@ -22,6 +23,7 @@ let orderIdxById = {};
22
23
  let cellPendingExecution = null;
23
24
  let lastExecutionMode = null;
24
25
  let isReactivelyExecuting = false;
26
+ let isAltModeExecuting = false;
25
27
  let lastExecutionHighlights = null;
26
28
  let executedReactiveReadyCells = new Set();
27
29
  let newReadyCells = new Set();
@@ -41,19 +43,22 @@ const extension = {
41
43
  isVisible: () => true,
42
44
  isToggled: () => false,
43
45
  execute: () => {
44
- if (notebooks.activeCell.model.type === 'code') {
46
+ if (!isAltModeExecuting && notebooks.activeCell.model.type === 'code') {
47
+ isAltModeExecuting = true;
45
48
  const session = notebooks.currentWidget.sessionContext;
46
49
  if (session.isReady && notebooks.activeCell.model.type === 'code') {
47
- session.session.kernel.requestExecute({
50
+ session.session.kernel
51
+ .requestExecute({
48
52
  code: '%flow toggle-reactivity-until-next-reset',
49
53
  silent: true,
50
54
  store_history: false,
51
- }).done.then(() => {
55
+ })
56
+ .done.then(() => {
52
57
  CodeCell.execute(notebooks.activeCell, session);
53
58
  });
54
59
  }
55
60
  }
56
- }
61
+ },
57
62
  });
58
63
  app.commands.addKeyBinding({
59
64
  command: 'alt-mode-execute',
@@ -76,15 +81,20 @@ const extension = {
76
81
  clearCellState(nbPanel.content);
77
82
  activeCell = nbPanel.content.activeCell;
78
83
  activeCellId = nbPanel.content.activeCell.model.id;
79
- let commDisconnectHandler = () => { };
84
+ let commDisconnectHandler = function () {
85
+ // do nothing if not connected.
86
+ };
80
87
  if (session.session.kernel.name === IPYFLOW_KERNEL_NAME) {
81
88
  commDisconnectHandler = connectToComm(session, nbPanel.content);
82
89
  }
83
90
  session.kernelChanged.connect((_, args) => {
84
91
  clearCellState(nbPanel.content);
85
92
  commDisconnectHandler();
86
- commDisconnectHandler = () => { };
87
- if (args.newValue !== null && args.newValue.name === IPYFLOW_KERNEL_NAME) {
93
+ commDisconnectHandler = function () {
94
+ // do nothing if not connected.
95
+ };
96
+ if (args.newValue !== null &&
97
+ args.newValue.name === IPYFLOW_KERNEL_NAME) {
88
98
  commDisconnectHandler = connectToComm(session, nbPanel.content);
89
99
  }
90
100
  });
@@ -98,7 +108,9 @@ const extension = {
98
108
  session.ready.then(() => {
99
109
  clearCellState(nbPanel.content);
100
110
  commDisconnectHandler();
101
- commDisconnectHandler = () => { };
111
+ commDisconnectHandler = function () {
112
+ // do nothing if not connected.
113
+ };
102
114
  if (session.session.kernel.name === IPYFLOW_KERNEL_NAME) {
103
115
  commDisconnectHandler = connectToComm(session, nbPanel.content);
104
116
  }
@@ -107,7 +119,7 @@ const extension = {
107
119
  });
108
120
  });
109
121
  });
110
- }
122
+ },
111
123
  };
112
124
  const getJpInputCollapser = (elem) => {
113
125
  if (elem === null || elem === undefined) {
@@ -206,6 +218,35 @@ const addUnsafeCellInteraction = (elem, linkedElems, cellsById, collapserFun, ev
206
218
  const connectToComm = (session, notebook) => {
207
219
  const comm = session.session.kernel.createComm('ipyflow');
208
220
  let disconnected = false;
221
+ const gatherCellMetadataAndContent = () => {
222
+ const cell_metadata_by_id = {};
223
+ notebook.widgets.forEach((itercell, idx) => {
224
+ cell_metadata_by_id[itercell.model.id] = {
225
+ index: idx,
226
+ content: itercell.model.value.text,
227
+ type: itercell.model.type,
228
+ };
229
+ });
230
+ return cell_metadata_by_id;
231
+ };
232
+ const onContentChanged = _.debounce(() => {
233
+ if (disconnected) {
234
+ notebook.model.contentChanged.disconnect(onContentChanged);
235
+ return;
236
+ }
237
+ comm.send({
238
+ type: 'notify_content_changed',
239
+ cell_metadata_by_id: gatherCellMetadataAndContent(),
240
+ });
241
+ }, 500);
242
+ const requestComputeExecSchedule = (cell) => {
243
+ const cell_metadata_by_id = gatherCellMetadataAndContent();
244
+ comm.send({
245
+ type: 'compute_exec_schedule',
246
+ executed_cell_id: cell === null || cell === void 0 ? void 0 : cell.id,
247
+ cell_metadata_by_id,
248
+ });
249
+ };
209
250
  const onExecution = (cell, args) => {
210
251
  if (disconnected) {
211
252
  cell.stateChanged.disconnect(onExecution);
@@ -214,23 +255,13 @@ const connectToComm = (session, notebook) => {
214
255
  if (args.name !== 'executionCount' || args.newValue === null) {
215
256
  return;
216
257
  }
217
- const cell_metadata_by_id = {};
218
258
  notebook.widgets.forEach((itercell, idx) => {
219
- cell_metadata_by_id[itercell.model.id] = {
220
- index: idx,
221
- content: itercell.model.value.text,
222
- type: itercell.model.type,
223
- };
224
259
  if (itercell.model.id === cell.id) {
225
260
  itercell.node.classList.remove(readyClass);
226
261
  itercell.node.classList.remove(readyMakingInputClass);
227
262
  }
228
263
  });
229
- comm.send({
230
- type: 'compute_exec_schedule',
231
- executed_cell_id: cell.id,
232
- cell_metadata_by_id,
233
- });
264
+ requestComputeExecSchedule(cell);
234
265
  };
235
266
  const notifyActiveCell = (newActiveCell) => {
236
267
  let newActiveCellOrderIdx = -1;
@@ -242,7 +273,7 @@ const connectToComm = (session, notebook) => {
242
273
  const payload = {
243
274
  type: 'change_active_cell',
244
275
  active_cell_id: newActiveCell.id,
245
- active_cell_order_idx: newActiveCellOrderIdx
276
+ active_cell_order_idx: newActiveCellOrderIdx,
246
277
  };
247
278
  comm.send(payload);
248
279
  };
@@ -266,7 +297,9 @@ const connectToComm = (session, notebook) => {
266
297
  }
267
298
  activeCell = cell;
268
299
  activeCellId = cell.model.id;
269
- if (activeCell === null || activeCell.model === null || activeCell.model.type !== "code") {
300
+ if (activeCell === null ||
301
+ activeCell.model === null ||
302
+ activeCell.model.type !== 'code') {
270
303
  return;
271
304
  }
272
305
  activeCell.model.stateChanged.connect(onExecution);
@@ -285,10 +318,11 @@ const connectToComm = (session, notebook) => {
285
318
  {
286
319
  action: 'mouseover',
287
320
  update: 'add',
288
- }, {
321
+ },
322
+ {
289
323
  action: 'mouseout',
290
324
  update: 'remove',
291
- }
325
+ },
292
326
  ];
293
327
  const updateOneCellUI = (id) => {
294
328
  const model = cellModelsById[id];
@@ -308,21 +342,19 @@ const connectToComm = (session, notebook) => {
308
342
  }
309
343
  else if (readyCells.has(id)) {
310
344
  elem.classList.add(readyMakingInputClass);
311
- if (lastExecutionMode === 'normal') {
312
- elem.classList.add(readyClass);
313
- addWaitingOutputInteractions(elem, linkedReadyMakerClass);
314
- }
345
+ elem.classList.add(readyClass);
346
+ addWaitingOutputInteractions(elem, linkedReadyMakerClass);
315
347
  }
316
348
  if (lastExecutionMode === 'reactive') {
317
349
  return;
318
350
  }
319
- if (waiterLinks.hasOwnProperty(id)) {
351
+ if (Object.prototype.hasOwnProperty.call(waiterLinks, id)) {
320
352
  actionUpdatePairs.forEach(({ action, update }) => {
321
353
  addUnsafeCellInteraction(getJpInputCollapser(elem), waiterLinks[id], cellsById, getJpInputCollapser, action, update, waitingCells);
322
354
  addUnsafeCellInteraction(getJpOutputCollapser(elem), waiterLinks[id], cellsById, getJpInputCollapser, action, update, waitingCells);
323
355
  });
324
356
  }
325
- if (readyMakerLinks.hasOwnProperty(id)) {
357
+ if (Object.prototype.hasOwnProperty.call(readyMakerLinks, id)) {
326
358
  if (!waitingCells.has(id)) {
327
359
  elem.classList.add(readyMakingClass);
328
360
  elem.classList.add(readyClass);
@@ -344,45 +376,58 @@ const connectToComm = (session, notebook) => {
344
376
  }
345
377
  };
346
378
  comm.onMsg = (msg) => {
347
- if (disconnected) {
379
+ var _a;
380
+ const payload = msg.content.data;
381
+ if (disconnected || !((_a = payload.success) !== null && _a !== void 0 ? _a : false)) {
348
382
  return;
349
383
  }
350
- if (msg.content.data['type'] === 'establish') {
384
+ if (payload.type === 'establish') {
351
385
  notebook.activeCell.model.stateChanged.connect(onExecution);
352
386
  notifyActiveCell(notebook.activeCell.model);
387
+ notebook.model.contentChanged.connect(onContentChanged);
388
+ requestComputeExecSchedule();
353
389
  }
354
- else if (msg.content.data['type'] === 'compute_exec_schedule') {
355
- waitingCells = new Set(msg.content.data['waiting_cells']);
356
- readyCells = new Set(msg.content.data['ready_cells']);
390
+ else if (payload.type === 'compute_exec_schedule') {
391
+ waitingCells = new Set(payload.waiting_cells);
392
+ readyCells = new Set(payload.ready_cells);
357
393
  newReadyCells = new Set([
358
394
  ...newReadyCells,
359
- ...msg.content.data['new_ready_cells'],
395
+ ...payload.new_ready_cells,
360
396
  ]);
361
397
  forcedReactiveCells = new Set([
362
398
  ...forcedReactiveCells,
363
- ...msg.content.data['forced_reactive_cells'],
399
+ ...payload.forced_reactive_cells,
364
400
  ]);
365
- waiterLinks = msg.content.data['waiter_links'];
366
- readyMakerLinks = msg.content.data['ready_maker_links'];
401
+ waiterLinks = payload.waiter_links;
402
+ readyMakerLinks = payload.ready_maker_links;
367
403
  cellPendingExecution = null;
368
- const exec_mode = msg.content.data['exec_mode'];
369
- isReactivelyExecuting = isReactivelyExecuting || (exec_mode === 'reactive');
370
- const flow_order = msg.content.data['flow_order'];
371
- const exec_schedule = msg.content.data['exec_schedule'];
404
+ const exec_mode = payload.exec_mode;
405
+ isReactivelyExecuting = isReactivelyExecuting || exec_mode === 'reactive';
406
+ const flow_order = payload.flow_order;
407
+ const exec_schedule = payload.exec_schedule;
372
408
  lastExecutionMode = exec_mode;
373
- lastExecutionHighlights = msg.content.data['highlights'];
374
- const lastExecutedCellId = msg.content.data['last_executed_cell_id'];
409
+ lastExecutionHighlights = payload.highlights;
410
+ const lastExecutedCellId = payload.last_executed_cell_id;
375
411
  executedReactiveReadyCells.add(lastExecutedCellId);
376
- const last_execution_was_error = msg.content.data['last_execution_was_error'];
412
+ const last_execution_was_error = payload.last_execution_was_error;
377
413
  if (!last_execution_was_error) {
414
+ let lastExecutedCellIdSeen = false;
378
415
  for (const cell of notebook.widgets) {
379
- if (cell.model.type !== 'code' || executedReactiveReadyCells.has(cell.model.id)) {
416
+ if (!lastExecutedCellIdSeen) {
417
+ lastExecutedCellIdSeen = cell.model.id === lastExecutedCellId;
418
+ if (flow_order === 'in_order' || exec_schedule === 'strict') {
419
+ continue;
420
+ }
421
+ }
422
+ if (cell.model.type !== 'code' ||
423
+ executedReactiveReadyCells.has(cell.model.id)) {
380
424
  continue;
381
425
  }
382
426
  if (!newReadyCells.has(cell.model.id)) {
383
427
  continue;
384
428
  }
385
- if (!forcedReactiveCells.has(cell.model.id) && exec_mode !== 'reactive') {
429
+ if (!forcedReactiveCells.has(cell.model.id) &&
430
+ exec_mode !== 'reactive') {
386
431
  continue;
387
432
  }
388
433
  const codeCell = cell;
@@ -396,7 +441,8 @@ const connectToComm = (session, notebook) => {
396
441
  else if (codeCell.model.executionCount == null) {
397
442
  // pass
398
443
  }
399
- else if (codeCell.model.executionCount < cellPendingExecution.model.executionCount) {
444
+ else if (codeCell.model.executionCount <
445
+ cellPendingExecution.model.executionCount) {
400
446
  // otherwise, execute in order of earliest execution counter
401
447
  cellPendingExecution = codeCell;
402
448
  }
@@ -416,6 +462,7 @@ const connectToComm = (session, notebook) => {
416
462
  executedReactiveReadyCells = new Set();
417
463
  updateUI(notebook);
418
464
  isReactivelyExecuting = false;
465
+ isAltModeExecuting = false;
419
466
  }
420
467
  else {
421
468
  isReactivelyExecuting = true;
package/package.json CHANGED
@@ -6,9 +6,9 @@
6
6
  "jupyterlab",
7
7
  "jupyterlab-extension"
8
8
  ],
9
- "homepage": "https://github.com/nbsafety-project/nbsafety",
9
+ "homepage": "https://github.com/ipyflow/ipyflow",
10
10
  "bugs": {
11
- "url": "https://github.com/nbsafety-project/nbsafety/issues"
11
+ "url": "https://github.com/ipyflow/ipyflow/issues"
12
12
  },
13
13
  "license": "BSD-3-Clause",
14
14
  "author": "Stephen Macke",
@@ -21,20 +21,22 @@
21
21
  "style": "style/index.css",
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/nbsafety-project/nbsafety.git"
24
+ "url": "https://github.com/ipyflow/ipyflow.git"
25
25
  },
26
26
  "scripts": {
27
- "build": "jlpm run build:lib && jlpm run build:labextension:dev",
28
- "build:prod": "jlpm run build:lib && jlpm run build:labextension",
27
+ "build": "npm run build:lib && npm run build:labextension",
28
+ "build:dev": "npm run build:lib && npm run build:labextension:dev",
29
29
  "build:labextension": "jupyter labextension build .",
30
30
  "build:labextension:dev": "jupyter labextension build --development True .",
31
31
  "build:lib": "tsc",
32
- "clean": "jlpm run clean:lib",
32
+ "clean": "npm run clean:lib",
33
33
  "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
34
34
  "eslint": "eslint . --ext .ts,.tsx --fix",
35
35
  "eslint:check": "eslint . --ext .ts,.tsx",
36
+ "format": "prettier --write 'src/*.ts'",
37
+ "lint": "prettier --check 'src/*.ts'",
36
38
  "install:extension": "jupyter labextension develop --overwrite .",
37
- "prepare": "jlpm run clean && jlpm run build:prod",
39
+ "prepare": "npm run clean && npm run build",
38
40
  "watch": "run-p watch:src watch:labextension",
39
41
  "watch:src": "tsc -w",
40
42
  "watch:labextension": "jupyter labextension watch ."
@@ -42,7 +44,8 @@
42
44
  "dependencies": {
43
45
  "@jupyterlab/application": "^3.4.3",
44
46
  "@jupyterlab/coreutils": "^5.4.3",
45
- "@jupyterlab/notebook": "^3.4.3"
47
+ "@jupyterlab/notebook": "^3.4.3",
48
+ "lodash": "^4.0"
46
49
  },
47
50
  "devDependencies": {
48
51
  "@jupyterlab/builder": "^3.4.3",
@@ -63,5 +66,5 @@
63
66
  "extension": true,
64
67
  "outputDir": "../../core/ipyflow/resources/labextension/"
65
68
  },
66
- "version": "0.0.154"
69
+ "version": "0.0.156"
67
70
  }