Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update keplergl-jupyter bindings #1572

Merged
merged 6 commits into from
Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/build-publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Build KeplerGL Python Package

on: push
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be on:push or on:release?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be “on:push”, which means this action can be used to build, check and test keplergl python package on push with changes. For release and publish, there is a step: “-name: Check Release Tag”.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


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: Publish Pypi
lixun910 marked this conversation as resolved.
Show resolved Hide resolved
if: github.event_name == 'release' && github.event.action == 'created'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.npm_token }}
run: |
python -m twine upload bindings/kepler.gl-jupyter/dist/*.tar.gz

1 change: 1 addition & 0 deletions bindings/kepler.gl-jupyter/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
recursive-include keplergl/static *.*
recursive-include keplergl-jupyter/labextension *.*
include keplergl-jupyter.json
16 changes: 12 additions & 4 deletions bindings/kepler.gl-jupyter/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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
}
}
}
}
}
2 changes: 1 addition & 1 deletion bindings/kepler.gl-jupyter/js/webpack/build-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
19 changes: 19 additions & 0 deletions bindings/kepler.gl-jupyter/keplergl/keplergl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -142,6 +143,24 @@ def add_data(self, data, name="unnamed"):

self.data = copy

def show(self, data=None, config=None, read_only=False, center_map=False):
lixun910 marked this conversation as resolved.
Show resolved Hide resolved
keplergl_html = resource_string(__name__, 'static/keplergl.html').decode('utf-8')
# find open of body
k = keplergl_html.find("<body>")

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] + "<body><script>" + cmd + "</script>" + 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

Expand Down
3 changes: 3 additions & 0 deletions bindings/kepler.gl-jupyter/pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
177 changes: 46 additions & 131 deletions bindings/kepler.gl-jupyter/setup.py
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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',
Expand All @@ -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',
],
}

Expand Down