From f7e11092eb3432ea606a91fce3fd0f9d43a6b36b Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Fri, 8 Dec 2023 10:31:46 -0800 Subject: [PATCH 1/7] feat: Add plotly-express JsPlugin implementation and registration --- plugins/plotly-express/setup.cfg | 4 +-- plugins/plotly-express/setup.py | 5 ++- .../src/deephaven/plot/express/__init__.py | 14 +++++--- .../src/deephaven/plot/express/js/__init__.py | 33 +++++++++++++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 plugins/plotly-express/src/deephaven/plot/express/js/__init__.py diff --git a/plugins/plotly-express/setup.cfg b/plugins/plotly-express/setup.cfg index c13026191..917b8a526 100644 --- a/plugins/plotly-express/setup.cfg +++ b/plugins/plotly-express/setup.cfg @@ -3,7 +3,7 @@ name = deephaven-plugin-plotly-express description = Deephaven Chart Plugin long_description = file: README.md long_description_content_type = text/markdown -version = attr:deephaven.plot.express.__version__ +version = 0.2.0.dev1 url = https://github.com/deephaven/deephaven-plugins project_urls = Source Code = https://github.com/deephaven/deephaven-plugins @@ -34,4 +34,4 @@ where=src [options.entry_points] deephaven.plugin = - registration_cls = deephaven.plot.express:ChartRegistration \ No newline at end of file + registration_cls = deephaven.plot.express:ExpressRegistration diff --git a/plugins/plotly-express/setup.py b/plugins/plotly-express/setup.py index 3de56d39d..e557b7370 100644 --- a/plugins/plotly-express/setup.py +++ b/plugins/plotly-express/setup.py @@ -2,7 +2,6 @@ from setuptools import setup import os import subprocess -import json # npm pack in js directory @@ -18,11 +17,11 @@ os.makedirs(dest_dir, exist_ok=True) # pack and unpack into the js plotly-express directory - subprocess.run(["npm", "pack", "--pack-destination", project], cwd=js_dir) + subprocess.run(["npm", "pack", "--pack-destination", project], cwd=js_dir, check=True) # it is assumed that there is only one tarball in the directory files = os.listdir(dest_dir) for file in files: - subprocess.run(["tar", "-xzf", file], cwd=dest_dir) + subprocess.run(["tar", "-xzf", file], cwd=dest_dir, check=True) os.remove(os.path.join(dest_dir, file)) # move the contents of the package directory to the plotly-express directory diff --git a/plugins/plotly-express/src/deephaven/plot/express/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/__init__.py index 05288baf9..5e4d1ba09 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/__init__.py @@ -1,12 +1,14 @@ from __future__ import annotations import json +import importlib.metadata from deephaven.plugin import Registration, Callback from deephaven.plugin.object_type import BidirectionalObjectType, MessageStream from .communication.DeephavenFigureConnection import DeephavenFigureConnection from .deephaven_figure import DeephavenFigure +from .js import ExpressJsPlugin from .plots import ( area, @@ -44,7 +46,10 @@ from .data import data_generators -__version__ = "0.2.0dev1" +# Note: this is the _distribution_ name, not the _package_ name. Until 3.10, there is not an easy way to get the +# distribution name from the package name. +# https://docs.python.org/3/library/importlib.metadata.html#package-distributions +__version__ = importlib.metadata.version("deephaven-plugin-plotly-express") NAME = "deephaven.plot.express.DeephavenFigure" @@ -103,16 +108,16 @@ def create_client_connection( return figure_connection -class ChartRegistration(Registration): +class ExpressRegistration(Registration): """ - Register the DeephavenFigureType + Register the DeephavenFigureType and ExpressJsPlugin """ @classmethod def register_into(cls, callback: Callback) -> None: """ - Register the DeephavenFigureType + Register the DeephavenFigureType and ExpressJsPlugin Args: callback: Registration.Callback: @@ -120,3 +125,4 @@ def register_into(cls, callback: Callback) -> None: """ callback.register(DeephavenFigureType) + callback.register(ExpressJsPlugin) diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py new file mode 100644 index 000000000..4feec4ea6 --- /dev/null +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -0,0 +1,33 @@ +import typing +import pathlib + +import importlib.metadata +import importlib.resources + +from deephaven.plugin.js import JsPlugin + + +class ExpressJsPlugin(JsPlugin): + def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: + # todo: better location + # todo: need to make sure this works w/ 3.8+ + # todo: should rename this method in JsPlugin? + return importlib.resources.as_file( + importlib.resources.files("js").joinpath("plotly-express") + ) + + @property + def name(self) -> str: + # note: should this be NPM name? + return "@deephaven/js-plugin-plotly-express" + + @property + def version(self) -> str: + # note: this vs NPM version? + # should it be combo of both? + return importlib.metadata.version("deephaven-plugin-plotly-express") + + @property + def main(self) -> str: + # todo: source from package.json? + return "dist/bundle/index.js" From 79143d3e458564d556dd17bff5fb9f03705dec1e Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Fri, 8 Dec 2023 11:49:45 -0800 Subject: [PATCH 2/7] Update to source from NPM package --- plugins/plotly-express/setup.py | 4 +- .../src/deephaven/plot/express/__init__.py | 4 +- .../src/deephaven/plot/express/js/__init__.py | 65 +++++++++++++++---- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/plugins/plotly-express/setup.py b/plugins/plotly-express/setup.py index e557b7370..d5125a974 100644 --- a/plugins/plotly-express/setup.py +++ b/plugins/plotly-express/setup.py @@ -17,7 +17,9 @@ os.makedirs(dest_dir, exist_ok=True) # pack and unpack into the js plotly-express directory - subprocess.run(["npm", "pack", "--pack-destination", project], cwd=js_dir, check=True) + subprocess.run( + ["npm", "pack", "--pack-destination", project], cwd=js_dir, check=True + ) # it is assumed that there is only one tarball in the directory files = os.listdir(dest_dir) for file in files: diff --git a/plugins/plotly-express/src/deephaven/plot/express/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/__init__.py index 5e4d1ba09..eae506139 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/__init__.py @@ -8,7 +8,7 @@ from .communication.DeephavenFigureConnection import DeephavenFigureConnection from .deephaven_figure import DeephavenFigure -from .js import ExpressJsPlugin +from .js import create_js_plugin from .plots import ( area, @@ -125,4 +125,4 @@ def register_into(cls, callback: Callback) -> None: """ callback.register(DeephavenFigureType) - callback.register(ExpressJsPlugin) + callback.register(create_js_plugin()) diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py index 4feec4ea6..5d9d4dd5a 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -3,31 +3,68 @@ import importlib.metadata import importlib.resources +import json +from typing import Callable from deephaven.plugin.js import JsPlugin class ExpressJsPlugin(JsPlugin): - def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: - # todo: better location - # todo: need to make sure this works w/ 3.8+ - # todo: should rename this method in JsPlugin? - return importlib.resources.as_file( - importlib.resources.files("js").joinpath("plotly-express") - ) + def __init__( + self, + name: str, + version: str, + main: str, + root_provider: Callable[[], typing.Generator[pathlib.Path, None, None]], + ) -> None: + self._name = name + self._version = version + self._main = main + self._root_provider = root_provider @property def name(self) -> str: - # note: should this be NPM name? - return "@deephaven/js-plugin-plotly-express" + return self._name @property def version(self) -> str: - # note: this vs NPM version? - # should it be combo of both? - return importlib.metadata.version("deephaven-plugin-plotly-express") + return self._version @property def main(self) -> str: - # todo: source from package.json? - return "dist/bundle/index.js" + return self._main + + def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: + # todo: should rename this method in JsPlugin + return self._root_provider() + + +def create_from_npm( + root_provider: Callable[[], typing.Generator[pathlib.Path, None, None]] +) -> JsPlugin: + with root_provider() as root, (root / "package.json").open("rb") as f: + package_json = json.load(f) + return ExpressJsPlugin( + package_json["name"], + package_json["version"], + package_json["main"], + root_provider, + ) + + +def production_root() -> typing.Generator[pathlib.Path, None, None]: + # todo: better location + # todo: need to make sure this works w/ 3.8+ + return importlib.resources.as_file( + importlib.resources.files("js").joinpath("plotly-express") + ) + + +def development_root() -> typing.Generator[pathlib.Path, None, None]: + raise NotImplementedError("TODO") + + +def create_js_plugin() -> JsPlugin: + # todo: some mode to switch into development mode / editable mode? + # or, some may to skip creating JsPlugin, and have developer add deephaven configuration property + return create_from_npm(production_root) From 786b37887c447a657bcc599d6ad64b14e9e45f0c Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Fri, 8 Dec 2023 12:22:08 -0800 Subject: [PATCH 3/7] Add python 3.8 support --- .../src/deephaven/plot/express/js/__init__.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py index 5d9d4dd5a..e8c194f8a 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -4,6 +4,7 @@ import importlib.metadata import importlib.resources import json +import sys from typing import Callable from deephaven.plugin.js import JsPlugin @@ -39,7 +40,7 @@ def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: return self._root_provider() -def create_from_npm( +def _create_from_npm_package_json( root_provider: Callable[[], typing.Generator[pathlib.Path, None, None]] ) -> JsPlugin: with root_provider() as root, (root / "package.json").open("rb") as f: @@ -52,19 +53,22 @@ def create_from_npm( ) -def production_root() -> typing.Generator[pathlib.Path, None, None]: - # todo: better location - # todo: need to make sure this works w/ 3.8+ - return importlib.resources.as_file( - importlib.resources.files("js").joinpath("plotly-express") - ) +def _production_root() -> typing.Generator[pathlib.Path, None, None]: + # TODO: Js content should be in same package directory + # https://github.com/deephaven/deephaven-plugins/issues/139 + if sys.version_info < (3, 9): + return importlib.resources.path("js", "plotly-express") + else: + return importlib.resources.as_file( + importlib.resources.files("js").joinpath("plotly-express") + ) -def development_root() -> typing.Generator[pathlib.Path, None, None]: +def _development_root() -> typing.Generator[pathlib.Path, None, None]: raise NotImplementedError("TODO") def create_js_plugin() -> JsPlugin: # todo: some mode to switch into development mode / editable mode? # or, some may to skip creating JsPlugin, and have developer add deephaven configuration property - return create_from_npm(production_root) + return _create_from_npm_package_json(_production_root) From 2609d4438ce780560ac02b90c17496a8ef8d2996 Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Fri, 8 Dec 2023 12:36:01 -0800 Subject: [PATCH 4/7] Update comments --- .../plotly-express/src/deephaven/plot/express/__init__.py | 5 ----- .../src/deephaven/plot/express/js/__init__.py | 8 +++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/plotly-express/src/deephaven/plot/express/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/__init__.py index eae506139..f42f5dc92 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/__init__.py @@ -1,7 +1,6 @@ from __future__ import annotations import json -import importlib.metadata from deephaven.plugin import Registration, Callback from deephaven.plugin.object_type import BidirectionalObjectType, MessageStream @@ -46,10 +45,6 @@ from .data import data_generators -# Note: this is the _distribution_ name, not the _package_ name. Until 3.10, there is not an easy way to get the -# distribution name from the package name. -# https://docs.python.org/3/library/importlib.metadata.html#package-distributions -__version__ = importlib.metadata.version("deephaven-plugin-plotly-express") NAME = "deephaven.plot.express.DeephavenFigure" diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py index e8c194f8a..2e1fb16e0 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -36,7 +36,8 @@ def main(self) -> str: return self._main def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: - # todo: should rename this method in JsPlugin + # TODO: Finalize JsPlugin + # https://github.com/deephaven/deephaven-plugin/issues/15 return self._root_provider() @@ -69,6 +70,7 @@ def _development_root() -> typing.Generator[pathlib.Path, None, None]: def create_js_plugin() -> JsPlugin: - # todo: some mode to switch into development mode / editable mode? - # or, some may to skip creating JsPlugin, and have developer add deephaven configuration property + # TODO: Include developer instructions for installing in editable mode + # https://github.com/deephaven/deephaven-plugins/issues/93 + # TBD what editable mode looks like for JsPlugin return _create_from_npm_package_json(_production_root) From c400a9632f67fc07c27e80806feafd8d368a20f8 Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Mon, 11 Dec 2023 11:56:42 -0800 Subject: [PATCH 5/7] Update typing to ContextManager --- .../src/deephaven/plot/express/js/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py index 2e1fb16e0..8d6ab336d 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -5,7 +5,7 @@ import importlib.resources import json import sys -from typing import Callable +from typing import Callable, ContextManager from deephaven.plugin.js import JsPlugin @@ -16,7 +16,7 @@ def __init__( name: str, version: str, main: str, - root_provider: Callable[[], typing.Generator[pathlib.Path, None, None]], + root_provider: Callable[[], ContextManager[pathlib.Path]], ) -> None: self._name = name self._version = version @@ -35,14 +35,14 @@ def version(self) -> str: def main(self) -> str: return self._main - def distribution_path(self) -> typing.Generator[pathlib.Path, None, None]: + def distribution_path(self) -> ContextManager[pathlib.Path]: # TODO: Finalize JsPlugin # https://github.com/deephaven/deephaven-plugin/issues/15 return self._root_provider() def _create_from_npm_package_json( - root_provider: Callable[[], typing.Generator[pathlib.Path, None, None]] + root_provider: Callable[[], ContextManager[pathlib.Path]] ) -> JsPlugin: with root_provider() as root, (root / "package.json").open("rb") as f: package_json = json.load(f) @@ -54,7 +54,7 @@ def _create_from_npm_package_json( ) -def _production_root() -> typing.Generator[pathlib.Path, None, None]: +def _production_root() -> ContextManager[pathlib.Path]: # TODO: Js content should be in same package directory # https://github.com/deephaven/deephaven-plugins/issues/139 if sys.version_info < (3, 9): @@ -65,7 +65,7 @@ def _production_root() -> typing.Generator[pathlib.Path, None, None]: ) -def _development_root() -> typing.Generator[pathlib.Path, None, None]: +def _development_root() -> ContextManager[pathlib.Path]: raise NotImplementedError("TODO") From 2f58734b12834d407e2b0bca9decada99184e13f Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Wed, 13 Dec 2023 11:27:23 -0800 Subject: [PATCH 6/7] Update for deephaven-plugin==0.6.0 --- plugins/plotly-express/setup.cfg | 2 +- .../src/deephaven/plot/express/js/__init__.py | 35 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/plugins/plotly-express/setup.cfg b/plugins/plotly-express/setup.cfg index 917b8a526..4b10a9fce 100644 --- a/plugins/plotly-express/setup.cfg +++ b/plugins/plotly-express/setup.cfg @@ -25,7 +25,7 @@ package_dir= =src packages=find_namespace: install_requires = - deephaven-plugin>=0.5.0 + deephaven-plugin>=0.6.0 plotly include_package_data = True diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py index 8d6ab336d..84d6c05fb 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py @@ -1,9 +1,6 @@ -import typing -import pathlib - -import importlib.metadata import importlib.resources import json +import pathlib import sys from typing import Callable, ContextManager @@ -16,12 +13,12 @@ def __init__( name: str, version: str, main: str, - root_provider: Callable[[], ContextManager[pathlib.Path]], + path: pathlib.Path, ) -> None: self._name = name self._version = version self._main = main - self._root_provider = root_provider + self._path = path @property def name(self) -> str: @@ -35,26 +32,30 @@ def version(self) -> str: def main(self) -> str: return self._main - def distribution_path(self) -> ContextManager[pathlib.Path]: - # TODO: Finalize JsPlugin - # https://github.com/deephaven/deephaven-plugin/issues/15 - return self._root_provider() + def path(self) -> pathlib.Path: + return self._path def _create_from_npm_package_json( - root_provider: Callable[[], ContextManager[pathlib.Path]] + path_provider: Callable[[], ContextManager[pathlib.Path]] ) -> JsPlugin: - with root_provider() as root, (root / "package.json").open("rb") as f: + with path_provider() as tmp_js_path: + js_path = tmp_js_path + if not js_path.exists(): + raise Exception( + f"Package is not installed in a normal python filesystem, '{js_path}' does not exist" + ) + with (js_path / "package.json").open("rb") as f: package_json = json.load(f) return ExpressJsPlugin( package_json["name"], package_json["version"], package_json["main"], - root_provider, + js_path, ) -def _production_root() -> ContextManager[pathlib.Path]: +def _resource_js_path() -> ContextManager[pathlib.Path]: # TODO: Js content should be in same package directory # https://github.com/deephaven/deephaven-plugins/issues/139 if sys.version_info < (3, 9): @@ -65,12 +66,8 @@ def _production_root() -> ContextManager[pathlib.Path]: ) -def _development_root() -> ContextManager[pathlib.Path]: - raise NotImplementedError("TODO") - - def create_js_plugin() -> JsPlugin: # TODO: Include developer instructions for installing in editable mode # https://github.com/deephaven/deephaven-plugins/issues/93 # TBD what editable mode looks like for JsPlugin - return _create_from_npm_package_json(_production_root) + return _create_from_npm_package_json(_resource_js_path) From ade4c8a2ce051099e48f51d697ecfa6d990fae31 Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Thu, 14 Dec 2023 13:41:49 -0800 Subject: [PATCH 7/7] Refactor to move registration and js to internal packages --- plugins/plotly-express/setup.cfg | 2 +- .../src/deephaven/plot/express/__init__.py | 22 ----------------- .../plot/express/{js/__init__.py => _js.py} | 0 .../src/deephaven/plot/express/_register.py | 24 +++++++++++++++++++ 4 files changed, 25 insertions(+), 23 deletions(-) rename plugins/plotly-express/src/deephaven/plot/express/{js/__init__.py => _js.py} (100%) create mode 100644 plugins/plotly-express/src/deephaven/plot/express/_register.py diff --git a/plugins/plotly-express/setup.cfg b/plugins/plotly-express/setup.cfg index ccf9ffd92..237bb3d1f 100644 --- a/plugins/plotly-express/setup.cfg +++ b/plugins/plotly-express/setup.cfg @@ -34,4 +34,4 @@ where=src [options.entry_points] deephaven.plugin = - registration_cls = deephaven.plot.express:ExpressRegistration + registration_cls = deephaven.plot.express._register:ExpressRegistration diff --git a/plugins/plotly-express/src/deephaven/plot/express/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/__init__.py index f42f5dc92..9764d2f95 100644 --- a/plugins/plotly-express/src/deephaven/plot/express/__init__.py +++ b/plugins/plotly-express/src/deephaven/plot/express/__init__.py @@ -2,12 +2,10 @@ import json -from deephaven.plugin import Registration, Callback from deephaven.plugin.object_type import BidirectionalObjectType, MessageStream from .communication.DeephavenFigureConnection import DeephavenFigureConnection from .deephaven_figure import DeephavenFigure -from .js import create_js_plugin from .plots import ( area, @@ -101,23 +99,3 @@ def create_client_connection( payload, references = figure_connection.on_data(initial_message, []) connection.on_data(payload, references) return figure_connection - - -class ExpressRegistration(Registration): - """ - Register the DeephavenFigureType and ExpressJsPlugin - - """ - - @classmethod - def register_into(cls, callback: Callback) -> None: - """ - Register the DeephavenFigureType and ExpressJsPlugin - - Args: - callback: Registration.Callback: - A function to call after registration - - """ - callback.register(DeephavenFigureType) - callback.register(create_js_plugin()) diff --git a/plugins/plotly-express/src/deephaven/plot/express/js/__init__.py b/plugins/plotly-express/src/deephaven/plot/express/_js.py similarity index 100% rename from plugins/plotly-express/src/deephaven/plot/express/js/__init__.py rename to plugins/plotly-express/src/deephaven/plot/express/_js.py diff --git a/plugins/plotly-express/src/deephaven/plot/express/_register.py b/plugins/plotly-express/src/deephaven/plot/express/_register.py new file mode 100644 index 000000000..378b35a8a --- /dev/null +++ b/plugins/plotly-express/src/deephaven/plot/express/_register.py @@ -0,0 +1,24 @@ +from . import DeephavenFigureType +from ._js import create_js_plugin + +from deephaven.plugin import Registration, Callback + + +class ExpressRegistration(Registration): + """ + Register the DeephavenFigureType and a JsPlugin + + """ + + @classmethod + def register_into(cls, callback: Callback) -> None: + """ + Register the DeephavenFigureType and a JsPlugin + + Args: + callback: Registration.Callback: + A function to call after registration + + """ + callback.register(DeephavenFigureType) + callback.register(create_js_plugin())