Skip to content

Commit

Permalink
Embed jupyter-widget .tgz within pydeck package for distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Duberstein committed Oct 4, 2019
1 parent ee4f7a1 commit 13591ff
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 53 deletions.
Empty file.
3 changes: 2 additions & 1 deletion bindings/python/pydeck/pydeck/widget/_frontend.py
Expand Up @@ -8,4 +8,5 @@
# module_name is the name of the NPM package for the widget
module_name = "@deck.gl/jupyter-widget"
# module_version is the current version of the module of the JS portion of the widget
module_version = "^7.3.0-beta.4"
# It appears to be important only for JupyterLab and ignored for Jupyter Notebooks
module_version = ">=7.3.0"
74 changes: 50 additions & 24 deletions bindings/python/pydeck/setup.py
Expand Up @@ -10,6 +10,7 @@

import atexit
from distutils import log
import glob
import json
import os
from shutil import copy
Expand Down Expand Up @@ -83,6 +84,7 @@ class FrontendBuild(Command):
target_files = [
os.path.join(here, "pydeck", "nbextension", "static", "index.js"),
os.path.join(here, "pydeck", "nbextension", "static", "index.js.map"),
os.path.join(here, "pydeck", "labextension/"),
]

user_options = []
Expand All @@ -103,8 +105,8 @@ def clean_frontend_build(self):

def has_build_utilities(self):
try:
check_call(["npm", "--version"], stdout=open(os.devnull, 'wb'))
check_call(["yarn", "--version"], stdout=open(os.devnull, 'wb'))
check_call(["npm", "--version"], stdout=open(os.devnull, "wb"))
check_call(["yarn", "--version"], stdout=open(os.devnull, "wb"))
return True
except Exception:
return False
Expand All @@ -113,14 +115,26 @@ def copy_frontend_build(self):
"""Copy JS bundle from top-level JS module to pydeck widget's `static/` folder.
Overwrites destination files"""
js_dist_dir = os.path.join(widget_dir, "dist")
nbextension_folder = os.path.join(here, "pydeck", "nbextension", "static")
labextension_folder = os.path.join(here, "pydeck", "labextension")
labextension_tgz = glob.glob(os.path.join(widget_dir, "deck.gl-jupyter-widget-*.tgz"))[0]
js_files = [
os.path.join(js_dist_dir, "index.js"),
os.path.join(js_dist_dir, "index.js.map"),
{
"source": os.path.join(js_dist_dir, "index.js"),
"destination": nbextension_folder,
},
{
"source": os.path.join(js_dist_dir, "index.js.map"),
"destination": nbextension_folder,
},
{
"source": labextension_tgz,
"destination": labextension_folder
},
]
static_folder = os.path.join(here, "pydeck", "nbextension", "static")
for js_file in js_files:
log.debug("Copying %s to %s" % (js_file, static_folder))
copy(js_file, static_folder)
log.debug("Copying %s to %s" % (js_file["source"], js_file["destination"]))
copy(js_file["source"], js_file["destination"])

def run(self):
has_build_utilities = self.has_build_utilities()
Expand All @@ -133,14 +147,24 @@ def run(self):
env["PATH"] = npm_path

if build_all:
log.info("Installing build dependencies with yarn. This may take a while...")
log.info(
"Installing build dependencies with yarn. This may take a while..."
)
check_call(
["yarn", "bootstrap"],
cwd=yarn_root,
stdout=sys.stdout,
stderr=sys.stderr,
env=env,
)
log.info("Creating lab extension .tgz with `npm pack`.")
check_call(
["npm", "run", "build:labextension"],
cwd=widget_dir,
stdout=sys.stdout,
stderr=sys.stderr,
env=env,
)
else:
log.info("Installing build dependencies with `npm run build`.")
check_call(
Expand All @@ -153,10 +177,14 @@ def run(self):

self.clean_frontend_build()
self.copy_frontend_build()
log.info('Creating RequireJS configs.')
setup_environment = 'production' if prod_build else 'development'
create_notebook_requirejs(load_requirejs_dependencies(), here, setup_environment=setup_environment)
create_standalone_render_requirejs(load_requirejs_dependencies(), here, setup_environment=setup_environment)
log.info("Creating RequireJS configs for notebook and standalone environments.")
setup_environment = "production" if prod_build else "development"
create_notebook_requirejs(
load_requirejs_dependencies(), here, setup_environment=setup_environment
)
create_standalone_render_requirejs(
load_requirejs_dependencies(), here, setup_environment=setup_environment
)

for t in self.target_files:
if not os.path.exists(t):
Expand All @@ -183,7 +211,7 @@ def run(self):


def load_requirejs_dependencies():
return json.loads(read('requirejs_dependencies.json'))
return json.loads(read("requirejs_dependencies.json"))


version_ns = {}
Expand All @@ -205,7 +233,7 @@ def load_requirejs_dependencies():
version=version_ns["__version__"],
description="Widget for deck.gl maps",
long_description="{}".format(read("README.md")),
long_description_content_type='text/markdown',
long_description_content_type="text/markdown",
license="MIT License",
include_package_data=True,
packages=find_packages(),
Expand Down Expand Up @@ -239,15 +267,12 @@ def load_requirejs_dependencies():
install_requires=[
'ipykernel>=5.1.2;python_version>="3.4"',
'ipython>=5.8.0;python_version<"3.4"',
'ipywidgets>=7.0.0,<8',
'traitlets>=4.3.2',
'jinja2>=2.10.1'
"ipywidgets>=7.0.0,<8",
"traitlets>=4.3.2",
"jinja2>=2.10.1",
],
setup_requires=[
'pytest-runner',
'Jinja2>=2.10.1'
],
tests_require=['pytest'],
setup_requires=["pytest-runner", "Jinja2>=2.10.1"],
tests_require=["pytest"],
data_files=[
(
"share/jupyter/nbextensions/pydeck",
Expand All @@ -256,8 +281,9 @@ def load_requirejs_dependencies():
"pydeck/nbextension/static/index.js",
"pydeck/io/templates/requirejs_dependencies.json",
"pydeck/nbextension/static/index.js.map",
],
),
]),
('share/jupyter/lab/extensions', ['pydeck/labextension/*']),

("etc/jupyter/nbconfig/notebook.d", ["pydeck.json"]),
],
zip_safe=False,
Expand Down
1 change: 1 addition & 0 deletions modules/jupyter-widget/.gitignore
@@ -0,0 +1 @@
*.tgz
1 change: 1 addition & 0 deletions modules/jupyter-widget/package.json
Expand Up @@ -25,6 +25,7 @@
"scripts": {
"watch": "(cd ../main && npm run build-bundle -- --env.dev) && ln -f ../main/dist/dist.dev.js ./dist/deckgl.dev.js && webpack-dev-server --env.dev --port 8080",
"build": "webpack",
"build:labextension": "npm pack",
"prepublishOnly": "webpack"
},
"dependencies": {
Expand Down
23 changes: 0 additions & 23 deletions modules/jupyter-widget/src/notebook-utils.js
Expand Up @@ -12,29 +12,6 @@ if (!window.require) {
document.head.appendChild(requirejs);
}

export function loadCss(url) {
const link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
document.getElementsByTagName('head')[0].appendChild(link);
}

/**
* Hides a warning in the mapbox-gl.js library from surfacing in the notebook as text.
*/
export function hideMapboxCSSWarning() {
const missingCssWarning = document.getElementsByClassName('mapboxgl-missing-css')[0];
if (missingCssWarning) {
missingCssWarning.style.display = 'none';
}
}

export function updateDeck(inputJSON, {jsonConverter, deckgl}) {
const results = jsonConverter.convert(inputJSON);
deckgl.setProps(results);
}

export function initDeck({mapboxApiKey, container, jsonInput, tooltip, onComplete, handleClick}) {
require(['mapbox-gl', 'h3', 's2Geometry'], mapboxgl => {
require(['deck.gl', 'loaders.gl/csv'], (deck, loaders) => {
Expand Down
5 changes: 2 additions & 3 deletions modules/jupyter-widget/src/plugin.js
Expand Up @@ -4,7 +4,7 @@
* https://github.com/jupyter-widgets/widget-ts-cookiecutter/blob/51e9fed8687e3b9cf1ed2fd307b7675e864f89ae/%7B%7Bcookiecutter.github_project_name%7D%7D/src/plugin.ts
*/
import {IJupyterWidgetRegistry} from '@jupyter-widgets/base';
import {DeckGLView, DeckGLModel} from './lab-widget';
import * as widgetExports from './lab-widget';
import {MODULE_NAME, MODULE_VERSION} from './version';

const EXTENSION_ID = '@deck.gl/jupyter-widget:plugin';
Expand All @@ -17,11 +17,10 @@ const widgetPlugin = {
};

export default widgetPlugin;

function activateWidgetExtension(app, registry) {
registry.registerWidget({
name: MODULE_NAME,
version: MODULE_VERSION,
exports: {DeckGLView, DeckGLModel}
exports: widgetExports
});
}
25 changes: 23 additions & 2 deletions modules/jupyter-widget/src/widget.js
Expand Up @@ -3,10 +3,31 @@ import {DOMWidgetModel, DOMWidgetView} from '@jupyter-widgets/base';

import {MODULE_NAME, MODULE_VERSION} from './version';

import {loadCss, hideMapboxCSSWarning, updateDeck} from './notebook-utils';

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

/**
* Hides a warning in the mapbox-gl.js library from surfacing in the notebook as text.
*/
function hideMapboxCSSWarning() {
const missingCssWarning = document.getElementsByClassName('mapboxgl-missing-css')[0];
if (missingCssWarning) {
missingCssWarning.style.display = 'none';
}
}

function loadCss(url) {
const link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
document.getElementsByTagName('head')[0].appendChild(link);
}

function updateDeck(inputJSON, {jsonConverter, deckgl}) {
const results = jsonConverter.convert(inputJSON);
deckgl.setProps(results);
}

// Note: Variables shared explictly between Python and JavaScript use snake_case
export class DeckGLModel extends DOMWidgetModel {
defaults() {
Expand Down

0 comments on commit 13591ff

Please sign in to comment.