Skip to content

Commit d437e86

Browse files
committed
netpyne-44 Add first implementation of a replay system
1 parent 0b05197 commit d437e86

3 files changed

Lines changed: 125 additions & 42 deletions

File tree

webapp/components/NetPyNE.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
TutorialObserver
1414
} from 'netpyne/components';
1515
import { loadModel } from '../redux/actions/general';
16+
import { execPythonMessage } from './general/GeppettoJupyterUtils';
17+
import { replayAll } from './general/CommandRecorder';
1618

1719
const styles = ({ zIndex }) => ({
1820
root: {
@@ -46,6 +48,10 @@ class NetPyNE extends React.Component {
4648
super(props);
4749
this.openPythonCallDialog = this.openPythonCallDialog.bind(this);
4850
this.loaded = false;
51+
this.kernelRestartState = {
52+
state: "idle",
53+
kernelID: undefined
54+
}
4955
}
5056

5157
componentDidMount () {
@@ -84,9 +90,27 @@ class NetPyNE extends React.Component {
8490
};
8591
// A message from the parent frame can specify the file to load
8692
window.addEventListener('message', loadFromEvent);
87-
// window.load = loadFromEvent
88-
const logme = (event) => {
89-
console.log("!!!! EVENT", event)
93+
94+
// Logic for kernel reinit
95+
const logme = ({ detail: { kernel, type } }) => {
96+
console.log("!!!! EVENT", type)
97+
switch (this.kernelRestartState.state) {
98+
case "restarting":
99+
if (type === "kernel_ready" || type === "kernel_autorestarting") {
100+
replayAll(this.kernelRestartState.kernelID)
101+
this.kernelRestartState = {
102+
state: "idle",
103+
kernelID: undefined
104+
}
105+
}
106+
case "idle":
107+
if (type === "kernel_restarting") {
108+
this.kernelRestartState = {
109+
state: "restarting",
110+
kernelID: kernel.id
111+
}
112+
}
113+
}
90114
}
91115
window.addEventListener('kernelstatus', logme)
92116
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { store } from '../../redux/actiondomainStore'
2+
import { recordCommand } from '../../redux/actions/actiondomain';
3+
import { execPythonMessageWithoutRecording } from './GeppettoJupyterUtils';
4+
5+
6+
const registerKernelListeners = () => {
7+
try {
8+
if(IPython.notebook.kernel == null) {
9+
console.warn("Kernel not initialized. Waiting to register kernel event listeners");
10+
setTimeout(registerKernelListeners, 500);
11+
return;
12+
}
13+
} catch (error) {
14+
console.warn("IPython not initialized. Waiting to register kernel event listeners");
15+
setTimeout(registerKernelListeners, 500);
16+
return
17+
}
18+
19+
const notebook = IPython.notebook;
20+
const handleKernelStatusChange = (event, data) => {
21+
const kernelStatusEvent = new CustomEvent("kernelstatus", {
22+
detail: {
23+
"type": event.type,
24+
...data
25+
},
26+
});
27+
window.dispatchEvent(kernelStatusEvent);
28+
};
29+
30+
const handleExecutionRequest = (event, data) => {
31+
if (data.content.netpyne_ui_triggered) {
32+
return
33+
}
34+
const { kernel, content } = data;
35+
console.log("Kernel", kernel.id, "execute", content.code)
36+
record(kernel.id, content.code);
37+
}
38+
39+
// Kernel lifecycle requests
40+
notebook.events.on('kernel_created.Kernel', handleKernelStatusChange);
41+
notebook.events.on('kernel_reconnecting.Kernel', handleKernelStatusChange);
42+
notebook.events.on('kernel_connected.Kernel', handleKernelStatusChange);
43+
notebook.events.on('kernel_starting.Kernel', handleKernelStatusChange);
44+
notebook.events.on('kernel_restarting.Kernel', handleKernelStatusChange);
45+
notebook.events.on('kernel_autorestarting.Kernel', handleKernelStatusChange);
46+
notebook.events.on('kernel_interrupting.Kernel', handleKernelStatusChange);
47+
notebook.events.on('kernel_disconnected.Kernel', handleKernelStatusChange);
48+
notebook.events.on('kernel_ready.Kernel', handleKernelStatusChange);
49+
notebook.events.on('kernel_killed.Kernel', handleKernelStatusChange);
50+
notebook.events.on('kernel_dead.Kernel', handleKernelStatusChange);
51+
52+
// Execution requests
53+
notebook.events.on('execution_request.Kernel', handleExecutionRequest);
54+
}
55+
registerKernelListeners();
56+
57+
58+
const record = (kernelID, command) => {
59+
store.dispatch(recordCommand(kernelID, command))
60+
const actionStore = store.getState();
61+
console.log("store", actionStore)
62+
}
63+
64+
const replayAll = (kernelID) => {
65+
const commands = [
66+
"from jupyter_geppetto import jupyter_geppetto",
67+
"from jupyter_geppetto import utils",
68+
"from netpyne_ui.netpyne_geppetto import netpyne_geppetto",
69+
"netpyne_geppetto.deleteModel({})",
70+
...store.getState()[kernelID]];
71+
commands.pop() // we drop the last command which is probably the faulty one
72+
execPythonMessageWithoutRecording(commands.join('\n'))
73+
}
74+
75+
export { record, replayAll }

webapp/components/general/GeppettoJupyterUtils.js

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,5 @@
1-
const registerKernelListeners = () => {
2-
try {
3-
if(IPython.notebook.kernel == null) {
4-
console.warn("Kernel not initialized. Waiting to register kernel event listeners");
5-
setTimeout(registerKernelListeners, 500);
6-
return;
7-
}
8-
} catch (error) {
9-
console.warn("IPython not initialized. Waiting to register kernel event listeners");
10-
setTimeout(registerKernelListeners, 500);
11-
return
12-
}
1+
import { record as recordCommand } from './CommandRecorder';
132

14-
const notebook = IPython.notebook;
15-
const handleKernelStatusChange = (event, data) => {
16-
const kernelStatusEvent = new CustomEvent("kernelstatus", {
17-
detail: {
18-
"type": event.type,
19-
...data
20-
},
21-
});
22-
window.dispatchEvent(kernelStatusEvent);
23-
};
24-
25-
notebook.events.on('kernel_created.Kernel', handleKernelStatusChange);
26-
notebook.events.on('kernel_reconnecting.Kernel', handleKernelStatusChange);
27-
notebook.events.on('kernel_connected.Kernel', handleKernelStatusChange);
28-
notebook.events.on('kernel_starting.Kernel', handleKernelStatusChange);
29-
notebook.events.on('kernel_restarting.Kernel', handleKernelStatusChange);
30-
notebook.events.on('kernel_autorestarting.Kernel', handleKernelStatusChange);
31-
notebook.events.on('kernel_interrupting.Kernel', handleKernelStatusChange);
32-
notebook.events.on('kernel_disconnected.Kernel', handleKernelStatusChange);
33-
notebook.events.on('kernel_ready.Kernel', handleKernelStatusChange);
34-
notebook.events.on('kernel_killed.Kernel', handleKernelStatusChange);
35-
notebook.events.on('kernel_dead.Kernel', handleKernelStatusChange);
36-
}
37-
registerKernelListeners();
383

394
const handle_output = function (data) {
405
// data is the object passed to the callback from the kernel execution
@@ -67,9 +32,24 @@ const handle_output = function (data) {
6732
}
6833
};
6934

70-
const execPythonMessage = function (command, callback = handle_output) {
35+
const execPythonMessage = function (command, callback = handle_output, record = true) {
7136
const { kernel } = IPython.notebook;
72-
const messageID = kernel.execute(command, { iopub: { output: callback } }, { silent: false, stop_on_error: true, store_history: true });
37+
console.log("Kernel", kernel.id, "executes", command)
38+
if (record) {
39+
recordCommand(kernel.id, command)
40+
}
41+
const messageID = kernel.execute(
42+
command,
43+
{
44+
iopub: { output: callback }
45+
},
46+
{
47+
silent: false,
48+
stop_on_error: true,
49+
store_history: true,
50+
netpyne_ui_triggered: true
51+
});
52+
7353

7454
return new Promise((resolve, reject) => GEPPETTO.on(GEPPETTO.Events.Receive_Python_Message, (data) => {
7555
if (data.data.id == messageID) {
@@ -78,6 +58,10 @@ const execPythonMessage = function (command, callback = handle_output) {
7858
}));
7959
};
8060

61+
const execPythonMessageWithoutRecording = function (command, callback = handle_output) {
62+
return execPythonMessage(command, callback, false)
63+
}
64+
8165
const addslashes = function (str) {
8266
return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
8367
}
@@ -99,4 +83,4 @@ const evalPythonMessage = function (command, parameters, parse = true) {
9983
return execPythonMessage(finalCommand, handle_output);
10084
};
10185

102-
export { execPythonMessage, evalPythonMessage };
86+
export { execPythonMessage, evalPythonMessage, execPythonMessageWithoutRecording };

0 commit comments

Comments
 (0)