diff --git a/.github/workflows/build-publish-pypi.yml b/.github/workflows/build-publish-pypi.yml new file mode 100644 index 0000000000..033144e3f8 --- /dev/null +++ b/.github/workflows/build-publish-pypi.yml @@ -0,0 +1,77 @@ +name: Build KeplerGL Python and NPM Packages + +on: push + +jobs: + + build_and_publish: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js 12.x + uses: actions/setup-node@v2 + with: + node-version: 12.x + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install twine virtualenv + + - name: Build KeplerGL + env: + MapboxAccessTokenJupyter: ${{ secrets.MAPBOXTOKEN }} + run: | + python -m virtualenv venv + source venv/bin/activate + pip install jupyter jupyterlab jupyter-packaging + cd bindings/kepler.gl-jupyter + python setup.py sdist + + - name: Test KeplerGL + run: | + source venv/bin/activate + pip install bindings/kepler.gl-jupyter/dist/*.tar.gz + if [ ! -f "venv/share/jupyter/nbextensions/keplergl-jupyter/index.js" ]; then + venv/bin/jupyter nbextension install --py --sys-prefix keplergl + venv/bin/jupyter nbextension enable --py --sys-prefix keplergl + fi + venv/bin/jupyter nbconvert --execute bindings/kepler.gl-jupyter/notebooks/DataFrame.ipynb --to python + python bindings/kepler.gl-jupyter/notebooks/DataFrame.py + + - name: Create artifact + uses: actions/upload-artifact@v2 + with: + name: keplergl-pypi + path: bindings/kepler.gl-jupyter/dist/ + + - name: Check Release Tag + id: check-tag + run: | + if [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+-jupyter$ ]]; then + echo ::set-output name=publish::true + fi + + - name: Publish KeplerGL to Pypi + if: steps.check-tag.outputs.publish == 'true' + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.pypi_token }} + run: | + python -m twine upload bindings/kepler.gl-jupyter/dist/*.tar.gz + + - name: Publish kepler-jupyter to NPM + if: steps.check-tag.outputs.publish == 'true' + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} + run: | + cd bindings/kepler.gl-jupyter/js + npm publish 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/README.md b/bindings/kepler.gl-jupyter/README.md index 59a2bf2e1e..cb582d04d1 100644 --- a/bindings/kepler.gl-jupyter/README.md +++ b/bindings/kepler.gl-jupyter/README.md @@ -14,40 +14,112 @@ Table of contacts ## Installation -### Prerequisites -- Python >= 2 -- ipywidgets >= 7.0.0 +[![Anaconda-Server Badge](https://anaconda.org/conda-forge/keplergl/badges/version.svg)](https://anaconda.org/conda-forge/keplergl) [![PyPI version](https://badge.fury.io/py/keplergl.svg)](https://badge.fury.io/py/keplergl) +### 1. For Jupyter Notebook -To install use pip: +#### Using conda: - $ pip install keplergl +```shell +conda install -c conda-forge keplergl +``` + +##### Prerequisites + - Python >= 3.7 + +#### Using pip: + +```shell +pip install keplergl +``` +##### Prerequisites + - For kelplergl <= 0.3.0 + - Python >= 2 + - ipywidgets >= 7.0.0 If you on Mac used `pip install` and running Notebook 5.3 and above, you don't need to run the following - $ jupyter nbextension install --py --sys-prefix keplergl # can be skipped for notebook 5.3 and above +```shell +jupyter nbextension install --py --sys-prefix keplergl # can be skipped for notebook 5.3 and above +jupyter nbextension enable --py --sys-prefix keplergl # can be skipped for notebook 5.3 and above +``` - $ jupyter nbextension enable --py --sys-prefix keplergl # can be skipped for notebook 5.3 and above +### 2. For Google Colab: -If you are in JupyterLab, you will also need to install the JupyterLab extension. This require [node](https://nodejs.org/en/download/package-manager/#macos) `> 8.15.0` +`keplergl` (>0.3.0) works with Google Colab. You can install it using pip. -If you use [Homebrew](https://brew.sh/) on Mac: +```python +# Install keplergl (>0.3.0) +!pip install keplergl +``` - $ brew install node@8 +### 3. For JupyterLab -Then install jupyter labextension. +#### JupyterLab 3 - $ jupyter labextension install @jupyter-widgets/jupyterlab-manager keplergl-jupyter +NOTE: `keplergl` <=0.3.0 doesn't work with JupyterLab 3. You need to make sure the python package `keplergl` > 0.3.0 is installed. -**Prerequisites for JupyterLab:** -- Node > 8.15.0 -- Python 3 -- JupyterLab >=1.0.0 || >=2.0.0 +Installation using pip: +```shell +pip install keplergl +``` +Installation using conda: +```shell +conda install keplergl +``` + +There is no need to use `jupyter labextension install` for `keplergl` > 0.3.0 with JupyterLab3. + +#### JupyterLab 1 + +For JupyterLab1, you need to install `keplergl-jupyter` labextension from NPM registery. There is no need to install `keplergl` python package. + +First, install `jupyterlab-manager` for JupyterLab1: +```shell +jupyter labextension install @jupyter-widgets/jupyterlab-manager@1.1 +``` + +Then, install `keplergl-jupyter` labextension from NPM registry: +```shell +jupyter labextension install keplergl-jupyter +``` +##### Prerequisites: + - Node >= 12 + - Python 3 + +#### JupyterLab 2 + +For JupyterLab2, you need to install `keplergl-jupyter` labextension from NPM registery. There is no need to install `keplergl` python package. + +First, install `jupyterlab-manager` for JupyterLab2: +```shell +jupyter labextension install @jupyter-widgets/jupyterlab-manager@2 +``` + +To install `keplergl-jupyter` from NPM registry, JupyterLab2 has following requirements of dependencies: +``` +JupyterLab Extension Package +>=16.9.0 <16.10.0 >=17.0.0 <18.0.0 react +>=16.9.0 <16.10.0 >=17.0.0 <18.0.0 react-dom +``` + +However, `keplergl-jupyter`<=0.3.0 depends on `react` >= 17.0.2. Therefore, the latest `keplergl-jupyter` can’t be installed with JupyterLab2: if you use `jupyter labextension install keplergl-jupyter`, the version 0.2.2 as a fallback will be installed. Unfortunately, version 0.2.2 does NOT work with JupyterLab2. + +A workaround is to modify the file `lib/python3.x/site-packages/jupyterlab/staging/package.json` and remove “react” and “react-dom” from “singletonPackages” object. Then, install keplergl-jupyter using this command: +``` +jupyter labextension install keplergl-jupyter +``` + +##### Prerequisites: + - Node >= 12 + - Python 3 ## Quick Start +### For Jupyter Notebook and JupyterLab: + ```python # Load kepler.gl with an empty map from keplergl import KeplerGl @@ -72,6 +144,33 @@ map_1.config map_1.save_to_html(file_name='keplergl_map.html') ``` +### For Google Colab: + +Keplergl (>0.3.0) works with Google Colab. You can install it using pip. + +```python +# Install keplergl (>0.3.0) +!pip install keplergl + +# Load Kepler.gl with an empty map +from keplergl import KeplerGl +map_1 = KeplerGl() + +# Display map +map_1.show() +``` + +The function `show()` is newly introduced for displaying map in Google Colab. The function is defined as: +```python +def show(self, data=None, config=None, read_only=False, center_map=False) +``` +with input parameters: +- data: a data dictionary {"name": data}, if not provided, will use current map data +- config: map config dictionary, if not provided, will use current map config +- read_only: if read_only is True, hide side panel to disable map customization +- center_map: if center_map is True, the bound of the map will be updated acoording to the current map data + +Please note that the map is not interactive due to the limitation of Google Colab. For example, when applying config to the map in Colab, the map won't be updated and one needs to call `show()` again to render a new map in a new cell. ## Demo Notebooks - [Load kepler.gl](https://github.com/keplergl/kepler.gl/blob/master/bindings/kepler.gl-jupyter/notebooks/Load%20kepler.gl.ipynb): Load kepler.gl widget, add data and config @@ -107,34 +206,48 @@ https://docs.kepler.gl/docs/keplergl-jupyter#1-load-keplergl-map You will need to install node, yarn and Jupyter Notebook. #### 1. Node and Yarn -Install [node](https://nodejs.org/en/download/package-manager/#macos) `> 10.15.0`, and [yarn](https://yarnpkg.com/en/docs/install#mac-stable). Use [nvm](https://github.com/creationix/nvm) for better node version management e.g. `nvm install 10`. +Install [node](https://nodejs.org/en/download/package-manager/#macos) `> 12`, and [yarn](https://yarnpkg.com/en/docs/install#mac-stable). Use [nvm](https://github.com/creationix/nvm) for better node version management e.g. `nvm install 12`. -#### 2. Install Jupyter with pip +#### 2. Install Jupyter -Python 3 -```bash -$ python3 -m pip install --upgrade pip -$ python3 -m pip install jupyter +- Using conda +```shell +conda install jupyter ``` -Python 2 -```bash -$ python -m pip install --upgrade pip -$ python -m pip install jupyter +- Using pip + +```shell +pip install jupyter +``` + +#### 3. Install GeoPandas + +- Using conda +```shell +conda install geopandas +``` + +- Using pip + +```shell +pip install geopandas ``` ### Download and run keplergl in your local Jupyter Notebook #### Clone Repo - $ git clone https://github.com/keplergl/kepler.gl.git +```shell +git clone https://github.com/keplergl/kepler.gl.git +``` ### Setup JS #### 1. Install Js module ```sh - $ cd bindings/kepler.gl-jupyter - $ cd js - $ yarn +cd bindings/kepler.gl-jupyter +cd js +yarn ``` #### 2. Load mapbox token @@ -145,7 +258,10 @@ export MapboxAccessTokenJupyter= ``` #### 3. Build js module, start a local server to watch for changes - $ npm start + +```shell +npm start +``` You need to run step 2 and 3 to restart the js program. And step 1-3 if any js dependency has changed (Usually after pulling new changes from master). @@ -155,27 +271,69 @@ You need to run step 2 and 3 to restart the js program. And step 1-3 if any js d This command must be run **AFTER** the `js` setup, and folder `static/` was created. It only needs to be run once. ```sh - # dev install from folder containing setup.py - $ pip install -e . +# dev install from folder containing setup.py +pip install -e . + +# only needed in dev mode, not in normal mode. +jupyter nbextension install --py --symlink --sys-prefix keplergl + +# only needed in dev mode, not in normal mode. +jupyter nbextension enable --py --sys-prefix keplergl +``` + +NOTE: The above command `jupyter nbextension install -py --symlink --sys-prefix keplergl` is trying to create a symoblic link of the folder `bindings/kepler.gl-jupyter/keplergl/static` under the jupyter's folder `nbextensions`. Please check if there is already a folder "nbextensions/kepler-jupyter" existed, and you might need to remove it first. - # only needed in dev mode, not in normal mode. - $ jupyter nbextension install --py --symlink --sys-prefix keplergl +To find the location of `nbextensions` folder, you can use the following command: +```shell +$ where jupyter +/Users/test/opt/anaconda3/envs/test37/bin/jupyter - # only needed in dev mode, not in normal mode. - $ jupyter nbextension enable --py --sys-prefix keplergl +# the nbextensions should be at: /Users/test/opt/anaconda3/envs/test37/share/jupyter/nbextensions ``` + #### 2. Start jupyter notebook - $ cd notebooks - $ jupyter notebook +```shell +cd notebooks +jupyter notebook +``` -### Have fun! +#### Have fun! You can now start editing the .js and .py files to see changes reflected in your local notebook. After changing files in the js folder, the local start script will recompile the js files and put them in to `keplergl/static` folder. You need to reload the jupyter notebook page to reload the files. +#### 3. Development for JupyterLab + +To test the development work in previous 2 steps for JupyterLab. You can build the `keplergl labextension` under the `js` directory: + +```shell +jupyter labextension build . +``` + +The output of the jupyter labextension is defined in the file `js/package.json`: +```javascript +... +"jupyterlab": { + "extension": "babel/labplugin", + "outputDir": "../keplergl-jupyter/labextension", + "sharedPackages": { + "@jupyter-widgets/base": { + "bundled": false, + "singleton": true + } + } +} +``` + +Then, you can either install this labextension to test it: +```shell +jupyter labextension install . +``` +or, you can manually create a symbolic link for the folder `bindings/kepler.gl-jupyter/kepler-jupyter/labextension` under the jupyter's folder `labextensions`, e.g. `/Users/test/opt/anaconda3/envs/test37/share/jupyter/labextensions`. You will need to reload the jupyter lab page. + [jupyter_widget]: https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/documentation/jupyter_widget.png [empty_map]: https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/documentation/jupyter_empty_map.png [geodataframe_map]: https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/documentation/jupyter_geodataframe.png diff --git a/bindings/kepler.gl-jupyter/RELEASE.md b/bindings/kepler.gl-jupyter/RELEASE.md index f2b0a5106d..bc3afeaa63 100644 --- a/bindings/kepler.gl-jupyter/RELEASE.md +++ b/bindings/kepler.gl-jupyter/RELEASE.md @@ -2,38 +2,49 @@ ## Release a new version -To release a new version. You need publish both the js module in NPM and the python module on PyPI. +When release a new version, the `keplergl-jupyter` js module will be published on NPM and the `keplergl` python module will be published on PyPI. -__Version number of the js module **`kelergl-jupyter`** and the python module **`keplergl`** should match__ +NOTE: __Version number of the js module **`kelergl-jupyter`** and the python module **`keplergl`** should match__ -### To release a new version of keplergl-jupyter on NPM: +### Step1: -- Go to the js folder -``` -npm version patch | minor | major -git commit -am "keplergl-jupyter@" -npm login -npm publish -``` - -### To release a new version of keplergl on PyPI: - -- Update `version_info` in keplergl/_version.py. in bindings/kepler.gl-jupyter folder. Update `EXTENSION_SPEC_VERSION` to match the js module version +Update `version_info` in keplergl/_version.py. in bindings/kepler.gl-jupyter folder. Update `EXTENSION_SPEC_VERSION` to match the js module version ``` git add keplergl/_version.py git commit -am "keplergl==" ``` -- Remove dist, build and upload to PyPI + +### Step2: + +Create a tag: `-jupyter` e.g. v0.3.2-jupyter + ``` -rm -r dist -python setup.py sdist -twine upload dist/* +git tag -a -jupyter -m "-jupyter" +git push origin master && git push origin -jupyter ``` -### add tags +The new tag will trigger the Github Action `build-publish-pypi.yml`: __"Build KeplerGL Python and NPM packages"__. The packages will be built and tested, then published to NPM and PyPI using the secret tokens. + +### Step3: + +For conda-forge release, please use the repo: https://github.com/lixun910/staged-recipes/tree/keplergl-feedstock + +Edit `meta.yaml` under directory `staged-recipes/recipes/kepler/gl`: + +* Update the version number + +```python +{% set version = "0.3.0" %} ``` -git tag -a -jupyter -m "-jupyter -git push origin master && git push origin -jupyter + +* Update the sha256 value of the latest tarball in PyPi that is published in Step2. + +```python +source: + url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz + sha256: cb21047b2104413af1c00ef1ac75794a19e0b578e51c69c86713911d97370167 ``` + +* Create a pull request and wait for manual checking from conda-forge team. 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/js/webpack/build-html.js b/bindings/kepler.gl-jupyter/js/webpack/build-html.js index 34e9f0769d..3ed55efab1 100644 --- a/bindings/kepler.gl-jupyter/js/webpack/build-html.js +++ b/bindings/kepler.gl-jupyter/js/webpack/build-html.js @@ -90,7 +90,7 @@ module.exports = (rules, plugins) => ({ filename: 'keplergl.html', inject: true, links: [ - 'http://d1a3f4spazzrp4.cloudfront.net/kepler.gl/uber-fonts/4.0.0/superfine.css', + 'https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/uber-fonts/4.0.0/superfine.css', 'https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.css' ], scripts: [ diff --git a/bindings/kepler.gl-jupyter/keplergl/keplergl.py b/bindings/kepler.gl-jupyter/keplergl/keplergl.py index fa0b299b19..be2f8a26db 100644 --- a/bindings/kepler.gl-jupyter/keplergl/keplergl.py +++ b/bindings/kepler.gl-jupyter/keplergl/keplergl.py @@ -6,6 +6,7 @@ import shapely.wkt import json from ._version import EXTENSION_SPEC_VERSION +import sys documentation = 'https://docs.kepler.gl/docs/keplergl-jupyter' def _df_to_dict(df): @@ -142,6 +143,39 @@ def add_data(self, data, name="unnamed"): self.data = copy + def show(self, data=None, config=None, read_only=False, center_map=False): + ''' Display current map in Google Colab + + Inputs: + - data: a data dictionary {"name": data}, if not provided, will use current map data + - config: map config dictionary, if not provided, will use current map config + - read_only: if read_only is True, hide side panel to disable map customization + - center_map: if center_map is True, the bound of the map will be updated acoording to the current map data + + Example of use: + # this will display map in Google Colab + from keplergl import KeplerGL + map1 = KeplerGL() + map1.show() + + ''' + keplergl_html = resource_string(__name__, 'static/keplergl.html').decode('utf-8') + # find open of body + k = keplergl_html.find("") + + data_to_add = data_to_json(self.data, None) if data == None else data_to_json(data, None) + config_to_add = self.config if config == None else config + + keplergl_data = json.dumps({"config": config_to_add, "data": data_to_add, "options": {"readOnly": read_only, "centerMap": center_map}}) + + cmd = """window.__keplerglDataConfig = {};""".format(keplergl_data) + frame_txt = keplergl_html[:k] + "" + keplergl_html[k+6:] + + if "google.colab" in sys.modules: + from IPython.display import HTML, Javascript + display(HTML(frame_txt)) + display(Javascript(f"google.colab.output.setIframeHeight('{self.height}');")) + def _repr_html_(self, data=None, config=None, read_only=False, center_map=False): ''' Return current map in an html encoded string @@ -149,6 +183,7 @@ def _repr_html_(self, data=None, config=None, read_only=False, center_map=False) - data: a data dictionary {"name": data}, if not provided, will use current map data - config: map config dictionary, if not provided, will use current map config - read_only: if read_only is True, hide side panel to disable map customization + - center_map: if center_map is True, the bound of the map will be updated acoording to the current map data Returns: - a html encoded string 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', ], }