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

Split base manager into separate packages #2710

Merged
merged 5 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .github/workflows/testjs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ jobs:
yarn run test:unit:firefox:headless
popd

pushd packages/base-manager
yarn run test:unit:firefox:headless
popd

pushd packages/controls
yarn run test:unit:firefox:headless
popd
Expand Down
1 change: 1 addition & 0 deletions dev-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pip install -v -e .

if test "$skip_jupyter_lab" != yes; then
jupyter labextension link ./packages/base --no-build
jupyter labextension link ./packages/base-manager --no-build
jupyter labextension link ./packages/controls --no-build
jupyter labextension link ./packages/output --no-build
jupyter labextension install ./packages/jupyterlab-manager
Expand Down
3 changes: 2 additions & 1 deletion examples/web1/manager.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
var base = require('@jupyter-widgets/base');
var ManagerBase = require('@jupyter-widgets/base-manager').ManagerBase;
var controls = require('@jupyter-widgets/controls');
var LuminoWidget = require('@lumino/widgets').Widget;

class WidgetManager extends base.ManagerBase {
class WidgetManager extends ManagerBase {
constructor(el) {
super();
this.el = el;
Expand Down
1 change: 1 addition & 0 deletions examples/web1/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"@jupyter-widgets/base": "^2.0.2",
"@jupyter-widgets/base-manager": "^0.1.0",
"@jupyter-widgets/controls": "^1.5.3"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion examples/web2/manager.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
var base = require('@jupyter-widgets/base');
var ManagerBase = require('@jupyter-widgets/base-manager').ManagerBase;
var controls = require('@jupyter-widgets/controls');
var LuminoWidget = require('@lumino/widgets').Widget;

class WidgetManager extends base.ManagerBase {
class WidgetManager extends ManagerBase {
constructor(el) {
super();
this.el = el;
Expand Down
1 change: 1 addition & 0 deletions examples/web2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@jupyter-widgets/base": "^2.0.2",
"@jupyter-widgets/base-manager": "^0.1.0",
"@jupyter-widgets/controls": "^1.5.3",
"codemirror": "^5.48.0",
"font-awesome": "^4.7.0"
Expand Down
2 changes: 2 additions & 0 deletions packages/base-manager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lib/
test/coverage/
5 changes: 5 additions & 0 deletions packages/base-manager/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"esnext": true,
"expr": true,
"node": true
}
7 changes: 7 additions & 0 deletions packages/base-manager/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
node_modules/
test/
.jshintrc
karma.conf.js
build_css.js
examples/
68 changes: 68 additions & 0 deletions packages/base-manager/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"name": "@jupyter-widgets/base-manager",
"version": "0.1.0",
"description": "Jupyter interactive widgets - base manager",
"repository": {
"type": "git",
"url": "https://github.com/jupyter-widgets/ipywidgets.git"
},
"license": "BSD-3-Clause",
"author": "Project Jupyter",
"files": [
"lib/**/*.d.ts",
"lib/**/*.js",
"css/*.css"
],
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"scripts": {
"build": "npm run build:src",
"build:src": "tsc --build",
"build:test": "tsc --build test && webpack --config test/webpack.conf.js",
"clean": "npm run clean:src",
"clean:src": "rimraf lib && rimraf tsconfig.tsbuildinfo",
"prepublish": "npm run clean && npm run build",
"test": "npm run test:unit",
"test:coverage": "npm run build:test && webpack --config test/webpack-cov.conf.js && karma start test/karma-cov.conf.js",
"test:unit": "npm run test:unit:firefox && npm run test:unit:chrome",
"test:unit:chrome": "npm run test:unit:default -- --browsers=Chrome",
"test:unit:default": "npm run build:test && karma start test/karma.conf.js --log-level debug",
"test:unit:firefox": "npm run test:unit:default -- --browsers=Firefox",
"test:unit:firefox:headless": "npm run test:unit:default -- --browsers=FirefoxHeadless",
"test:unit:ie": "npm run test:unit:default -- --browsers=IE"
},
"dependencies": {
"@jupyter-widgets/base": "^2.0.2",
"@jupyterlab/services": "^5.0.0-beta.2",
"@lumino/coreutils": "^1.2.0",
"base64-js": "^1.2.1"
},
"devDependencies": {
"@types/base64-js": "^1.2.5",
"@types/chai": "^4.1.7",
"@types/chai-as-promised": "^7.1.0",
"@types/expect.js": "^0.3.29",
"@types/mocha": "^5.2.7",
"@types/sinon": "^7.0.13",
"@types/sinon-chai": "^3.2.2",
"chai": "^4.0.0",
"chai-as-promised": "^7.0.0",
"expect.js": "^0.3.1",
"istanbul-instrumenter-loader": "^3.0.1",
"karma": "^4.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.2",
"karma-firefox-launcher": "^1.1.0",
"karma-ie-launcher": "^1.0.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-webpack": "^4.0.2",
"mocha": "^6.1.4",
"npm-run-all": "^4.1.5",
"rimraf": "^2.6.1",
"sinon": "^7.3.2",
"sinon-chai": "^3.3.0",
"typescript": "~3.7.4",
"webpack": "^4.41.5"
}
}
5 changes: 5 additions & 0 deletions packages/base-manager/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

export * from './manager-base';
export * from './utils';
Original file line number Diff line number Diff line change
@@ -1,132 +1,28 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import * as utils from './utils';
import * as services from '@jupyterlab/services';

import {
JSONObject, PartialJSONObject
} from '@lumino/coreutils';

import {
DOMWidgetView, WidgetModel, WidgetView, DOMWidgetModel
} from './widget';

import {
IClassicComm, ICallbacks
} from './services-shim';
DOMWidgetView, WidgetModel, WidgetView, DOMWidgetModel,
IClassicComm, ICallbacks,
put_buffers, remove_buffers, resolvePromisesDict,
ISerializedState, reject, uuid, PROTOCOL_VERSION,
IWidgetManager, IModelOptions, IWidgetOptions
} from '@jupyter-widgets/base';

import {
ISerializedState
base64ToBuffer, bufferToBase64, hexToBuffer
} from './utils';

import {
PROTOCOL_VERSION
} from './version';

const PROTOCOL_MAJOR_VERSION = PROTOCOL_VERSION.split('.', 1)[0];

/**
* The options for a model.
*
* #### Notes
* Either a comm or a model_id must be provided.
*/
export
interface IModelOptions {

/**
* Target name of the widget model to create.
*/
model_name: string;

/**
* Module name of the widget model to create.
*/
model_module: string;

/**
* Semver version requirement for the model module.
*/
model_module_version: string;

/**
* Target name of the widget view to create.
*/
view_name?: string | null;

/**
* Module name of the widget view to create.
*/
view_module?: string | null;

/**
* Semver version requirement for the view module.
*/
view_module_version?: string;

/**
* Comm object associated with the widget.
*/
comm?: any;

/**
* The model id to use. If not provided, the comm id of the comm is used.
*/
model_id?: string;
}

/**
* The options for a connected model.
*
* This gives all of the information needed to instantiate a comm to a new
* widget on the kernel side (so view information is mandatory).
*
* #### Notes
* Either a comm or a model_id must be provided.
*/
export
interface IWidgetOptions extends IModelOptions {
/**
* Target name of the widget model to create.
*/
model_name: string;

/**
* Module name of the widget model to create.
*/
model_module: string;

/**
* Semver version requirement for the model module.
*/
model_module_version: string;

/**
* Target name of the widget view to create.
*/
view_name: string | null;

/**
* Module name of the widget view to create.
*/
view_module: string | null;

/**
* Semver version requirement for the view module.
*/
view_module_version: string;

/**
* Comm object associated with the widget.
*/
comm?: IClassicComm;

/**
* The model id to use. If not provided, the comm id of the comm is used.
*/
model_id?: string;
}

export
interface IState extends PartialJSONObject {
Expand Down Expand Up @@ -160,14 +56,14 @@ interface IBase64Buffers extends PartialJSONObject {
/**
* Manager abstract base class
*/
export abstract class ManagerBase<T> {
export abstract class ManagerBase<T> implements IWidgetManager {

/**
* Display a DOMWidgetView for a particular model.
*/
display_model(msg: services.KernelMessage.IMessage | null, model: DOMWidgetModel, options: any = {}): Promise<T> {
return this.create_view(model, options).then(
view => this.display_view(msg, view, options)).catch(utils.reject('Could not create view', true));
view => this.display_view(msg, view, options)).catch(reject('Could not create view', true));
}

/**
Expand Down Expand Up @@ -206,9 +102,9 @@ export abstract class ManagerBase<T> {
});
view.listenTo(model, 'destroy', view.remove);
return Promise.resolve(view.render()).then(() => { return view; });
}).catch(utils.reject('Could not create a view for model id ' + model.model_id, true));
}).catch(reject('Could not create a view for model id ' + model.model_id, true));
});
const id = utils.uuid();
const id = uuid();
model.views[id] = viewPromise;
viewPromise.then((view) => {
view.once('remove', () => { delete view.model.views[id]; }, this);
Expand All @@ -219,7 +115,7 @@ export abstract class ManagerBase<T> {
/**
* callback handlers specific to a view
*/
callbacks (view?: WidgetView): ICallbacks {
callbacks(view?: WidgetView): ICallbacks {
return {};
}

Expand Down Expand Up @@ -258,13 +154,13 @@ export abstract class ManagerBase<T> {
return new DataView(b instanceof ArrayBuffer ? b : b.buffer);
}
});
utils.put_buffers(data.state, buffer_paths, buffers);
put_buffers(data.state, buffer_paths, buffers);
return this.new_model({
model_name: data.state['_model_name'] as string,
model_module: data.state['_model_module'] as string,
model_module_version: data.state['_model_module_version'] as string,
comm: comm
}, data.state).catch(utils.reject('Could not create a model.', true));
}, data.state).catch(reject('Could not create a model.', true));
}

/**
Expand Down Expand Up @@ -318,7 +214,7 @@ export abstract class ManagerBase<T> {
}, () => {
// Comm Promise Rejected.
if (!options_clone.model_id) {
options_clone.model_id = utils.uuid();
options_clone.model_id = uuid();
}
return this.new_model(options_clone, serialized_state);
});
Expand Down Expand Up @@ -402,7 +298,7 @@ export abstract class ManagerBase<T> {
* @return Promise that resolves when the widget state is cleared.
*/
clear_state(): Promise<void> {
return utils.resolvePromisesDict(this._models).then((models) => {
return resolvePromisesDict(this._models).then((models) => {
Object.keys(models).forEach(id => models[id].close());
this._models = Object.create(null);
});
Expand Down Expand Up @@ -454,14 +350,14 @@ export abstract class ManagerBase<T> {
return Promise.all(Object.keys(models).map(model_id => {

// First put back the binary buffers
const decode: { [s: string]: (s: string) => ArrayBuffer } = {'base64': utils.base64ToBuffer, 'hex': utils.hexToBuffer};
const decode: { [s: string]: (s: string) => ArrayBuffer } = {'base64': base64ToBuffer, 'hex': hexToBuffer};
const model = models[model_id];
const modelState = model.state;
if (model.buffers) {
const bufferPaths = model.buffers.map((b: any) => b.path);
// put_buffers expects buffers to be DataViews
const buffers = model.buffers.map((b: any) => new DataView(decode[b.encoding](b.data)));
utils.put_buffers(model.state, bufferPaths, buffers);
put_buffers(model.state, bufferPaths, buffers);
}

// If the model has already been created, set its state and then
Expand Down Expand Up @@ -598,10 +494,10 @@ function serialize_state(models: WidgetModel[], options: IStateOptions = {}): IM
const state: IManagerStateMap = {};
models.forEach(model => {
const model_id = model.model_id;
const split = utils.remove_buffers(model.serialize(model.get_state(options.drop_defaults)));
const split = remove_buffers(model.serialize(model.get_state(options.drop_defaults)));
const buffers: IBase64Buffers[] = split.buffers.map((buffer, index) => {
return {
data: utils.bufferToBase64(buffer),
data: bufferToBase64(buffer),
path: split.buffer_paths[index],
encoding: 'base64'
};
Expand Down
Loading