diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..3b8482a503ff6802c13466afeb92140d09812466 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,35 @@ +FROM jupyter/minimal-notebook +USER root + +RUN mkdir /software +WORKDIR /software + +RUN wget 'https://www.paraview.org/files/v5.7/ParaView-5.7.0-osmesa-MPI-Linux-Python3.7-64bit.tar.gz' \ + && tar xf ParaView-5.7.0-osmesa-MPI-Linux-Python3.7-64bit.tar.gz \ + && rm ParaView-5.7.0-osmesa-MPI-Linux-Python3.7-64bit.tar.gz + +ENV PATH="/software/ParaView-5.7.0-osmesa-MPI-Linux-Python3.7-64bit/bin:${PATH}" +RUN apt-get update && apt-get -y install openssh-server net-tools \ + && rm -rf /var/lib/apt/lists/* + +USER $NB_UID +WORKDIR /home/$NB_USER/work + +COPY --chown=1000:100 pvlink /home/$NB_USER/.jupyter/pvlink +COPY --chown=1000:100 pv_server.py /home/$NB_USER/work/ +COPY --chown=1000:100 remoterenderer_test.ipynb /home/$NB_USER/work/ + +RUN pip install service_identity \ + voila \ + ipyvuetify voila-vuetify \ + /home/$NB_USER/.jupyter/pvlink \ + && jupyter labextension install --no-build \ + @jupyter-widgets/jupyterlab-manager \ + @jupyter-voila/jupyterlab-preview \ + jupyter-vuetify \ + /home/$NB_USER/.jupyter/pvlink/js \ + && jupyter lab build && jupyter lab clean \ + && npm cache clean --force \ + && rm -rf $CONDA_DIR/share/jupyter/lab/staging \ + && rm -rf /home/$NB_USER/.cache/yarn \ + && rm -rf /home/$NB_USER/.node-gyp \ No newline at end of file diff --git a/docker/pv_server.py b/docker/pv_server.py new file mode 100644 index 0000000000000000000000000000000000000000..d429c47016b11519b113d35c138c9fbc2be45744 --- /dev/null +++ b/docker/pv_server.py @@ -0,0 +1,62 @@ +# add paraview modules +import sys +sys.path.append('/home/grosch/Devel/install/ParaView-v5.6.0/build/lib/python3.6/site-packages/') + +# import to process args +import os + +# import paraview modules. +from paraview.web import pv_wslink +from paraview.web import protocols as pv_protocols + +from paraview import simple +from wslink import server + +try: + import argparse +except ImportError: + # since Python 2.6 and earlier don't have argparse, we simply provide + # the source for the same as _argparse and we use it instead. + from vtk.util import _argparse as argparse + +# ============================================================================= +# Create custom PVServerProtocol class to handle clients requests +# ============================================================================= + +class _DemoServer(pv_wslink.PVServerProtocol): + authKey = "wslink-secret" + def initialize(self): + # Bring used components + self.registerVtkWebProtocol(pv_protocols.ParaViewWebMouseHandler()) + self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPort()) + self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPortImageDelivery()) + self.updateSecret(_DemoServer.authKey) + + # Disable interactor-based render calls + simple.GetRenderView().EnableRenderOnInteraction = 0 + simple.GetRenderView().Background = [0,0,0] + cone = simple.Cone() + simple.Show(cone) + simple.Render() + + # Update interaction mode + pxm = simple.servermanager.ProxyManager() + interactionProxy = pxm.GetProxy('settings', 'RenderViewInteractionSettings') + interactionProxy.Camera3DManipulators = ['Rotate', 'Pan', 'Zoom', 'Pan', 'Roll', 'Pan', 'Zoom', 'Rotate', 'Zoom'] + +# ============================================================================= +# Main: Parse args and start server +# ============================================================================= + +if __name__ == "__main__": + # Create argument parser + parser = argparse.ArgumentParser(description="ParaViewWeb Demo") + + # Add default arguments + server.add_arguments(parser) + + # Extract arguments + args = parser.parse_args() + + # Start server + server.start_webserver(options=args, protocol=_DemoServer) \ No newline at end of file diff --git a/docker/pvlink/MANIFEST.in b/docker/pvlink/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..a5ba7c1212ed3cbf612464a290d05db4a796c8fa --- /dev/null +++ b/docker/pvlink/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include pvlink/static *.* +include pvlink.json diff --git a/docker/pvlink/README.md b/docker/pvlink/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d24623785198c7583b558ebb0f7e976ebad028de --- /dev/null +++ b/docker/pvlink/README.md @@ -0,0 +1,35 @@ +pvlink +=============================== + +Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook + +Installation +------------ + +To install use pip: + + $ pip install pvlink + $ jupyter nbextension enable --py --sys-prefix pvlink + +To install for jupyterlab + + $ jupyter labextension install pvlink + +For a development installation (requires npm), + + $ git clone https://github.com//pvlink.git + $ cd pvlink + $ pip install -e . + $ jupyter nbextension install --py --symlink --sys-prefix pvlink + $ jupyter nbextension enable --py --sys-prefix pvlink + $ jupyter labextension install js + +When actively developing your extension, build Jupyter Lab with the command: + + $ jupyter lab --watch + +This take a minute or so to get started, but then allows you to hot-reload your javascript extension. +To see a change, save your javascript, watch the terminal for an update. + +Note on first `jupyter lab --watch`, you may need to touch a file to get Jupyter Lab to open. + diff --git a/docker/pvlink/RELEASE.md b/docker/pvlink/RELEASE.md new file mode 100644 index 0000000000000000000000000000000000000000..d6bc7932c158377af05f436e11468dccc7ec070f --- /dev/null +++ b/docker/pvlink/RELEASE.md @@ -0,0 +1,20 @@ +- To release a new version of pvlink on PyPI: + +Update _version.py (set release version, remove 'dev') +git add the _version.py file and git commit +`python setup.py sdist upload` +`python setup.py bdist_wheel upload` +`git tag -a X.X.X -m 'comment'` +Update _version.py (add 'dev' and increment minor) +git add and git commit +git push +git push --tags + +- To release a new version of pvlink on NPM: + +``` +# clean out the `dist` and `node_modules` directories +git clean -fdx +npm install +npm publish +``` \ No newline at end of file diff --git a/docker/pvlink/js/README.md b/docker/pvlink/js/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a2d42d8fbc010645bbc3768e2071ef06f75bb46c --- /dev/null +++ b/docker/pvlink/js/README.md @@ -0,0 +1,11 @@ +Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook + +Package Install +--------------- + +**Prerequisites** +- [node](http://nodejs.org/) + +```bash +npm install --save pvlink +``` diff --git a/docker/pvlink/js/lib/embed.js b/docker/pvlink/js/lib/embed.js new file mode 100644 index 0000000000000000000000000000000000000000..84c6809d485106d85af765bfb60ac3293b4cb078 --- /dev/null +++ b/docker/pvlink/js/lib/embed.js @@ -0,0 +1,9 @@ +// Entry point for the unpkg bundle containing custom model definitions. +// +// It differs from the notebook bundle in that it does not need to define a +// dynamic baseURL for the static assets and may load some css that would +// already be loaded by the notebook otherwise. + +// Export widget models and views, and the npm package version number. +module.exports = require('./remoterenderer.js'); +module.exports['version'] = require('../package.json').version; diff --git a/docker/pvlink/js/lib/extension.js b/docker/pvlink/js/lib/extension.js new file mode 100644 index 0000000000000000000000000000000000000000..bdbe3e4ca3e18b468c60e8025a73fea332971f04 --- /dev/null +++ b/docker/pvlink/js/lib/extension.js @@ -0,0 +1,25 @@ +// This file contains the javascript that is run when the notebook is loaded. +// It contains some requirejs configuration and the `load_ipython_extension` +// which is required for any notebook extension. +// +// 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. +__webpack_public_path__ = document.querySelector('body').getAttribute('data-base-url') + 'nbextensions/pvlink'; + + +// Configure requirejs +if (window.require) { + window.require.config({ + map: { + "*" : { + "pvlink": "nbextensions/pvlink/index", + } + } + }); +} + +// Export the required load_ipython_extension +module.exports = { + load_ipython_extension: function() {} +}; diff --git a/docker/pvlink/js/lib/index.js b/docker/pvlink/js/lib/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8c04d96da084ffef45f7f012e6c2755888ff3d54 --- /dev/null +++ b/docker/pvlink/js/lib/index.js @@ -0,0 +1,3 @@ +// Export widget models and views, and the npm package version number. +module.exports = require('./remoterenderer.js'); +module.exports['version'] = require('../package.json').version; diff --git a/docker/pvlink/js/lib/labplugin.js b/docker/pvlink/js/lib/labplugin.js new file mode 100644 index 0000000000000000000000000000000000000000..d5318e98dcfc0ea740c7c6916b4b4d929009c520 --- /dev/null +++ b/docker/pvlink/js/lib/labplugin.js @@ -0,0 +1,16 @@ +var plugin = require('./index'); +var base = require('@jupyter-widgets/base'); + +module.exports = { + id: 'pvlink', + requires: [base.IJupyterWidgetRegistry], + activate: function(app, widgets) { + widgets.registerWidget({ + name: 'pvlink', + version: plugin.version, + exports: plugin + }); + }, + autoStart: true +}; + diff --git a/docker/pvlink/js/lib/remoterenderer.js b/docker/pvlink/js/lib/remoterenderer.js new file mode 100644 index 0000000000000000000000000000000000000000..8fc7f085e032dcb44fea4bba794f56a9a3158d19 --- /dev/null +++ b/docker/pvlink/js/lib/remoterenderer.js @@ -0,0 +1,73 @@ +var widgets = require('@jupyter-widgets/base'); +var _ = require('lodash'); + +import ParaViewWebClient from 'paraviewweb/src/IO/WebSocket/ParaViewWebClient'; +import RemoteRenderer from 'paraviewweb/src/NativeUI/Canvas/RemoteRenderer'; +import SizeHelper from "paraviewweb/src/Common/Misc/SizeHelper"; +import SmartConnect from 'wslink/src/SmartConnect'; + +export var RemoteRendererModel = widgets.DOMWidgetModel.extend({ + defaults: _.extend(widgets.DOMWidgetModel.prototype.defaults(), { + _model_name: 'RemoteRendererModel', + _view_name: 'RemoteRendererView', + _model_module: 'pvlink', + _view_module: 'pvlink', + _model_module_version: '0.1.0', + _view_module_version: '0.1.0', + }) +}); + +export var RemoteRendererView = widgets.DOMWidgetView.extend({ + render: function () { + var that = this; + + // div to hold the canvas of the RemoteRenderer. + var render_div = document.createElement('div'); + render_div.style.height = '100%'; + render_div.style.width = '100%'; + this.el.appendChild(render_div); + + /* Get configuration for SmartConnect. + * SmartConnect will establish a direct + * WebSocket connection using Autobahn. + */ + var config = { + sessionURL: this.model.get('sessionURL'), + secret: this.model.get('authKey') + }; + var smartConnect = SmartConnect.newInstance({ config: config }); + + smartConnect.onConnectionReady(function (connection) { + // Create the RemoteRenderer + var pvwClient = ParaViewWebClient.createClient(connection, [ + 'MouseHandler', + 'ViewPort', + 'ViewPortImageDelivery'] + ); + var renderer = new RemoteRenderer(pvwClient); + renderer.setContainer(render_div); + renderer.setView(that.model.get('viewID')); + renderer.onImageReady(function () { + // Resize when the renderer is placed within a widget. + if (that.el.style.width != '100%') { + that.el.style.width = '100%'; + renderer.resize(); + } + console.log("We are good."); + }); + + // Handle size changes when the entire window is resized. + SizeHelper.onSizeChange(function () { + renderer.resize(); + }); + SizeHelper.startListening(); + + // Explicit render called from python side. + that.model.on('change:_update', function () { + renderer.render(true); + }, that); + }); + + smartConnect.connect(); + }, +}); diff --git a/docker/pvlink/js/package.json b/docker/pvlink/js/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6a4417948970b58eb43e8393f1ad6640b80f6c80 --- /dev/null +++ b/docker/pvlink/js/package.json @@ -0,0 +1,44 @@ +{ + "name": "pvlink", + "version": "0.1.0", + "description": "Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook", + "author": "Alice Grosch", + "main": "lib/index.js", + "repository": { + "type": "git", + "url": "https://github.com//pvlink.git" + }, + "keywords": [ + "jupyter", + "widgets", + "ipython", + "ipywidgets", + "jupyterlab-extension" + ], + "files": [ + "lib/**/*.js", + "dist/*.js" + ], + "scripts": { + "clean": "rimraf dist/", + "prepublish": "webpack", + "build": "webpack", + "watch": "webpack --watch --mode=development", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "devDependencies": { + "webpack": "^3.5.5", + "rimraf": "^2.6.1" + }, + "dependencies": { + "@jupyter-widgets/base": "^1.1 || ^2", + "lodash": "^4.17.4", + "hammerjs": "^2.0.8", + "monologue.js": "^0.3.5", + "paraviewweb": "^3.2.12", + "wslink": "^0.1.12" + }, + "jupyterlab": { + "extension": "lib/labplugin" + } +} diff --git a/docker/pvlink/js/webpack.config.js b/docker/pvlink/js/webpack.config.js new file mode 100644 index 0000000000000000000000000000000000000000..372bbe234cdc00cb05c77ebb80b94cdc5597b084 --- /dev/null +++ b/docker/pvlink/js/webpack.config.js @@ -0,0 +1,72 @@ +var path = require('path'); +var version = require('./package.json').version; + +// Custom webpack rules are generally the same for all webpack bundles, hence +// stored in a separate local variable. +var rules = [ + { test: /\.css$/, use: ['style-loader', 'css-loader']} +] + + +module.exports = [ + {// Notebook extension + // + // This bundle only contains the part of the JavaScript that is run on + // load of the notebook. This section generally only performs + // some configuration for requirejs, and provides the legacy + // "load_ipython_extension" function which is required for any notebook + // extension. + // + entry: './lib/extension.js', + output: { + filename: 'extension.js', + path: path.resolve(__dirname, '..', 'pvlink', 'static'), + libraryTarget: 'amd' + } + }, + {// Bundle for the notebook containing the custom widget views and models + // + // This bundle contains the implementation for the custom widget views and + // custom widget. + // It must be an amd module + // + entry: './lib/index.js', + output: { + filename: 'index.js', + path: path.resolve(__dirname, '..', 'pvlink', 'static'), + libraryTarget: 'amd' + }, + devtool: 'source-map', + module: { + rules: rules + }, + externals: ['@jupyter-widgets/base'] + }, + {// Embeddable pvlink bundle + // + // This bundle is generally almost identical to the notebook bundle + // containing the custom widget views and models. + // + // The only difference is in the configuration of the webpack public path + // for the static assets. + // + // It will be automatically distributed by unpkg to work with the static + // widget embedder. + // + // The target bundle is always `dist/index.js`, which is the path required + // by the custom widget embedder. + // + entry: './lib/embed.js', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'amd', + publicPath: 'https://unpkg.com/pvlink@' + version + '/dist/' + }, + devtool: 'source-map', + module: { + rules: rules + }, + externals: ['@jupyter-widgets/base'] + } +]; diff --git a/docker/pvlink/pvlink.json b/docker/pvlink/pvlink.json new file mode 100644 index 0000000000000000000000000000000000000000..ce45f56f6b937a77442d9c1530747c16508750b3 --- /dev/null +++ b/docker/pvlink/pvlink.json @@ -0,0 +1,5 @@ +{ + "load_extensions": { + "pvlink/extension": true + } +} diff --git a/docker/pvlink/pvlink/MANIFEST.in b/docker/pvlink/pvlink/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..a5ba7c1212ed3cbf612464a290d05db4a796c8fa --- /dev/null +++ b/docker/pvlink/pvlink/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include pvlink/static *.* +include pvlink.json diff --git a/docker/pvlink/pvlink/README.md b/docker/pvlink/pvlink/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d24623785198c7583b558ebb0f7e976ebad028de --- /dev/null +++ b/docker/pvlink/pvlink/README.md @@ -0,0 +1,35 @@ +pvlink +=============================== + +Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook + +Installation +------------ + +To install use pip: + + $ pip install pvlink + $ jupyter nbextension enable --py --sys-prefix pvlink + +To install for jupyterlab + + $ jupyter labextension install pvlink + +For a development installation (requires npm), + + $ git clone https://github.com//pvlink.git + $ cd pvlink + $ pip install -e . + $ jupyter nbextension install --py --symlink --sys-prefix pvlink + $ jupyter nbextension enable --py --sys-prefix pvlink + $ jupyter labextension install js + +When actively developing your extension, build Jupyter Lab with the command: + + $ jupyter lab --watch + +This take a minute or so to get started, but then allows you to hot-reload your javascript extension. +To see a change, save your javascript, watch the terminal for an update. + +Note on first `jupyter lab --watch`, you may need to touch a file to get Jupyter Lab to open. + diff --git a/docker/pvlink/pvlink/RELEASE.md b/docker/pvlink/pvlink/RELEASE.md new file mode 100644 index 0000000000000000000000000000000000000000..d6bc7932c158377af05f436e11468dccc7ec070f --- /dev/null +++ b/docker/pvlink/pvlink/RELEASE.md @@ -0,0 +1,20 @@ +- To release a new version of pvlink on PyPI: + +Update _version.py (set release version, remove 'dev') +git add the _version.py file and git commit +`python setup.py sdist upload` +`python setup.py bdist_wheel upload` +`git tag -a X.X.X -m 'comment'` +Update _version.py (add 'dev' and increment minor) +git add and git commit +git push +git push --tags + +- To release a new version of pvlink on NPM: + +``` +# clean out the `dist` and `node_modules` directories +git clean -fdx +npm install +npm publish +``` \ No newline at end of file diff --git a/docker/pvlink/pvlink/__init__.py b/docker/pvlink/pvlink/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..cb1c0b2cc962d83068190085d8d66ba7e11f4d72 --- /dev/null +++ b/docker/pvlink/pvlink/__init__.py @@ -0,0 +1,11 @@ +from ._version import version_info, __version__ + +from .remoterenderer import * + +def _jupyter_nbextension_paths(): + return [{ + 'section': 'notebook', + 'src': 'static', + 'dest': 'pvlink', + 'require': 'pvlink/extension' + }] diff --git a/docker/pvlink/pvlink/_version.py b/docker/pvlink/pvlink/_version.py new file mode 100644 index 0000000000000000000000000000000000000000..ed74cad81423128d33c830d30531df907ca88a33 --- /dev/null +++ b/docker/pvlink/pvlink/_version.py @@ -0,0 +1,6 @@ +version_info = (0, 1, 0, 'alpha', 0) + +_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''} + +__version__ = '%s.%s.%s%s'%(version_info[0], version_info[1], version_info[2], + '' if version_info[3]=='final' else _specifier_[version_info[3]]+str(version_info[4])) diff --git a/docker/pvlink/pvlink/js/README.md b/docker/pvlink/pvlink/js/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a2d42d8fbc010645bbc3768e2071ef06f75bb46c --- /dev/null +++ b/docker/pvlink/pvlink/js/README.md @@ -0,0 +1,11 @@ +Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook + +Package Install +--------------- + +**Prerequisites** +- [node](http://nodejs.org/) + +```bash +npm install --save pvlink +``` diff --git a/docker/pvlink/pvlink/js/lib/embed.js b/docker/pvlink/pvlink/js/lib/embed.js new file mode 100644 index 0000000000000000000000000000000000000000..84c6809d485106d85af765bfb60ac3293b4cb078 --- /dev/null +++ b/docker/pvlink/pvlink/js/lib/embed.js @@ -0,0 +1,9 @@ +// Entry point for the unpkg bundle containing custom model definitions. +// +// It differs from the notebook bundle in that it does not need to define a +// dynamic baseURL for the static assets and may load some css that would +// already be loaded by the notebook otherwise. + +// Export widget models and views, and the npm package version number. +module.exports = require('./remoterenderer.js'); +module.exports['version'] = require('../package.json').version; diff --git a/docker/pvlink/pvlink/js/lib/extension.js b/docker/pvlink/pvlink/js/lib/extension.js new file mode 100644 index 0000000000000000000000000000000000000000..bdbe3e4ca3e18b468c60e8025a73fea332971f04 --- /dev/null +++ b/docker/pvlink/pvlink/js/lib/extension.js @@ -0,0 +1,25 @@ +// This file contains the javascript that is run when the notebook is loaded. +// It contains some requirejs configuration and the `load_ipython_extension` +// which is required for any notebook extension. +// +// 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. +__webpack_public_path__ = document.querySelector('body').getAttribute('data-base-url') + 'nbextensions/pvlink'; + + +// Configure requirejs +if (window.require) { + window.require.config({ + map: { + "*" : { + "pvlink": "nbextensions/pvlink/index", + } + } + }); +} + +// Export the required load_ipython_extension +module.exports = { + load_ipython_extension: function() {} +}; diff --git a/docker/pvlink/pvlink/js/lib/index.js b/docker/pvlink/pvlink/js/lib/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8c04d96da084ffef45f7f012e6c2755888ff3d54 --- /dev/null +++ b/docker/pvlink/pvlink/js/lib/index.js @@ -0,0 +1,3 @@ +// Export widget models and views, and the npm package version number. +module.exports = require('./remoterenderer.js'); +module.exports['version'] = require('../package.json').version; diff --git a/docker/pvlink/pvlink/js/lib/labplugin.js b/docker/pvlink/pvlink/js/lib/labplugin.js new file mode 100644 index 0000000000000000000000000000000000000000..d5318e98dcfc0ea740c7c6916b4b4d929009c520 --- /dev/null +++ b/docker/pvlink/pvlink/js/lib/labplugin.js @@ -0,0 +1,16 @@ +var plugin = require('./index'); +var base = require('@jupyter-widgets/base'); + +module.exports = { + id: 'pvlink', + requires: [base.IJupyterWidgetRegistry], + activate: function(app, widgets) { + widgets.registerWidget({ + name: 'pvlink', + version: plugin.version, + exports: plugin + }); + }, + autoStart: true +}; + diff --git a/docker/pvlink/pvlink/js/lib/remoterenderer.js b/docker/pvlink/pvlink/js/lib/remoterenderer.js new file mode 100644 index 0000000000000000000000000000000000000000..8fc7f085e032dcb44fea4bba794f56a9a3158d19 --- /dev/null +++ b/docker/pvlink/pvlink/js/lib/remoterenderer.js @@ -0,0 +1,73 @@ +var widgets = require('@jupyter-widgets/base'); +var _ = require('lodash'); + +import ParaViewWebClient from 'paraviewweb/src/IO/WebSocket/ParaViewWebClient'; +import RemoteRenderer from 'paraviewweb/src/NativeUI/Canvas/RemoteRenderer'; +import SizeHelper from "paraviewweb/src/Common/Misc/SizeHelper"; +import SmartConnect from 'wslink/src/SmartConnect'; + +export var RemoteRendererModel = widgets.DOMWidgetModel.extend({ + defaults: _.extend(widgets.DOMWidgetModel.prototype.defaults(), { + _model_name: 'RemoteRendererModel', + _view_name: 'RemoteRendererView', + _model_module: 'pvlink', + _view_module: 'pvlink', + _model_module_version: '0.1.0', + _view_module_version: '0.1.0', + }) +}); + +export var RemoteRendererView = widgets.DOMWidgetView.extend({ + render: function () { + var that = this; + + // div to hold the canvas of the RemoteRenderer. + var render_div = document.createElement('div'); + render_div.style.height = '100%'; + render_div.style.width = '100%'; + this.el.appendChild(render_div); + + /* Get configuration for SmartConnect. + * SmartConnect will establish a direct + * WebSocket connection using Autobahn. + */ + var config = { + sessionURL: this.model.get('sessionURL'), + secret: this.model.get('authKey') + }; + var smartConnect = SmartConnect.newInstance({ config: config }); + + smartConnect.onConnectionReady(function (connection) { + // Create the RemoteRenderer + var pvwClient = ParaViewWebClient.createClient(connection, [ + 'MouseHandler', + 'ViewPort', + 'ViewPortImageDelivery'] + ); + var renderer = new RemoteRenderer(pvwClient); + renderer.setContainer(render_div); + renderer.setView(that.model.get('viewID')); + renderer.onImageReady(function () { + // Resize when the renderer is placed within a widget. + if (that.el.style.width != '100%') { + that.el.style.width = '100%'; + renderer.resize(); + } + console.log("We are good."); + }); + + // Handle size changes when the entire window is resized. + SizeHelper.onSizeChange(function () { + renderer.resize(); + }); + SizeHelper.startListening(); + + // Explicit render called from python side. + that.model.on('change:_update', function () { + renderer.render(true); + }, that); + }); + + smartConnect.connect(); + }, +}); diff --git a/docker/pvlink/pvlink/js/package.json b/docker/pvlink/pvlink/js/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1fab78cf58533be0fcbb6446ddc67ec1d888ced6 --- /dev/null +++ b/docker/pvlink/pvlink/js/package.json @@ -0,0 +1,44 @@ +{ + "name": "pvlink", + "version": "0.1.0", + "description": "Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook", + "author": "Alice Grosch", + "main": "lib/index.js", + "repository": { + "type": "git", + "url": "https://github.com//pvlink.git" + }, + "keywords": [ + "jupyter", + "widgets", + "ipython", + "ipywidgets", + "jupyterlab-extension" + ], + "files": [ + "lib/**/*.js", + "dist/*.js" + ], + "scripts": { + "clean": "rimraf dist/", + "prepublish": "webpack", + "build": "webpack", + "watch": "webpack --watch --mode=development", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "devDependencies": { + "webpack": "^3.5.5", + "rimraf": "^2.6.1", + "hammerjs": "^2.0.8", + "monologue.js": "^0.3.5" + }, + "dependencies": { + "@jupyter-widgets/base": "^1.1 || ^2", + "lodash": "^4.17.4", + "paraviewweb": "^3.2.12", + "wslink": "^0.1.12" + }, + "jupyterlab": { + "extension": "lib/labplugin" + } +} diff --git a/docker/pvlink/pvlink/js/webpack.config.js b/docker/pvlink/pvlink/js/webpack.config.js new file mode 100644 index 0000000000000000000000000000000000000000..372bbe234cdc00cb05c77ebb80b94cdc5597b084 --- /dev/null +++ b/docker/pvlink/pvlink/js/webpack.config.js @@ -0,0 +1,72 @@ +var path = require('path'); +var version = require('./package.json').version; + +// Custom webpack rules are generally the same for all webpack bundles, hence +// stored in a separate local variable. +var rules = [ + { test: /\.css$/, use: ['style-loader', 'css-loader']} +] + + +module.exports = [ + {// Notebook extension + // + // This bundle only contains the part of the JavaScript that is run on + // load of the notebook. This section generally only performs + // some configuration for requirejs, and provides the legacy + // "load_ipython_extension" function which is required for any notebook + // extension. + // + entry: './lib/extension.js', + output: { + filename: 'extension.js', + path: path.resolve(__dirname, '..', 'pvlink', 'static'), + libraryTarget: 'amd' + } + }, + {// Bundle for the notebook containing the custom widget views and models + // + // This bundle contains the implementation for the custom widget views and + // custom widget. + // It must be an amd module + // + entry: './lib/index.js', + output: { + filename: 'index.js', + path: path.resolve(__dirname, '..', 'pvlink', 'static'), + libraryTarget: 'amd' + }, + devtool: 'source-map', + module: { + rules: rules + }, + externals: ['@jupyter-widgets/base'] + }, + {// Embeddable pvlink bundle + // + // This bundle is generally almost identical to the notebook bundle + // containing the custom widget views and models. + // + // The only difference is in the configuration of the webpack public path + // for the static assets. + // + // It will be automatically distributed by unpkg to work with the static + // widget embedder. + // + // The target bundle is always `dist/index.js`, which is the path required + // by the custom widget embedder. + // + entry: './lib/embed.js', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'amd', + publicPath: 'https://unpkg.com/pvlink@' + version + '/dist/' + }, + devtool: 'source-map', + module: { + rules: rules + }, + externals: ['@jupyter-widgets/base'] + } +]; diff --git a/docker/pvlink/pvlink/pv_server.py b/docker/pvlink/pvlink/pv_server.py new file mode 100644 index 0000000000000000000000000000000000000000..d429c47016b11519b113d35c138c9fbc2be45744 --- /dev/null +++ b/docker/pvlink/pvlink/pv_server.py @@ -0,0 +1,62 @@ +# add paraview modules +import sys +sys.path.append('/home/grosch/Devel/install/ParaView-v5.6.0/build/lib/python3.6/site-packages/') + +# import to process args +import os + +# import paraview modules. +from paraview.web import pv_wslink +from paraview.web import protocols as pv_protocols + +from paraview import simple +from wslink import server + +try: + import argparse +except ImportError: + # since Python 2.6 and earlier don't have argparse, we simply provide + # the source for the same as _argparse and we use it instead. + from vtk.util import _argparse as argparse + +# ============================================================================= +# Create custom PVServerProtocol class to handle clients requests +# ============================================================================= + +class _DemoServer(pv_wslink.PVServerProtocol): + authKey = "wslink-secret" + def initialize(self): + # Bring used components + self.registerVtkWebProtocol(pv_protocols.ParaViewWebMouseHandler()) + self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPort()) + self.registerVtkWebProtocol(pv_protocols.ParaViewWebViewPortImageDelivery()) + self.updateSecret(_DemoServer.authKey) + + # Disable interactor-based render calls + simple.GetRenderView().EnableRenderOnInteraction = 0 + simple.GetRenderView().Background = [0,0,0] + cone = simple.Cone() + simple.Show(cone) + simple.Render() + + # Update interaction mode + pxm = simple.servermanager.ProxyManager() + interactionProxy = pxm.GetProxy('settings', 'RenderViewInteractionSettings') + interactionProxy.Camera3DManipulators = ['Rotate', 'Pan', 'Zoom', 'Pan', 'Roll', 'Pan', 'Zoom', 'Rotate', 'Zoom'] + +# ============================================================================= +# Main: Parse args and start server +# ============================================================================= + +if __name__ == "__main__": + # Create argument parser + parser = argparse.ArgumentParser(description="ParaViewWeb Demo") + + # Add default arguments + server.add_arguments(parser) + + # Extract arguments + args = parser.parse_args() + + # Start server + server.start_webserver(options=args, protocol=_DemoServer) \ No newline at end of file diff --git a/docker/pvlink/pvlink/pvlink.json b/docker/pvlink/pvlink/pvlink.json new file mode 100644 index 0000000000000000000000000000000000000000..ce45f56f6b937a77442d9c1530747c16508750b3 --- /dev/null +++ b/docker/pvlink/pvlink/pvlink.json @@ -0,0 +1,5 @@ +{ + "load_extensions": { + "pvlink/extension": true + } +} diff --git a/docker/pvlink/pvlink/pvlink/__init__.py b/docker/pvlink/pvlink/pvlink/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..cb1c0b2cc962d83068190085d8d66ba7e11f4d72 --- /dev/null +++ b/docker/pvlink/pvlink/pvlink/__init__.py @@ -0,0 +1,11 @@ +from ._version import version_info, __version__ + +from .remoterenderer import * + +def _jupyter_nbextension_paths(): + return [{ + 'section': 'notebook', + 'src': 'static', + 'dest': 'pvlink', + 'require': 'pvlink/extension' + }] diff --git a/docker/pvlink/pvlink/pvlink/_version.py b/docker/pvlink/pvlink/pvlink/_version.py new file mode 100644 index 0000000000000000000000000000000000000000..ed74cad81423128d33c830d30531df907ca88a33 --- /dev/null +++ b/docker/pvlink/pvlink/pvlink/_version.py @@ -0,0 +1,6 @@ +version_info = (0, 1, 0, 'alpha', 0) + +_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''} + +__version__ = '%s.%s.%s%s'%(version_info[0], version_info[1], version_info[2], + '' if version_info[3]=='final' else _specifier_[version_info[3]]+str(version_info[4])) diff --git a/docker/pvlink/pvlink/pvlink/remoterenderer.py b/docker/pvlink/pvlink/pvlink/remoterenderer.py new file mode 100644 index 0000000000000000000000000000000000000000..0f5937846cf4015962adf10f0de88493531dd6f7 --- /dev/null +++ b/docker/pvlink/pvlink/pvlink/remoterenderer.py @@ -0,0 +1,34 @@ +import ipywidgets as widgets +from traitlets import Unicode, Int + +@widgets.register +class RemoteRenderer(widgets.DOMWidget): + """ParaviewWeb RemoteRenderer for the Jupyter Notebook.""" + _view_name = Unicode('RemoteRendererView').tag(sync=True) + _model_name = Unicode('RemoteRendererModel').tag(sync=True) + _view_module = Unicode('pvlink').tag(sync=True) + _model_module = Unicode('pvlink').tag(sync=True) + _view_module_version = Unicode('^0.1.0').tag(sync=True) + _model_module_version = Unicode('^0.1.0').tag(sync=True) + + # URL to establish a websocket connection to. + sessionURL = Unicode('ws://localhost:8080/ws').tag(sync=True) + # Authentication key for clients to connect to the WebSocket. + authKey = Unicode('wslink-secret').tag(sync=True) + # ViewID of the view to connect to (only relevant + # if multiple views exist on the server side). + viewID = Unicode("-1").tag(sync=True) + # Placeholder to force rendering updates on change. + _update = Int(0).tag(sync=True) + + + def __init__(self, sessionURL='ws://localhost:8080/ws', authKey='wslink-secret', viewID='-1', *args, **kwargs): + super(RemoteRenderer, self).__init__(*args, **kwargs) + self.sessionURL = sessionURL + self.authKey = authKey + self.viewID = viewID + + + def update_render(self): + """Explicit call for the renderer on the javascript side to render.""" + self._update += 1 \ No newline at end of file diff --git a/docker/pvlink/pvlink/remoterenderer.py b/docker/pvlink/pvlink/remoterenderer.py new file mode 100644 index 0000000000000000000000000000000000000000..0f5937846cf4015962adf10f0de88493531dd6f7 --- /dev/null +++ b/docker/pvlink/pvlink/remoterenderer.py @@ -0,0 +1,34 @@ +import ipywidgets as widgets +from traitlets import Unicode, Int + +@widgets.register +class RemoteRenderer(widgets.DOMWidget): + """ParaviewWeb RemoteRenderer for the Jupyter Notebook.""" + _view_name = Unicode('RemoteRendererView').tag(sync=True) + _model_name = Unicode('RemoteRendererModel').tag(sync=True) + _view_module = Unicode('pvlink').tag(sync=True) + _model_module = Unicode('pvlink').tag(sync=True) + _view_module_version = Unicode('^0.1.0').tag(sync=True) + _model_module_version = Unicode('^0.1.0').tag(sync=True) + + # URL to establish a websocket connection to. + sessionURL = Unicode('ws://localhost:8080/ws').tag(sync=True) + # Authentication key for clients to connect to the WebSocket. + authKey = Unicode('wslink-secret').tag(sync=True) + # ViewID of the view to connect to (only relevant + # if multiple views exist on the server side). + viewID = Unicode("-1").tag(sync=True) + # Placeholder to force rendering updates on change. + _update = Int(0).tag(sync=True) + + + def __init__(self, sessionURL='ws://localhost:8080/ws', authKey='wslink-secret', viewID='-1', *args, **kwargs): + super(RemoteRenderer, self).__init__(*args, **kwargs) + self.sessionURL = sessionURL + self.authKey = authKey + self.viewID = viewID + + + def update_render(self): + """Explicit call for the renderer on the javascript side to render.""" + self._update += 1 \ No newline at end of file diff --git a/docker/pvlink/pvlink/remoterenderer_test.ipynb b/docker/pvlink/pvlink/remoterenderer_test.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..420e318f3369a9a75e225a34af4a54f9d6bef3c8 --- /dev/null +++ b/docker/pvlink/pvlink/remoterenderer_test.ipynb @@ -0,0 +1,103 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from pvlink import RemoteRenderer" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b3d897da337443239c15f5346e046e55", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "RemoteRenderer()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "renderer = RemoteRenderer()\n", + "# renderer" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Box" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4428cc6539af4c0eb23f822bd10873df", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Box(children=(RemoteRenderer(),), layout=Layout(height='500px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = Box(children=[renderer])\n", + "out.layout.height = '500px'\n", + "out" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docker/pvlink/pvlink/setup.cfg b/docker/pvlink/pvlink/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3c6e79cf31da1c0433d2fa666bf50b53f6359f26 --- /dev/null +++ b/docker/pvlink/pvlink/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/docker/pvlink/pvlink/setup.py b/docker/pvlink/pvlink/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..fd55fd4ce7de4856a85fed780ad87b9d488e6958 --- /dev/null +++ b/docker/pvlink/pvlink/setup.py @@ -0,0 +1,180 @@ +from __future__ import print_function +from setuptools import setup, find_packages, Command +from setuptools.command.sdist import sdist +from setuptools.command.build_py import build_py +from setuptools.command.egg_info import egg_info +from subprocess import check_call +import os +import sys +import platform + +here = os.path.dirname(os.path.abspath(__file__)) +node_root = os.path.join(here, 'js') +is_repo = os.path.exists(os.path.join(here, '.git')) + +npm_path = os.pathsep.join([ + os.path.join(node_root, 'node_modules', '.bin'), + os.environ.get('PATH', os.defpath), +]) + +from distutils import log +log.set_verbosity(log.DEBUG) +log.info('setup.py entered') +log.info('$PATH=%s' % os.environ['PATH']) + +LONG_DESCRIPTION = 'Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook' + +def js_prerelease(command, strict=False): + """decorator for building minified js/css prior to another command""" + class DecoratedCommand(command): + def run(self): + jsdeps = self.distribution.get_command_obj('jsdeps') + if not is_repo and all(os.path.exists(t) for t in jsdeps.targets): + # sdist, nothing to do + command.run(self) + return + + try: + self.distribution.run_command('jsdeps') + except Exception as e: + missing = [t for t in jsdeps.targets if not os.path.exists(t)] + if strict or missing: + log.warn('rebuilding js and css failed') + if missing: + log.error('missing files: %s' % missing) + raise e + else: + log.warn('rebuilding js and css failed (not a problem)') + log.warn(str(e)) + command.run(self) + update_package_data(self.distribution) + return DecoratedCommand + +def update_package_data(distribution): + """update package_data to catch changes during setup""" + build_py = distribution.get_command_obj('build_py') + # distribution.package_data = find_package_data() + # re-init build_py options which load package_data + build_py.finalize_options() + + +class NPM(Command): + description = 'install package.json dependencies using npm' + + user_options = [] + + node_modules = os.path.join(node_root, 'node_modules') + + targets = [ + os.path.join(here, 'pvlink', 'static', 'extension.js'), + os.path.join(here, 'pvlink', 'static', 'index.js') + ] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def get_npm_name(self): + npmName = 'npm'; + if platform.system() == 'Windows': + npmName = 'npm.cmd'; + + return npmName; + + def has_npm(self): + npmName = self.get_npm_name(); + try: + check_call([npmName, '--version']) + return True + except: + return False + + def should_run_npm_install(self): + package_json = os.path.join(node_root, 'package.json') + node_modules_exists = os.path.exists(self.node_modules) + return self.has_npm() + + def run(self): + has_npm = self.has_npm() + if not has_npm: + log.error("`npm` unavailable. If you're running this command using sudo, make sure `npm` is available to sudo") + + env = os.environ.copy() + env['PATH'] = npm_path + + if self.should_run_npm_install(): + log.info("Installing build dependencies with npm. This may take a while...") + npmName = self.get_npm_name(); + check_call([npmName, 'install'], cwd=node_root, stdout=sys.stdout, stderr=sys.stderr) + os.utime(self.node_modules, None) + + for t in self.targets: + if not os.path.exists(t): + msg = 'Missing file: %s' % t + if not has_npm: + msg += '\nnpm is required to build a development version of a widget extension' + raise ValueError(msg) + + # update package data in case this created new files + update_package_data(self.distribution) + +version_ns = {} +with open(os.path.join(here, 'pvlink', '_version.py')) as f: + exec(f.read(), {}, version_ns) + +setup_args = { + 'name': 'pvlink', + 'version': version_ns['__version__'], + 'description': 'Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook', + 'long_description': LONG_DESCRIPTION, + 'include_package_data': True, + 'data_files': [ + ('share/jupyter/nbextensions/pvlink', [ + 'pvlink/static/extension.js', + 'pvlink/static/index.js', + 'pvlink/static/index.js.map', + ],), + ('etc/jupyter/nbconfig/notebook.d' ,['pvlink.json']) + ], + 'install_requires': [ + 'ipywidgets>=7.0.0', + 'wslink>=0.1.11', + 'twisted>=19.2.1', + ], + 'packages': find_packages(), + 'zip_safe': False, + 'cmdclass': { + 'build_py': js_prerelease(build_py), + 'egg_info': js_prerelease(egg_info), + 'sdist': js_prerelease(sdist, strict=True), + 'jsdeps': NPM, + }, + + 'author': 'Alice Grosch', + 'author_email': 'a.grosch@fz-juelich.de', + 'url': 'https://github.com//pvlink', + 'keywords': [ + 'ipython', + 'jupyter', + 'widgets', + ], + 'classifiers': [ + 'Development Status :: 4 - Beta', + 'Framework :: IPython', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Topic :: Multimedia :: Graphics', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + ], +} + +setup(**setup_args) diff --git a/docker/pvlink/setup.cfg b/docker/pvlink/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3c6e79cf31da1c0433d2fa666bf50b53f6359f26 --- /dev/null +++ b/docker/pvlink/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/docker/pvlink/setup.py b/docker/pvlink/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..fd55fd4ce7de4856a85fed780ad87b9d488e6958 --- /dev/null +++ b/docker/pvlink/setup.py @@ -0,0 +1,180 @@ +from __future__ import print_function +from setuptools import setup, find_packages, Command +from setuptools.command.sdist import sdist +from setuptools.command.build_py import build_py +from setuptools.command.egg_info import egg_info +from subprocess import check_call +import os +import sys +import platform + +here = os.path.dirname(os.path.abspath(__file__)) +node_root = os.path.join(here, 'js') +is_repo = os.path.exists(os.path.join(here, '.git')) + +npm_path = os.pathsep.join([ + os.path.join(node_root, 'node_modules', '.bin'), + os.environ.get('PATH', os.defpath), +]) + +from distutils import log +log.set_verbosity(log.DEBUG) +log.info('setup.py entered') +log.info('$PATH=%s' % os.environ['PATH']) + +LONG_DESCRIPTION = 'Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook' + +def js_prerelease(command, strict=False): + """decorator for building minified js/css prior to another command""" + class DecoratedCommand(command): + def run(self): + jsdeps = self.distribution.get_command_obj('jsdeps') + if not is_repo and all(os.path.exists(t) for t in jsdeps.targets): + # sdist, nothing to do + command.run(self) + return + + try: + self.distribution.run_command('jsdeps') + except Exception as e: + missing = [t for t in jsdeps.targets if not os.path.exists(t)] + if strict or missing: + log.warn('rebuilding js and css failed') + if missing: + log.error('missing files: %s' % missing) + raise e + else: + log.warn('rebuilding js and css failed (not a problem)') + log.warn(str(e)) + command.run(self) + update_package_data(self.distribution) + return DecoratedCommand + +def update_package_data(distribution): + """update package_data to catch changes during setup""" + build_py = distribution.get_command_obj('build_py') + # distribution.package_data = find_package_data() + # re-init build_py options which load package_data + build_py.finalize_options() + + +class NPM(Command): + description = 'install package.json dependencies using npm' + + user_options = [] + + node_modules = os.path.join(node_root, 'node_modules') + + targets = [ + os.path.join(here, 'pvlink', 'static', 'extension.js'), + os.path.join(here, 'pvlink', 'static', 'index.js') + ] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def get_npm_name(self): + npmName = 'npm'; + if platform.system() == 'Windows': + npmName = 'npm.cmd'; + + return npmName; + + def has_npm(self): + npmName = self.get_npm_name(); + try: + check_call([npmName, '--version']) + return True + except: + return False + + def should_run_npm_install(self): + package_json = os.path.join(node_root, 'package.json') + node_modules_exists = os.path.exists(self.node_modules) + return self.has_npm() + + def run(self): + has_npm = self.has_npm() + if not has_npm: + log.error("`npm` unavailable. If you're running this command using sudo, make sure `npm` is available to sudo") + + env = os.environ.copy() + env['PATH'] = npm_path + + if self.should_run_npm_install(): + log.info("Installing build dependencies with npm. This may take a while...") + npmName = self.get_npm_name(); + check_call([npmName, 'install'], cwd=node_root, stdout=sys.stdout, stderr=sys.stderr) + os.utime(self.node_modules, None) + + for t in self.targets: + if not os.path.exists(t): + msg = 'Missing file: %s' % t + if not has_npm: + msg += '\nnpm is required to build a development version of a widget extension' + raise ValueError(msg) + + # update package data in case this created new files + update_package_data(self.distribution) + +version_ns = {} +with open(os.path.join(here, 'pvlink', '_version.py')) as f: + exec(f.read(), {}, version_ns) + +setup_args = { + 'name': 'pvlink', + 'version': version_ns['__version__'], + 'description': 'Displays the ParaviewWeb RemoteRenderer in a Jupyter Notebook', + 'long_description': LONG_DESCRIPTION, + 'include_package_data': True, + 'data_files': [ + ('share/jupyter/nbextensions/pvlink', [ + 'pvlink/static/extension.js', + 'pvlink/static/index.js', + 'pvlink/static/index.js.map', + ],), + ('etc/jupyter/nbconfig/notebook.d' ,['pvlink.json']) + ], + 'install_requires': [ + 'ipywidgets>=7.0.0', + 'wslink>=0.1.11', + 'twisted>=19.2.1', + ], + 'packages': find_packages(), + 'zip_safe': False, + 'cmdclass': { + 'build_py': js_prerelease(build_py), + 'egg_info': js_prerelease(egg_info), + 'sdist': js_prerelease(sdist, strict=True), + 'jsdeps': NPM, + }, + + 'author': 'Alice Grosch', + 'author_email': 'a.grosch@fz-juelich.de', + 'url': 'https://github.com//pvlink', + 'keywords': [ + 'ipython', + 'jupyter', + 'widgets', + ], + 'classifiers': [ + 'Development Status :: 4 - Beta', + 'Framework :: IPython', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Topic :: Multimedia :: Graphics', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + ], +} + +setup(**setup_args) diff --git a/docker/remoterenderer_test.ipynb b/docker/remoterenderer_test.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..e6d7171c7f03e3c0e881562c592393e4b470df47 --- /dev/null +++ b/docker/remoterenderer_test.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from pvlink import RemoteRenderer" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "renderer = RemoteRenderer()\n", + "# renderer" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from ipywidgets import Box" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "36e64b966b4d47e49e00bb93c60714aa", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Box(children=(RemoteRenderer(),), layout=Layout(height='500px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = Box(children=[renderer])\n", + "out.layout.height = '500px'\n", + "out" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}