Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script editor debugger - experimental #2087

Merged
merged 98 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
0f5e3d5
Create PythonEditor class
karlaspuldaro Aug 12, 2021
9108ae2
Create REditor class
karlaspuldaro Aug 13, 2021
c0d3853
Cleanup
karlaspuldaro Aug 17, 2021
5c0ee6c
Add new button to the toolbar
karlaspuldaro Aug 17, 2021
e2844d4
Handle disable debug button
karlaspuldaro Aug 19, 2021
6fff405
Fix disable bug
karlaspuldaro Aug 24, 2021
6e183b2
Add editor debug handler
karlaspuldaro Aug 31, 2021
a0de184
Merge branch 'master' into debugger
karlaspuldaro Sep 8, 2021
8ea8793
Improve kernel specs init
karlaspuldaro Sep 10, 2021
2ad1d68
Merge branch 'master' into debugger
karlaspuldaro Sep 14, 2021
585328c
Pass language to the constructor
karlaspuldaro Sep 16, 2021
dc6571d
Merge branch 'master' into debugger
karlaspuldaro Sep 23, 2021
5f4dd1e
Store button reference
karlaspuldaro Sep 23, 2021
b355c2f
Merge branch 'master' into debugger
karlaspuldaro Dec 6, 2021
7f616fa
Track console debug
karlaspuldaro Dec 15, 2021
d7bbdf0
Merge branch 'master' into debugger
karlaspuldaro Dec 20, 2021
d887a13
Merge master + resolve conflicts
karlaspuldaro Jan 31, 2022
baaf0b1
Remove unnecessary access to current widget
karlaspuldaro Jan 31, 2022
475fc5f
Merge branch 'master' into debugger
karlaspuldaro Feb 2, 2022
8be12b4
Merge branch 'master' into debugger
karlaspuldaro Feb 11, 2022
4d7f3ee
Merge branch 'master' into debugger
karlaspuldaro Feb 17, 2022
454536d
Merge master + solve 3.3 dependency issues
karlaspuldaro Mar 7, 2022
ddd1d49
Solve dependency conflict
karlaspuldaro Mar 18, 2022
46af08f
Cleanup
karlaspuldaro Mar 18, 2022
c809af9
Fix integration tests
karlaspuldaro Mar 22, 2022
cfb4be7
Merge branch 'master' into debugger
karlaspuldaro Mar 22, 2022
9bd3d38
Dismiss code assistant box on failing tests
karlaspuldaro Mar 23, 2022
5d57f61
Merge branch 'master' into debugger
karlaspuldaro Mar 23, 2022
94c3a4b
Merge with master and resolve conflicts
karlaspuldaro Apr 1, 2022
fbacfcb
Merge master and resolve conflicts
karlaspuldaro Apr 8, 2022
e02e7f6
Merge branch 'master' into debugger
karlaspuldaro Apr 19, 2022
fa688ca
Merge master and resolve conflicts
karlaspuldaro Apr 20, 2022
89e73f1
Add debugger plugins - wip
karlaspuldaro Apr 26, 2022
7d3d491
Merge master and resolve conflicts
karlaspuldaro May 6, 2022
a4833fc
Merge branch 'master' into debugger
karlaspuldaro May 11, 2022
80c0237
Add debugger plugins - wip
karlaspuldaro May 12, 2022
690ec4b
Add service to editor handler - wip
karlaspuldaro May 13, 2022
595a604
Move handler to script editor package
karlaspuldaro May 25, 2022
8399990
Add File Handler
karlaspuldaro May 26, 2022
7756c0b
Get kernel session for extension
karlaspuldaro May 30, 2022
3b41eea
Merge master
karlaspuldaro Jun 1, 2022
8000fa1
Create elyra script-editor-debugger-extension
karlaspuldaro Jun 1, 2022
080531c
Merge branch 'master' into debugger
karlaspuldaro Jun 3, 2022
cfae567
Merge branch 'main' into debugger
karlaspuldaro Jun 6, 2022
c36ac93
Add select style to match notebook dropdown
karlaspuldaro Jun 8, 2022
a2b0ac9
Rename extension
karlaspuldaro Jun 8, 2022
423b0df
Identify ScriptEditor widget on change signal
karlaspuldaro Jun 8, 2022
5792193
Add callback function to KernelDropdown
karlaspuldaro Jun 9, 2022
a445589
Use kernel selection getter
karlaspuldaro Jun 9, 2022
c37886a
kernel selection dropdown - wip
karlaspuldaro Jun 9, 2022
ec3b00c
Fix kernel options rendering
karlaspuldaro Jun 10, 2022
2686b95
Handle debug button update on kernel selection
karlaspuldaro Jun 10, 2022
d52642f
Track active session connections from plugin
karlaspuldaro Jun 10, 2022
c6ae458
Merge branch 'main' into debugger
karlaspuldaro Jun 10, 2022
e4d5fce
Typo
karlaspuldaro Jun 10, 2022
68d7c93
Start session connection for plugin - wip
karlaspuldaro Jun 10, 2022
e22aea1
Deep copy kernel spec obj
karlaspuldaro Jun 13, 2022
1b338e9
Select default kernel on load
karlaspuldaro Jun 15, 2022
e14be35
Use custom function to get default kernel
karlaspuldaro Jun 16, 2022
38398ed
Start kernel session - wip
karlaspuldaro Jun 16, 2022
1306b6e
Use console.warn on catch block
karlaspuldaro Jun 21, 2022
937119f
Fix editor tracker update
karlaspuldaro Jun 21, 2022
e58a954
Cleanup
karlaspuldaro Jun 21, 2022
510ecc8
Remove unused file
karlaspuldaro Jun 23, 2022
833a49f
Simplify run and debug
karlaspuldaro Jun 23, 2022
b0127ba
Fix console errors related to widget type
karlaspuldaro Jun 24, 2022
e797273
Handle listeners - wip
karlaspuldaro Jul 4, 2022
0c60da4
Handle kernel restart
karlaspuldaro Jul 13, 2022
62d95e1
Emit signal of first load - wip
karlaspuldaro Jul 15, 2022
82bf78c
Merge branch 'main' into debugger
karlaspuldaro Jul 15, 2022
d308940
Remove unused file
karlaspuldaro Jul 18, 2022
c29fb3f
Update dependencies
karlaspuldaro Jul 19, 2022
14fe830
Clean up
karlaspuldaro Jul 20, 2022
693e5bd
Replace log errors for warn
karlaspuldaro Jul 20, 2022
3d87359
Simplify disableRunButton
karlaspuldaro Jul 20, 2022
c6a16c2
Fix existing integration tests
karlaspuldaro Jul 26, 2022
184c479
Merge branch 'main' into debugger
karlaspuldaro Jul 27, 2022
07dcd66
Prevent session starting on closed editors
karlaspuldaro Aug 3, 2022
7865a31
Handle UI update on page reload with an open editor tab
karlaspuldaro Aug 4, 2022
9c80b8c
Keep session open after run and debug
karlaspuldaro Aug 10, 2022
ec07585
Merge branch 'main' into debugger
karlaspuldaro Aug 10, 2022
04d1d8e
Increase test timeout
karlaspuldaro Aug 11, 2022
d4bfc9b
Keep session open after a run
karlaspuldaro Aug 11, 2022
9c416c2
Stop run button stops kernel only
karlaspuldaro Aug 11, 2022
d25894f
Fix hanging execution state
karlaspuldaro Aug 11, 2022
2ee3705
Fix rerun after stop kernel
karlaspuldaro Aug 16, 2022
6504dff
Update create-release script
karlaspuldaro Aug 16, 2022
139235e
Update overview doc
karlaspuldaro Aug 16, 2022
a8aeade
Update interrupt button title
karlaspuldaro Aug 16, 2022
0c504a0
Various fixes
karlaspuldaro Aug 17, 2022
4ecd018
Add script debugging support doc section
karlaspuldaro Aug 18, 2022
c015e08
Break up script editor test files
karlaspuldaro Aug 19, 2022
f5a6552
Doc update as per review comments
karlaspuldaro Aug 19, 2022
9b66bad
Update doc as per review comments
karlaspuldaro Aug 19, 2022
c5267f1
Move common test to commands.ts
karlaspuldaro Aug 19, 2022
b81e147
Update readme and release script
akchinSTC Aug 19, 2022
24e18cf
Fix no kernel display
karlaspuldaro Aug 19, 2022
525247e
Update doc as per review comments
karlaspuldaro Aug 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ uninstall-src: # Uninstalls source extensions if they're still installed
- jupyter labextension uninstall --no-build @elyra/python-editor-extension
- jupyter labextension uninstall --no-build @elyra/r-editor-extension
- jupyter labextension uninstall --no-build @elyra/code-viewer-extension
- jupyter labextension uninstall --no-build @elyra/script-debugger-extension
- jupyter labextension unlink --no-build @elyra/pipeline-services
- jupyter labextension unlink --no-build @elyra/pipeline-editor

Expand Down
4 changes: 2 additions & 2 deletions create-release.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,14 +597,14 @@ def prepare_extensions_release() -> None:
f"See https://elyra.readthedocs.io/en/{config.new_version}/user_guide/pipelines.html",
),
"elyra-python-editor-extension": SimpleNamespace(
packages=["python-editor-extension", "metadata-extension", "theme-extension"],
packages=["python-editor-extension", "metadata-extension", "theme-extension", "script-debugger-extension"],
description=f"The Python Script editor extension contains support for Python files, "
f"which can take advantage of the Hybrid Runtime Support enabling users to "
f"locally edit .py scripts and execute them against local or cloud-based resources."
f"See https://elyra.readthedocs.io/en/{config.new_version}/user_guide/enhanced-script-support.html",
),
"elyra-r-editor-extension": SimpleNamespace(
packages=["r-editor-extension", "metadata-extension", "theme-extension"],
packages=["r-editor-extension", "metadata-extension", "theme-extension", "script-debugger-extension"],
description=f"The R Script editor extension contains support for R files, which can take "
f"advantage of the Hybrid Runtime Support enabling users to locally edit .R scripts "
f"and execute them against local or cloud-based resources."
Expand Down
2 changes: 1 addition & 1 deletion packages/python-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"@elyra/ui-components": "3.11.0-dev",
"@jupyterlab/application": "^3.4.0",
"@jupyterlab/apputils": "^3.4.0",
"@jupyterlab/builder": "^3.4.0",
"@jupyterlab/codeeditor": "^3.4.0",
"@jupyterlab/docregistry": "^3.4.0",
"@jupyterlab/filebrowser": "^3.4.0",
Expand All @@ -59,6 +58,7 @@
"@lumino/coreutils": "^1.5.6"
},
"devDependencies": {
"@jupyterlab/builder": "^3.4.0",
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
"rimraf": "^3.0.2",
"typescript": "~4.1.3"
},
Expand Down
65 changes: 65 additions & 0 deletions packages/script-debugger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "@elyra/script-debugger-extension",
"version": "3.10.0-dev",
"description": "JupyterLab extension - visual debugging support for script editors",
"keywords": [
"jupyter",
"jupyterlab",
"jupyterlab-extension"
],
"homepage": "https://github.com/elyra-ai/elyra",
"bugs": {
"url": "https://github.com/elyra-ai/elyra/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/elyra-ai/elyra/"
},
"license": "Apache-2.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"style": "style/index.css",
"files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"src/**/*.{ts,tsx}",
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
],
"scripts": {
"build": "jlpm run build:lib && jlpm run build:labextension:dev",
"build:prod": "jlpm run build:lib && jlpm run build:labextension",
"build:lib": "tsc",
"build:labextension": "jupyter labextension build .",
"build:labextension:dev": "jupyter labextension build --development True .",
"clean": "rimraf lib tsconfig.tsbuildinfo ../../dist/labextensions/@elyra/script-debugger-extension",
"lab:dev": "jupyter labextension develop --overwrite ../../dist/labextensions/@elyra/script-debugger-extension",
"dist": "npm pack .",
"prepare": "npm run build",
"watch": "run-p watch:src watch:labextension",
"watch:src": "tsc -w",
"watch:labextension": "jupyter labextension watch .",
"lab:install": "jupyter labextension install --no-build",
"lab:uninstall": "jupyter labextension uninstall --no-build",
"link:dev": "yarn link @jupyterlab/builder",
"unlink:dev": "yarn unlink @jupyterlab/builder"
},
"dependencies": {
"@elyra/script-editor": "3.11.0-dev",
"@jupyterlab/application": "^3.4.0",
"@jupyterlab/debugger": "^3.4.0",
"@jupyterlab/fileeditor": "^3.4.0",
"@jupyterlab/services": "^6.4.0",
"@lumino/widgets": "^1.19.0"
},
"devDependencies": {
"@jupyterlab/builder": "^3.4.0",
"rimraf": "^3.0.2",
"typescript": "~4.1.3"
},
"publishConfig": {
"access": "public"
},
"jupyterlab": {
"extension": true,
"outputDir": "../../dist/labextensions/@elyra/script-debugger-extension"
}
}
188 changes: 188 additions & 0 deletions packages/script-debugger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* Copyright 2018-2022 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ScriptEditor } from '@elyra/script-editor';
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
import { Debugger, IDebugger } from '@jupyterlab/debugger';
import { IEditorTracker } from '@jupyterlab/fileeditor';
import { KernelManager, Session, SessionManager } from '@jupyterlab/services';
import { Widget } from '@lumino/widgets';

/**
* Debugger plugin.
* Adapted from JupyterLab debugger extension.
* A plugin that provides visual debugging support for script editors.
*/
const scriptEditorDebuggerExtension: JupyterFrontEndPlugin<void> = {
id: 'elyra-script-debugger',
autoStart: true,
requires: [IDebugger, IEditorTracker],
optional: [ILabShell],
activate: (
app: JupyterFrontEnd,
debug: IDebugger,
editorTracker: IEditorTracker,
labShell: ILabShell | null
) => {
console.log('Elyra - script-debugger extension is activated!');
const handler = new Debugger.Handler({
type: 'file',
shell: app.shell,
service: debug
});

const activeSessions: { [id: string]: Session.ISessionConnection } = {};
const kernelManager = new KernelManager();
const sessionManager = new SessionManager({
kernelManager: kernelManager
});

const updateDebugger = async (widget: ScriptEditor): Promise<void> => {
const kernelSelection = (widget as ScriptEditor).kernelSelection;
const debuggerAvailable = await widget.isDebuggerAvailable(
kernelSelection
);
// console.log(
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
// `#####updateDebugger kernelSelection= ' ${kernelSelection} \n debuggerAvailable= ' ${!!debuggerAvailable}`
// );
if (!debuggerAvailable) {
return;
}

const sessions = app.serviceManager.sessions;
try {
const path = widget.context.path;
let sessionModel = await sessions.findByPath(path);
if (!sessionModel) {
// Start a kernel session for the selected kernel supporting debug
const sessionConnection = await startSession(kernelSelection, path);
sessionModel = await sessions.findByPath(path);
if (sessionConnection && sessionModel) {
activeSessions[sessionModel.id] = sessionConnection;
}
}

if (sessionModel) {
let sessionConnection: Session.ISessionConnection | null =
activeSessions[sessionModel.id];
if (!sessionConnection) {
// Use `connectTo` only if the session does not exist.
// `connectTo` sends a kernel_info_request on the shell
// channel, which blocks the debug session restore when waiting
// for the kernel to be ready
sessionConnection = sessions.connectTo({ model: sessionModel });
activeSessions[sessionModel.id] = sessionConnection;
}
if (sessionModel.kernel?.name !== kernelSelection) {
// New kernel selection detected, restart session connection for new kernel
await shutdownSession(sessionConnection);

sessionConnection = await startSession(kernelSelection, path);
sessionModel = await sessions.findByPath(path);
if (sessionConnection && sessionModel) {
activeSessions[sessionModel.id] = sessionConnection;
}
}
await handler.update(widget, sessionConnection);
app.commands.notifyCommandChanged();
}
} catch (e) {
console.log('Exception: shutdown = ' + JSON.stringify(e));
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
}
};

// Use a weakmap to track the callback function used by signal listeners so that the object can be cleared by gargabe collector when no longer in use, avoiding memory leaks
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
// Key: ScriptEditor widget
// Value: instance of updateDebugger function
const callbackControl = new WeakMap<ScriptEditor, () => Promise<void>>();

const update = async (widget: Widget | null): Promise<void> => {
if (widget instanceof ScriptEditor) {
let callbackFn = callbackControl.get(widget);
if (!callbackFn) {
callbackFn = (): Promise<void> => updateDebugger(widget);
callbackControl.set(widget, callbackFn);
}
updateDebugger(widget);

// Listen to possible kernel selection changes
widget.kernelSelectionChanged.disconnect(callbackFn);
widget.kernelSelectionChanged.connect(callbackFn);
}
};

if (labShell) {
// Listen to main area's current focus changes.
labShell.currentChanged.connect((_, widget) => {
return update(widget.newValue);
});
}

if (editorTracker) {
// Listen to script editor's current instance changes.
editorTracker.currentChanged.connect((_, widget) => {
console.log('editorTracker.currentChanged#######');
return update(widget);
});
// listen to script editor's widget updates
// editorTracker.widgetUpdated.connect((_, widget) => { console.log('editorTracker.widgetUpdated#######'); return update(widget); });
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
}

const startSession = async (
kernelSelection: string,
path: string
): Promise<Session.ISessionConnection | null> => {
const options: Session.ISessionOptions = {
kernel: {
name: kernelSelection
},
path: path,
type: 'file',
name: path
};
let sessionConnection;
try {
sessionConnection = await sessionManager.startNew(options);
sessionConnection.setPath(path);
console.log(
`Kernel session started for ${path} with selected ${kernelSelection} kernel.`
);
} catch (e) {
console.log('Exception: start session = ' + JSON.stringify(e));
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
sessionConnection = null;
}
return sessionConnection;
};

const shutdownSession = async (
sessionConnection: Session.ISessionConnection
): Promise<void> => {
try {
const kernelName = sessionConnection.kernel?.name;
await sessionConnection.shutdown();
console.log(`${kernelName} kernel shut down.`);
} catch (e) {
console.log('Exception: shutdown = ' + JSON.stringify(e));
karlaspuldaro marked this conversation as resolved.
Show resolved Hide resolved
}
};
}
};

export default scriptEditorDebuggerExtension;
15 changes: 15 additions & 0 deletions packages/script-debugger/style/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2018-2022 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
7 changes: 7 additions & 0 deletions packages/script-debugger/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "lib"
},
"include": ["src"]
}
1 change: 1 addition & 0 deletions packages/script-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@jupyterlab/rendermime": "^3.4.0",
"@jupyterlab/services": "^6.4.0",
"@jupyterlab/ui-components": "^3.4.0",
"@lumino/signaling": "^1.4.3",
"@lumino/widgets": "^1.19.0",
"react": "^17.0.1",
"react-dom": "^17.0.1"
Expand Down
Loading