Skip to content

Commit

Permalink
Restore jupyter-widget tests (#7545)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress authored Jan 2, 2023
1 parent 59c2651 commit 468d981
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 143 deletions.
2 changes: 1 addition & 1 deletion modules/jupyter-widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@loaders.gl/core": "^3.2.10",
"@loaders.gl/csv": "^3.2.10",
"@luma.gl/constants": "^8.5.16",
"mapbox-gl": "^1.2.1"
"mapbox-gl": "^1.13.2"
},
"jupyterlab": {
"extension": "src/plugin",
Expand Down
22 changes: 14 additions & 8 deletions modules/jupyter-widget/src/deck-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
* Pulls together all deck.gl dependencies used
* in @deck.gl/jupyter-widget
*/
const deck = require('../../core/bundle');
import deck from '../../core/bundle';
import * as deckglLayers from '@deck.gl/layers';
import * as deckglAggregationLayers from '@deck.gl/aggregation-layers';
import * as deckglGeoLayers from '@deck.gl/geo-layers';
import * as deckglMeshLayers from '@deck.gl/mesh-layers';
import * as GoogleMapsUtils from '@deck.gl/google-maps';
import * as JSONUtils from '@deck.gl/json';

Object.assign(
deck,
require('@deck.gl/layers'),
require('@deck.gl/aggregation-layers'),
require('@deck.gl/geo-layers'),
require('@deck.gl/mesh-layers'),
require('@deck.gl/google-maps'),
require('@deck.gl/json')
deckglLayers,
deckglAggregationLayers,
deckglGeoLayers,
deckglMeshLayers,
GoogleMapsUtils,
JSONUtils
);

module.exports = deck;
export default deck;
28 changes: 10 additions & 18 deletions modules/jupyter-widget/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,34 @@
// See https://github.com/jupyter-widgets/widget-ts-cookiecutter/blob/master/%7B%7Bcookiecutter.github_project_name%7D%7D/src/extension.ts
// Entry point for the Jupyter Notebook bundle containing custom Backbone model and view definitions.

import {MODULE_VERSION, MODULE_NAME} from './version';
// TODO - this should be placed in a separate module `@deck.gl/playground`
import {createDeck, updateDeck} from './playground/create-deck';
import {initPlayground} from './playground';
import jupyterTransport from './lib/jupyter-transport';
import JupyterTransportModel from './lib/jupyter-transport-model';
import JupyterTransportView from './lib/jupyter-transport-view';

// Some static assets may be required by the custom widget javascript. The base
// url for the notebook is not known at build time and is therefore computed dynamically.
const dataBaseUrl = document.body && document.body.getAttribute('data-base-url');
if (dataBaseUrl) {
// @ts-expect-error undefined global property
window.__webpack_public_path__ = `${dataBaseUrl}nbextensions/pydeck/nb_extension`;
}

// Initialize the transport
const {jupyterTransport} = require('./lib/jupyter-transport').default;

let JupyterTransportModel = null;
let JupyterTransportView = null;
try {
JupyterTransportModel = require('./lib/jupyter-transport-model').default;
JupyterTransportView = require('./lib/jupyter-transport-view').default;
} catch (err) {
// Note: Happens in the to_html() case
}

const {MODULE_VERSION, MODULE_NAME} = require('./version');

// TODO - this should be placed in a separate module `@deck.gl/playground`
const {createDeck, updateDeck} = require('./playground/create-deck');
const {initPlayground} = require('./playground');
initPlayground();

module.exports = {
export {
// Transports
jupyterTransport,

// Jupyter Hooks
MODULE_VERSION,
MODULE_NAME,
JupyterTransportModel,
JupyterTransportView,

// For to_html()...
initPlayground,
// TODO - use playground?
Expand Down
109 changes: 59 additions & 50 deletions modules/jupyter-widget/src/lib/jupyter-transport-model.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,65 @@
import {DOMWidgetModel} from '@jupyter-widgets/base';
import * as widgets from '@jupyter-widgets/base';
import {MODULE_NAME, MODULE_VERSION} from '../version';
import {deserializeMatrix} from './utils/deserialize-matrix';
/**
*
* Note: Variables shared explictly between Python and JavaScript use snake_case
*/
export default class JupyterTransportModel extends DOMWidgetModel {
defaults() {
return {
...super.defaults(),
_model_name: JupyterTransportModel.model_name,
_model_module: JupyterTransportModel.model_module,
_model_module_version: JupyterTransportModel.model_module_version,
_view_name: JupyterTransportModel.view_name,
_view_module: JupyterTransportModel.view_module,
_view_module_version: JupyterTransportModel.view_module_version,
custom_libraries: [],
json_input: null,
mapbox_key: null,
selected_data: [],
data_buffer: null,
tooltip: null,
width: '100%',
height: 500,
js_warning: false
};
}

static get serializers() {
return {
...DOMWidgetModel.serializers,
// Add any extra serializers here
data_buffer: {deserialize: deserializeMatrix}
};
}
let JupyterTransportModel = null;
const DOMWidgetModel = widgets && widgets.DOMWidgetModel;

static get model_name() {
return 'JupyterTransportModel';
}
static get model_module() {
return MODULE_NAME;
}
static get model_module_version() {
return MODULE_VERSION;
}
static get view_name() {
return 'JupyterTransportView';
}
static get view_module() {
return MODULE_NAME;
}
static get view_module_version() {
return MODULE_VERSION;
if (DOMWidgetModel) {
/**
*
* Note: Variables shared explictly between Python and JavaScript use snake_case
*/
class Model extends DOMWidgetModel {
defaults() {
return {
...super.defaults(),
_model_name: JupyterTransportModel.model_name,
_model_module: JupyterTransportModel.model_module,
_model_module_version: JupyterTransportModel.model_module_version,
_view_name: JupyterTransportModel.view_name,
_view_module: JupyterTransportModel.view_module,
_view_module_version: JupyterTransportModel.view_module_version,
custom_libraries: [],
json_input: null,
mapbox_key: null,
selected_data: [],
data_buffer: null,
tooltip: null,
width: '100%',
height: 500,
js_warning: false
};
}

static get serializers() {
return {
...DOMWidgetModel.serializers,
// Add any extra serializers here
data_buffer: {deserialize: deserializeMatrix}
};
}

static get model_name() {
return 'JupyterTransportModel';
}
static get model_module() {
return MODULE_NAME;
}
static get model_module_version() {
return MODULE_VERSION;
}
static get view_name() {
return 'JupyterTransportView';
}
static get view_module() {
return MODULE_NAME;
}
static get view_module_version() {
return MODULE_VERSION;
}
}
JupyterTransportModel = Model;
}

export default JupyterTransportModel;
90 changes: 49 additions & 41 deletions modules/jupyter-widget/src/lib/jupyter-transport-view.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,64 @@
import {DOMWidgetView} from '@jupyter-widgets/base';
import * as widgets from '@jupyter-widgets/base';
import JupyterTransport from './jupyter-transport';

export default class JupyterTransportView extends DOMWidgetView {
initialize() {
this.listenTo(this.model, 'destroy', this.remove);
let JupyterTransportView = null;
const DOMWidgetView = widgets && widgets.DOMWidgetView;

// TODO - is there any variable information on the model we can use to
// give an interesting name or id to this instance?
this.transport = new JupyterTransport();
if (DOMWidgetView) {
class View extends DOMWidgetView {
initialize() {
this.listenTo(this.model, 'destroy', this.remove);

// Expose Jupyter internals to enable work-arounds
this.transport.jupyterModel = this.model;
this.transport.jupyterView = this;
this.transport._initialize();
super.initialize.apply(this, arguments);
}
// TODO - is there any variable information on the model we can use to
// give an interesting name or id to this instance?
this.transport = new JupyterTransport();

remove() {
if (this.transport) {
this.transport._finalize();
this.transport.jupyterModel = null;
this.transport.jupyterView = null;
this.transport = null;
// Expose Jupyter internals to enable work-arounds
this.transport.jupyterModel = this.model;
this.transport.jupyterView = this;
this.transport._initialize();
super.initialize.apply(this, arguments);
}
}

render() {
super.render();
remove() {
if (this.transport) {
this.transport._finalize();
this.transport.jupyterModel = null;
this.transport.jupyterView = null;
this.transport = null;
}
}

this.model.on('change:json_input', this.onJsonChanged.bind(this));
this.model.on('change:data_buffer', this.onDataBufferChanged.bind(this));
render() {
super.render();

this.onDataBufferChanged();
}
this.model.on('change:json_input', this.onJsonChanged.bind(this));
this.model.on('change:data_buffer', this.onDataBufferChanged.bind(this));

onJsonChanged() {
const json = JSON.parse(this.model.get('json_input'));
this.transport._messageReceived({type: 'json', json});
}
this.onDataBufferChanged();
}

onDataBufferChanged() {
const json = this.model.get('json_input');
const dataBuffer = this.model.get('data_buffer');

if (json && dataBuffer) {
this.transport._messageReceived({
type: 'json-with-binary',
json,
binary: dataBuffer
});
} else {
onJsonChanged() {
const json = JSON.parse(this.model.get('json_input'));
this.transport._messageReceived({type: 'json', json});
}

onDataBufferChanged() {
const json = this.model.get('json_input');
const dataBuffer = this.model.get('data_buffer');

if (json && dataBuffer) {
this.transport._messageReceived({
type: 'json-with-binary',
json,
binary: dataBuffer
});
} else {
this.transport._messageReceived({type: 'json', json});
}
}
}
JupyterTransportView = View;
}

export default JupyterTransportView;
2 changes: 1 addition & 1 deletion modules/jupyter-widget/src/playground/create-deck.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {createGoogleMapsDeckOverlay} from './utils/google-maps-utils';

import {addSupportComponents} from '../lib/components/index';

import * as deck from '../deck-bundle';
import deck from '../deck-bundle';

const classesFilter = x => x.charAt(0) === x.charAt(0).toUpperCase();
const functionsFilter = x => x.charAt(0) === x.charAt(0).toLowerCase() && x.charAt(0) != '_';
Expand Down
1 change: 1 addition & 0 deletions modules/jupyter-widget/src/playground/playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function processDataBuffer({binary, convertedJson}) {

// Filters circular references on JSON string conversion
function filterJsonValue(key, value) {
// eslint-disable-next-line
return value instanceof deckBundle.Layer ? value.id : value;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* global window */
import * as deck from '../../deck-bundle';
import deck from '../../deck-bundle';

export function createGoogleMapsDeckOverlay({
container,
Expand Down
13 changes: 3 additions & 10 deletions modules/jupyter-widget/src/playground/utils/mapbox-utils.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
/* global process, document */
/* global document */
import {loadCSS} from './css-utils';

// SSR safe import (ensures this file can be imported under Node.js e.g. for tests)
// From https://github.com/mapbox/mapbox-gl-js/issues/4593#issuecomment-546290823
// eslint-disable-next-line no-undef
let mapboxgl;
import mapboxgl from 'mapbox-gl';

if (process.browser) {
mapboxgl = require('mapbox-gl');
}

const MAPBOX_CSS_URL = 'https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.1/mapbox-gl.css';
const MAPBOX_CSS_URL = 'https://api.tiles.mapbox.com/mapbox-gl-js/v1.13.2/mapbox-gl.css';

export default mapboxgl;

Expand Down
2 changes: 1 addition & 1 deletion test/modules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ import './google-maps';
import './mapbox';
import './json';
import './react';
// import './jupyter-widget';
import './jupyter-widget';
import './extensions';
13 changes: 13 additions & 0 deletions test/modules/jupyter-widget/dummy-jupyter-widgets-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Dummy exports for node tests
import * as Backbone from 'backbone';

export class ManagerBase {}
export class DOMWidgetModel extends Backbone.Model {
defaults() {
return {};
}
}
export class DOMWidgetView {}
export function uuid() {
return 'uuid';
}
2 changes: 2 additions & 0 deletions test/modules/jupyter-widget/dummy-mapbox-gl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Dummy exports for node tests
export default {};
16 changes: 6 additions & 10 deletions test/modules/jupyter-widget/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
try {
require('./binary-transport.spec');
require('./create-deck.spec');
require('./index.spec');
require('./widget-tooltip.spec');
require('./utils/google-maps-utils.spec');
} catch (err) {
// eslint-disable-next-line no-console,no-undef
console.log('Skipping browser tests');
}
import './binary-transport.spec';
import './create-deck.spec';
import './widget-tooltip.spec';
import './utils/google-maps-utils.spec';

import './index.spec';
Loading

0 comments on commit 468d981

Please sign in to comment.