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

0.4.x: Lazy loading of widgets packages, for ipywidgets 7 and 8 support #1482

Merged
merged 15 commits into from
Jul 17, 2024
Merged
15 changes: 14 additions & 1 deletion .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ jobs:
strategy:
matrix:
python-version: [3.8]
node-version: [16.x]
node-version: [18.x]
ipywidgets: [8, 7]
fail-fast: false

steps:
Expand All @@ -18,6 +19,7 @@ jobs:
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

- name: Install dependencies
if: ${{ matrix.ipywidgets == 8 }}
run: |
python -m pip install -r requirements-visual-test.txt
python -m pip install ".[test]"
Expand All @@ -27,6 +29,17 @@ jobs:
cd ui-tests
jlpm install

- name: Install dependencies
if: ${{ matrix.ipywidgets == 7 }}
run: |
python -m pip install -r requirements-visual-test.txt
python -m pip install ".[test7]"
jlpm
jlpm build
jupyter labextension develop . --overwrite
cd ui-tests
jlpm install

- name: Launch Voila
run: |
# Mount a volume to overwrite the server configuration
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ lib
voila/labextension
tsconfig.tsbuildinfo

.yarn

ui-tests/playwright-report
ui-tests/test-results
ui-tests/benchmark-results
Expand Down
6 changes: 5 additions & 1 deletion packages/voila/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"browserslist": ">0.8%, not ie 11, not op_mini all, not dead",
"dependencies": {
"@jupyter-widgets/base": "^6.0.5",
"@jupyter-widgets/base7": "npm:@jupyter-widgets/[email protected]",
"@jupyter-widgets/controls": "^5.0.6",
"@jupyter-widgets/controls7": "npm:@jupyter-widgets/[email protected]",
"@jupyter-widgets/jupyterlab-manager": "^5.0.8",
"@jupyterlab/application": "^3 || ^4",
"@jupyterlab/apputils": "^3 || ^4",
Expand All @@ -27,18 +29,20 @@
"@lumino/signaling": "^1.4.3 || ^2",
"@lumino/virtualdom": "^1.8.0 || ^2",
"@lumino/widgets": "^1.18.0 || ^2",
"jquery": "^3.7.0",
"mathjax-full": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"@types/node": "^20.14.10",
"babel-loader": "^8.0.5",
"css-loader": "^5.0.0",
"file-loader": "^4.0.0",
"npm-run-all": "^4.1.5",
"p-limit": "^2.2.2",
"style-loader": "^2.0.0",
"typescript": "~4.1.3",
"typescript": "^5",
"url-loader": "^1.0.0",
"webpack": "^5",
"webpack-cli": "^3.2.3"
Expand Down
68 changes: 53 additions & 15 deletions packages/voila/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

import $ from 'jquery';
import 'jquery-ui/ui/widgets/slider';

import {
WidgetManager as JupyterLabManager,
WidgetRenderer
} from '@jupyter-widgets/jupyterlab-manager';

import { output } from '@jupyter-widgets/jupyterlab-manager';

import * as base from '@jupyter-widgets/base';
import * as controls from '@jupyter-widgets/controls';

import * as Application from '@jupyterlab/application';
import * as AppUtils from '@jupyterlab/apputils';
import * as CoreUtils from '@jupyterlab/coreutils';
Expand All @@ -40,10 +38,14 @@ import { Widget } from '@lumino/widgets';

import { requireLoader } from './loader';

function windowDefine(name: string, module: any) {
if (typeof window !== 'undefined' && typeof window.define !== 'undefined') {
window.define(name, module);
}
}

if (typeof window !== 'undefined' && typeof window.define !== 'undefined') {
window.define('@jupyter-widgets/base', base);
window.define('@jupyter-widgets/controls', controls);
window.define('@jupyter-widgets/output', output);
window.define('jquery', $);

window.define('@jupyterlab/application', Application);
window.define('@jupyterlab/apputils', AppUtils);
Expand Down Expand Up @@ -105,6 +107,7 @@ export class WidgetManager extends JupyterLabManager {
if (!viewtag?.parentElement) {
return;
}

martinRenou marked this conversation as resolved.
Show resolved Hide resolved
try {
const widgetViewObject = JSON.parse(viewtag.innerHTML);
const { model_id } = widgetViewObject;
Expand All @@ -126,13 +129,14 @@ export class WidgetManager extends JupyterLabManager {
//
// This workaround may not be necessary anymore with templates that make use
// of progressive rendering.
console.error('Something went wrong', error);
}
});
}

async display_view(msg: any, view: any, options: any): Promise<Widget> {
if (options.el) {
LuminoWidget.Widget.attach(view.luminoWidget, options.el);
LuminoWidget.Widget.attach(view.luminoWidget || view.pWidget, options.el);
}
if (view.el) {
view.el.setAttribute('data-voila-jupyter-widget', '');
Expand Down Expand Up @@ -181,20 +185,54 @@ export class WidgetManager extends JupyterLabManager {
}

private _registerWidgets(): void {
// Lazy loading of either ipywidgets 7 or ipywidgets 8 widgets and CSS
// Depending on what is requested by the kernel, one or the other will load
// IPYWIDGETS 8
this.register({
name: '@jupyter-widgets/base',
version: base.JUPYTER_WIDGETS_VERSION,
exports: base as any
version: '2.0.0',
exports: () => {
const baseWidgets = require('@jupyter-widgets/base') as any;
windowDefine('@jupyter-widgets/base', baseWidgets);
return baseWidgets;
}
});
this.register({
name: '@jupyter-widgets/controls',
version: controls.JUPYTER_CONTROLS_VERSION,
exports: controls as any
version: '2.0.0',
exports: () => {
const controlsWidgets = require('@jupyter-widgets/controls') as any;
windowDefine('@jupyter-widgets/controls', controlsWidgets);
require('@jupyter-widgets/controls/css/widgets-base.css');
return controlsWidgets;
}
});
this.register({
name: '@jupyter-widgets/output',
version: output.OUTPUT_WIDGET_VERSION,
exports: output as any
version: '1.0.0',
exports: async () =>
(await require('@jupyter-widgets/jupyterlab-manager')).output as any
});

// IPYWIDGETS 7
this.register({
name: '@jupyter-widgets/base',
version: '1.2.0',
exports: () => {
const base7Widgets = require('@jupyter-widgets/base7') as any;
windowDefine('@jupyter-widgets/base', base7Widgets);
return base7Widgets;
}
});
this.register({
name: '@jupyter-widgets/controls',
version: '1.5.0',
exports: () => {
const controls7Widget = require('@jupyter-widgets/controls7') as any;
windowDefine('@jupyter-widgets/controls', controls7Widget);
require('@jupyter-widgets/controls7/css/widgets-base.css');
return controls7Widget;
}
});
}

Expand Down
2 changes: 0 additions & 2 deletions packages/voila/style/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@import '@jupyter-widgets/controls/css/widgets-base.css';

@font-face /* 0 */ {
font-family: MJXZERO;
src: url('~mathjax-full/es5/output/chtml/fonts/woff-v2/MathJax_Zero.woff')
Expand Down
11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ test = [
"pytest",
"pytest-tornasync",
]
test7 = [
"notebook==6",
"ipywidgets==7.8.2",
"matplotlib",
"mock",
"numpy",
"pandas",
"papermill",
"pytest",
"pytest-tornasync",
]

[project.scripts]
voila = "voila.app:main"
Expand Down
1 change: 0 additions & 1 deletion requirements-visual-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ jupyterlab~=4.0
bqplot
scipy
ipympl==0.9.2
ipyvolume @ git+https://github.com/jtpio/ipyvolume@ipywidgets-8
# jupyterlab_miami_nights==0.3.2
2 changes: 1 addition & 1 deletion tsconfigbase.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
"skipLibCheck": true,
"strictNullChecks": true,
"target": "es2017",
"types": []
"types": ["node"]
}
}
31 changes: 0 additions & 31 deletions ui-tests/tests/voila.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
expect(await page.screenshot()).toMatchSnapshot('voila-tree-dark.png');
});

// test('Render tree miami theme', async ({ page, browserName }, testInfo) => {

Check warning on line 62 in ui-tests/tests/voila.test.ts

View workflow job for this annotation

GitHub Actions / build

Some tests seem to be commented
// const testFunction = async () => {
// await page.goto('?voila-theme=jupyterlab_miami_nights');
// // wait for page to load
Expand Down Expand Up @@ -140,7 +140,7 @@
expect(await page.screenshot()).toMatchSnapshot(`${notebookName}-dark.png`);
});

// test('Render basics.ipynb with miami theme', async ({

Check warning on line 143 in ui-tests/tests/voila.test.ts

View workflow job for this annotation

GitHub Actions / build

Some tests seem to be commented
// page,
// browserName
// }, testInfo) => {
Expand Down Expand Up @@ -227,24 +227,6 @@
expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`);
});

test('Render and benchmark interactive.ipynb', async ({
page,
browserName
}, testInfo) => {
const notebookName = 'interactive';
const testFunction = async () => {
await page.goto(`/voila/render/${notebookName}.ipynb`);
await page.waitForSelector('div.widget-slider.widget-hslider');
await page.fill('div.widget-readout', '8.00');
await page.keyboard.down('Enter');
await page.fill('div.widget-readout >> text=0', '8.00');
await page.keyboard.down('Enter');
await page.mouse.click(0, 0);
};
await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName);
expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`);
});

test('Render and benchmark ipympl.ipynb', async ({
page,
browserName
Expand All @@ -258,19 +240,6 @@
expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`);
});

test('Render and benchmark ipyvolume.ipynb', async ({
page,
browserName
}, testInfo) => {
const notebookName = 'ipyvolume';
const testFunction = async () => {
await page.goto(`/voila/render/${notebookName}.ipynb`);
await page.waitForSelector('canvas');
};
await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName);
expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`);
});

test('Benchmark the multiple widgets notebook', async ({
page,
browserName
Expand Down
2 changes: 0 additions & 2 deletions voila/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,6 @@ def init_handlers(self) -> List:
])

if JUPYTER_SERVER_2:


handlers.extend(self.identity_provider.get_handlers())

if self.voila_configuration.preheat_kernel:
Expand Down
Loading
Loading