From 3820aecaf762a76e090e0f469324b597dff74530 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Mon, 9 Aug 2021 20:54:17 -0700 Subject: [PATCH] The keplergl-jupyter widget needs to be updated for JupyterLab 3 #882 #1565 #1165 Signed-off-by: Xun Li --- bindings/kepler.gl-jupyter/MANIFEST.in | 1 + bindings/kepler.gl-jupyter/js/package.json | 16 +- bindings/kepler.gl-jupyter/pyproject.toml | 3 + bindings/kepler.gl-jupyter/setup.py | 177 ++++++--------------- 4 files changed, 62 insertions(+), 135 deletions(-) create mode 100644 bindings/kepler.gl-jupyter/pyproject.toml diff --git a/bindings/kepler.gl-jupyter/MANIFEST.in b/bindings/kepler.gl-jupyter/MANIFEST.in index 11a5bc8ea9..071f7865e0 100644 --- a/bindings/kepler.gl-jupyter/MANIFEST.in +++ b/bindings/kepler.gl-jupyter/MANIFEST.in @@ -1,2 +1,3 @@ recursive-include keplergl/static *.* +recursive-include keplergl-jupyter/labextension *.* include keplergl-jupyter.json diff --git a/bindings/kepler.gl-jupyter/js/package.json b/bindings/kepler.gl-jupyter/js/package.json index 72e67d7a08..c8a2e41c25 100644 --- a/bindings/kepler.gl-jupyter/js/package.json +++ b/bindings/kepler.gl-jupyter/js/package.json @@ -27,7 +27,7 @@ "clean": "rimraf dist/ && rimraf ../keplergl/static/", "cleanall": "npm run clean && rimraf node_modules/", "prepublish": "yarn build && yarn build:lab", - "build": "npm run clean && webpack --config ./webpack/build.js", + "build": "npm run clean && webpack --config ./webpack/build.js && jupyter labextension build .", "build:lab": "rimraf babel/ && mkdir babel && babel lib --out-dir babel", "test": "echo \"Error: no test specified\" && exit 1", "lint": "eslint lib webpack --fix", @@ -61,7 +61,8 @@ "webpack-stats-plugin": "^0.2.1" }, "dependencies": { - "@jupyter-widgets/base": "^1.1.10 || ^2.0.0 || ^3.0.0", + "@jupyter-widgets/base": "^2 || ^3 || ^4.0.0", + "@jupyterlab/builder": "^3.1.5", "global": "^4.3.0", "kepler.gl": "^2.5.2", "node-polyfill-webpack-plugin": "^1.1.2", @@ -76,6 +77,13 @@ "styled-components": "^4.1.3" }, "jupyterlab": { - "extension": "babel/labplugin" + "extension": "babel/labplugin", + "outputDir": "../keplergl-jupyter/labextension", + "sharedPackages": { + "@jupyter-widgets/base": { + "bundled": false, + "singleton": true + } + } } -} \ No newline at end of file +} diff --git a/bindings/kepler.gl-jupyter/pyproject.toml b/bindings/kepler.gl-jupyter/pyproject.toml new file mode 100644 index 0000000000..20789c6ba2 --- /dev/null +++ b/bindings/kepler.gl-jupyter/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["jupyter_packaging~=0.7.0", "jupyterlab>=3.0.0,==3.*", "setuptools>=40.8.0", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/bindings/kepler.gl-jupyter/setup.py b/bindings/kepler.gl-jupyter/setup.py index 7f5e720c67..db00af99f9 100644 --- a/bindings/kepler.gl-jupyter/setup.py +++ b/bindings/kepler.gl-jupyter/setup.py @@ -1,143 +1,65 @@ 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 +from distutils import log +from setuptools import setup, find_packages 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')) +from jupyter_packaging import ( + create_cmdclass, + install_npm, + ensure_targets, + combine_commands, + get_version, + skip_if_exists +) -npm_path = os.pathsep.join([ - os.path.join(node_root, 'node_modules', '.bin'), - os.environ.get('PATH', os.defpath), -]) +# Name of the project +name = 'keplergl' + +here = os.path.dirname(os.path.abspath(__file__)) +long_description = 'Keplergl Jupyter Extension' -from distutils import log -log.set_verbosity(log.DEBUG) log.info('setup.py entered') log.info('$PATH=%s' % os.environ['PATH']) -LONG_DESCRIPTION = 'A jupyter widget for kepler.gl, an advanced geospatial visualization tool, to render large-scale interactive maps.' - -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' +# Get version +version = get_version(os.path.join(name, '_version.py')) - user_options = [] +js_dir = os.path.join(here, 'js') - node_modules = os.path.join(node_root, 'node_modules') +# Representative files that should exist after a successful build +jstargets = [ + os.path.join('keplergl', 'static', 'index.js'), + os.path.join('keplergl-jupyter', 'labextension', 'package.json'), +] - targets = [ - os.path.join(here, 'keplergl', 'static', 'extension.js'), - os.path.join(here, 'keplergl', 'static', 'index.js') - ] +data_files_spec = [ + ('share/jupyter/nbextensions/keplergl-jupyter', + 'keplergl/static', '**'), + ('share/jupyter/labextensions/keplergl-jupyter', + 'keplergl-jupyter/labextension', "**"), + ('etc/jupyter/nbconfig/notebook.d', '.', 'keplergl-jupyter.json'), +] - def initialize_options(self): - pass +cmdclass = create_cmdclass('jsdeps', data_files_spec=data_files_spec) +js_command = combine_commands( + install_npm(js_dir, npm=["yarn"], build_cmd='build'), ensure_targets(jstargets), +) - 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) +is_repo = os.path.exists(os.path.join(here, '.git')) +if is_repo: + cmdclass['jsdeps'] = js_command +else: + cmdclass['jsdeps'] = skip_if_exists(jstargets, js_command) - # update package data in case this created new files - update_package_data(self.distribution) -version_ns = {} -with open(os.path.join(here, 'keplergl', '_version.py')) as f: - exec(f.read(), {}, version_ns) +LONG_DESCRIPTION = 'A jupyter widget for kepler.gl, an advanced geospatial visualization tool, to render large-scale interactive maps.' setup_args = { 'name': 'keplergl', - 'version': version_ns['__version__'], + 'version': version, 'description': 'This is a simple jupyter widget for kepler.gl, an advanced geospatial visualization tool, to render large-scale interactive maps.', 'long_description': LONG_DESCRIPTION, 'include_package_data': True, - 'data_files': [ - ('share/jupyter/nbextensions/keplergl-jupyter', [ - 'keplergl/static/extension.js', - 'keplergl/static/index.js', - 'keplergl/static/index.js.map', - ]), - ('etc/jupyter/nbconfig/notebook.d' ,['keplergl-jupyter.json']) - ], 'install_requires': [ 'ipywidgets>=7.0.0,<8', 'traittypes>=0.2.1', @@ -147,13 +69,7 @@ def run(self): ], '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, - }, - + 'cmdclass': cmdclass, 'author': 'Shan He', 'author_email': 'shan@uber.com', 'url': 'https://github.com/keplergl/kepler.gl/tree/master/bindings/kepler.gl-jupyter', @@ -172,11 +88,10 @@ def run(self): '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', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', ], }