perspective-python 3.0.0rc1__cp39-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- perspective/__init__.py +78 -0
- perspective/extension/finos-perspective-nbextension.json +5 -0
- perspective/handlers/__init__.py +26 -0
- perspective/handlers/aiohttp.py +54 -0
- perspective/handlers/starlette.py +51 -0
- perspective/handlers/tornado.py +61 -0
- perspective/perspective.pyd +0 -0
- perspective/templates/exported_widget.html.jinja +35 -0
- perspective/tests/__init__.py +11 -0
- perspective/tests/conftest.py +268 -0
- perspective/tests/core/__init__.py +11 -0
- perspective/tests/core/test_async.py +436 -0
- perspective/tests/core/test_threadpool.py +48 -0
- perspective/tests/server/__init__.py +11 -0
- perspective/tests/server/test_server.py +1062 -0
- perspective/tests/server/test_session.py +55 -0
- perspective/tests/single_threaded/test_single_threaded.py +61 -0
- perspective/tests/table/__init__.py +11 -0
- perspective/tests/table/arrow/date32.arrow +0 -0
- perspective/tests/table/arrow/date64.arrow +0 -0
- perspective/tests/table/arrow/dict.arrow +0 -0
- perspective/tests/table/arrow/dict_update.arrow +0 -0
- perspective/tests/table/arrow/int_float_str.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_file.arrow +0 -0
- perspective/tests/table/arrow/int_float_str_update.arrow +0 -0
- perspective/tests/table/object_sequence.py +402 -0
- perspective/tests/table/test_delete.py +124 -0
- perspective/tests/table/test_exception.py +53 -0
- perspective/tests/table/test_leaks.py +54 -0
- perspective/tests/table/test_ports.py +178 -0
- perspective/tests/table/test_remove.py +102 -0
- perspective/tests/table/test_table.py +610 -0
- perspective/tests/table/test_table_arrow.py +452 -0
- perspective/tests/table/test_table_datetime.py +2409 -0
- perspective/tests/table/test_table_infer.py +201 -0
- perspective/tests/table/test_table_limit.py +43 -0
- perspective/tests/table/test_table_numpy.py +1022 -0
- perspective/tests/table/test_table_pandas.py +1018 -0
- perspective/tests/table/test_to_arrow.py +414 -0
- perspective/tests/table/test_to_arrow_lz4.py +33 -0
- perspective/tests/table/test_to_format.py +1024 -0
- perspective/tests/table/test_update.py +545 -0
- perspective/tests/table/test_update_arrow.py +980 -0
- perspective/tests/table/test_update_numpy.py +252 -0
- perspective/tests/table/test_update_pandas.py +211 -0
- perspective/tests/table/test_view.py +2235 -0
- perspective/tests/table/test_view_expression.py +1940 -0
- perspective/tests/viewer/__init__.py +11 -0
- perspective/tests/viewer/test_validate.py +70 -0
- perspective/tests/viewer/test_viewer.py +245 -0
- perspective/tests/widget/__init__.py +11 -0
- perspective/tests/widget/test_widget.py +278 -0
- perspective/tests/widget/test_widget_pandas.py +453 -0
- perspective/viewer/__init__.py +15 -0
- perspective/viewer/validate.py +22 -0
- perspective/viewer/viewer.py +331 -0
- perspective/viewer/viewer_traitlets.py +101 -0
- perspective/widget/__init__.py +16 -0
- perspective/widget/widget.py +269 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/install.json +5 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/package.json +81 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js +18 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/253.6f17b87bb4eb1e656365.js.LICENSE.txt +59 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/905.d3bbc3d5954582d507bb.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/remoteEntry.7044010cbbf2a7208035.js +1 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/style.js +4 -0
- perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab/static/third-party-licenses.json +16 -0
- perspective_python-3.0.0rc1.dist-info/METADATA +13 -0
- perspective_python-3.0.0rc1.dist-info/RECORD +70 -0
- perspective_python-3.0.0rc1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import base64
|
|
14
|
+
import jinja2
|
|
15
|
+
import json
|
|
16
|
+
import logging
|
|
17
|
+
import os
|
|
18
|
+
from datetime import date, datetime
|
|
19
|
+
from functools import partial
|
|
20
|
+
|
|
21
|
+
from ipywidgets import DOMWidget
|
|
22
|
+
from traitlets import Unicode, observe
|
|
23
|
+
from ..viewer import PerspectiveViewer
|
|
24
|
+
import importlib
|
|
25
|
+
|
|
26
|
+
__version__ = importlib.metadata.version("perspective-python")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PerspectiveWidget(DOMWidget, PerspectiveViewer):
|
|
30
|
+
""":class`~perspective.PerspectiveWidget` allows for Perspective to be used
|
|
31
|
+
in the form of a Jupyter IPython widget.
|
|
32
|
+
|
|
33
|
+
Using `perspective.Table`, you can create a widget that extends the full
|
|
34
|
+
functionality of `perspective-viewer`. Changes on the viewer can be
|
|
35
|
+
programatically set on the :class`~perspective.PerspectiveWidget` instance,
|
|
36
|
+
and state is maintained across page refreshes.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
>>> from perspective import Table, PerspectiveWidget
|
|
40
|
+
>>> data = {
|
|
41
|
+
... "a": [1, 2, 3],
|
|
42
|
+
... "b": [
|
|
43
|
+
... "2019/07/11 7:30PM",
|
|
44
|
+
... "2019/07/11 8:30PM",
|
|
45
|
+
... "2019/07/11 9:30PM"
|
|
46
|
+
... ]
|
|
47
|
+
... }
|
|
48
|
+
>>> tbl = Table(data, index="a")
|
|
49
|
+
>>> widget = PerspectiveWidget(
|
|
50
|
+
... tbl,
|
|
51
|
+
... group_by=["a"],
|
|
52
|
+
... sort=[["b", "desc"]],
|
|
53
|
+
... filter=[["a", ">", 1]]
|
|
54
|
+
... )
|
|
55
|
+
>>> widget.sort
|
|
56
|
+
[["b", "desc"]]
|
|
57
|
+
>>> widget.sort.append(["a", "asc"])
|
|
58
|
+
>>> widget.sort
|
|
59
|
+
[["b", "desc"], ["a", "asc"]]
|
|
60
|
+
>>> widget.update({"a": [4, 5]}) # Browser UI updates
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Required by ipywidgets for proper registration of the backend
|
|
64
|
+
_model_name = Unicode("PerspectiveModel").tag(sync=True)
|
|
65
|
+
_model_module = Unicode("@finos/perspective-jupyterlab").tag(sync=True)
|
|
66
|
+
_model_module_version = Unicode("~{}".format(__version__)).tag(sync=True)
|
|
67
|
+
_view_name = Unicode("PerspectiveView").tag(sync=True)
|
|
68
|
+
_view_module = Unicode("@finos/perspective-jupyterlab").tag(sync=True)
|
|
69
|
+
_view_module_version = Unicode("~{}".format(__version__)).tag(sync=True)
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
data,
|
|
74
|
+
index=None,
|
|
75
|
+
limit=None,
|
|
76
|
+
binding_mode="server",
|
|
77
|
+
**kwargs,
|
|
78
|
+
):
|
|
79
|
+
"""Initialize an instance of :class`~perspective.PerspectiveWidget`
|
|
80
|
+
with the given table/data and viewer configuration.
|
|
81
|
+
|
|
82
|
+
If a pivoted DataFrame or MultiIndex table is passed in, the widget
|
|
83
|
+
preserves pivots and applies them. See `PerspectiveViewer.__init__` for
|
|
84
|
+
arguments that transform the view shown in the widget.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
data (:obj:`Table`|:obj:`View`|:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`|:obj:`bytes`|:obj:`str`): a
|
|
88
|
+
`perspective.Table` instance, a `perspective.View` instance, or
|
|
89
|
+
a dataset to be loaded in the widget.
|
|
90
|
+
|
|
91
|
+
Keyword Arguments:
|
|
92
|
+
index (:obj:`str`): A column name to be used as the primary key.
|
|
93
|
+
Ignored if `server` is True.
|
|
94
|
+
|
|
95
|
+
limit (:obj:`int`): A upper limit on the number of rows in the Table.
|
|
96
|
+
Cannot be set at the same time as `index`, ignored if `server`
|
|
97
|
+
is True.
|
|
98
|
+
|
|
99
|
+
binding_mode (:obj:`str`): "client-server" or "server"
|
|
100
|
+
|
|
101
|
+
kwargs (:obj:`dict`): configuration options for the `PerspectiveViewer`,
|
|
102
|
+
and `Table` constructor if `data` is a dataset.
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
>>> widget = PerspectiveWidget(
|
|
106
|
+
... {"a": [1, 2, 3]},
|
|
107
|
+
... aggregates={"a": "avg"},
|
|
108
|
+
... group_by=["a"],
|
|
109
|
+
... sort=[["b", "desc"]],
|
|
110
|
+
... filter=[["a", ">", 1]],
|
|
111
|
+
... expressions=["\"a\" + 100"])
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
self.binding_mode = binding_mode
|
|
115
|
+
|
|
116
|
+
# Pass table load options to the front-end, unless in server mode
|
|
117
|
+
self._options = {}
|
|
118
|
+
|
|
119
|
+
if index is not None and limit is not None:
|
|
120
|
+
raise TypeError("Index and Limit cannot be set at the same time!")
|
|
121
|
+
|
|
122
|
+
# Parse the dataset we pass in - if it's Pandas, preserve pivots
|
|
123
|
+
# if isinstance(data, pandas.DataFrame) or isinstance(data, pandas.Series):
|
|
124
|
+
# data, config = deconstruct_pandas(data)
|
|
125
|
+
|
|
126
|
+
# if config.get("group_by", None) and "group_by" not in kwargs:
|
|
127
|
+
# kwargs.update({"group_by": config["group_by"]})
|
|
128
|
+
|
|
129
|
+
# if config.get("split_by", None) and "split_by" not in kwargs:
|
|
130
|
+
# kwargs.update({"split_by": config["split_by"]})
|
|
131
|
+
|
|
132
|
+
# if config.get("columns", None) and "columns" not in kwargs:
|
|
133
|
+
# kwargs.update({"columns": config["columns"]})
|
|
134
|
+
|
|
135
|
+
# Initialize the viewer
|
|
136
|
+
super(PerspectiveWidget, self).__init__(**kwargs)
|
|
137
|
+
|
|
138
|
+
# Handle messages from the the front end
|
|
139
|
+
self.on_msg(self.handle_message)
|
|
140
|
+
self._sessions = {}
|
|
141
|
+
|
|
142
|
+
# If an empty dataset is provided, don't call `load()` and wait
|
|
143
|
+
# for the user to call `load()`.
|
|
144
|
+
if data is None:
|
|
145
|
+
if index is not None or limit is not None:
|
|
146
|
+
raise TypeError(
|
|
147
|
+
"Cannot initialize PerspectiveWidget `index` or `limit` without a Table, data, or schema!"
|
|
148
|
+
)
|
|
149
|
+
else:
|
|
150
|
+
if index is not None:
|
|
151
|
+
self._options.update({"index": index})
|
|
152
|
+
|
|
153
|
+
if limit is not None:
|
|
154
|
+
self._options.update({"limit": limit})
|
|
155
|
+
|
|
156
|
+
self.load(data, **self._options)
|
|
157
|
+
|
|
158
|
+
def load(self, data, **options):
|
|
159
|
+
"""Load the widget with data."""
|
|
160
|
+
# Viewer will ignore **options if `data` is a Table or View.
|
|
161
|
+
super(PerspectiveWidget, self).load(data, **options)
|
|
162
|
+
|
|
163
|
+
def update(self, data):
|
|
164
|
+
"""Update the widget with new data."""
|
|
165
|
+
super(PerspectiveWidget, self).update(data)
|
|
166
|
+
|
|
167
|
+
def clear(self):
|
|
168
|
+
"""Clears the widget's underlying `Table`."""
|
|
169
|
+
super(PerspectiveWidget, self).clear()
|
|
170
|
+
|
|
171
|
+
def replace(self, data):
|
|
172
|
+
"""Replaces the widget's `Table` with new data conforming to the same
|
|
173
|
+
schema. Does not clear user-set state. If in client mode, serializes
|
|
174
|
+
the data and sends it to the browser.
|
|
175
|
+
"""
|
|
176
|
+
super(PerspectiveWidget, self).replace(data)
|
|
177
|
+
|
|
178
|
+
def delete(self, delete_table=True):
|
|
179
|
+
"""Delete the Widget's data and clears its internal state.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
delete_table (`bool`): whether the underlying `Table` will be
|
|
183
|
+
deleted. Defaults to True.
|
|
184
|
+
"""
|
|
185
|
+
super(PerspectiveWidget, self).delete(delete_table)
|
|
186
|
+
|
|
187
|
+
# Close the underlying comm and remove widget from the front-end
|
|
188
|
+
self.close()
|
|
189
|
+
|
|
190
|
+
@observe("value")
|
|
191
|
+
def handle_message(self, widget, content, buffers):
|
|
192
|
+
"""Given a message from `PerspectiveJupyterClient.send()`, process the
|
|
193
|
+
message and return the result to `self.post`.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
widget: a reference to the `Widget` instance that received the
|
|
197
|
+
message.
|
|
198
|
+
content (dict): the message from the front-end. Automatically
|
|
199
|
+
de-serialized by ipywidgets.
|
|
200
|
+
buffers : optional arraybuffers from the front-end, if any.
|
|
201
|
+
"""
|
|
202
|
+
if content["type"] == "connect":
|
|
203
|
+
client_id = content["client_id"]
|
|
204
|
+
logging.debug("view {} connected", client_id)
|
|
205
|
+
self._sessions[client_id] = self.new_proxy_session(
|
|
206
|
+
lambda msg: self.send(
|
|
207
|
+
{"type": "binary_msg", "client_id": client_id}, [msg]
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
elif content["type"] == "binary_msg":
|
|
211
|
+
[binary_msg] = buffers
|
|
212
|
+
client_id = content["client_id"]
|
|
213
|
+
session = self._sessions[client_id]
|
|
214
|
+
logging.debug("view {} message {}", client_id, len(binary_msg))
|
|
215
|
+
if session is not None:
|
|
216
|
+
session.handle_request(binary_msg)
|
|
217
|
+
else:
|
|
218
|
+
logging.error("No session for client_id {}".format(client_id))
|
|
219
|
+
elif content["type"] == "hangup":
|
|
220
|
+
# XXX(tom): client won't reliably send this so shouldn't rely on it to clean up; does jupyter notify us
|
|
221
|
+
# when the client on the websocket, i.e. the view, disconnects?
|
|
222
|
+
client_id = content["client_id"]
|
|
223
|
+
logging.debug("view {} hangup", client_id)
|
|
224
|
+
session = self._sessions.pop(client_id, None)
|
|
225
|
+
if session:
|
|
226
|
+
session.close()
|
|
227
|
+
|
|
228
|
+
def _repr_mimebundle_(self, **kwargs):
|
|
229
|
+
super_bundle = super(DOMWidget, self)._repr_mimebundle_(**kwargs)
|
|
230
|
+
if not _jupyter_html_export_enabled():
|
|
231
|
+
return super_bundle
|
|
232
|
+
# Serialize viewer attrs + view data to be rendered in the template
|
|
233
|
+
viewer_attrs = self.save()
|
|
234
|
+
data = self.table.view().to_arrow()
|
|
235
|
+
b64_data = base64.encodebytes(data)
|
|
236
|
+
|
|
237
|
+
jinja_env = jinja2.Environment(
|
|
238
|
+
loader=jinja2.PackageLoader("perspective"),
|
|
239
|
+
autoescape=jinja2.select_autoescape(),
|
|
240
|
+
)
|
|
241
|
+
template = jinja_env.get_template("exported_widget.html.jinja")
|
|
242
|
+
|
|
243
|
+
def psp_cdn(module, path=None):
|
|
244
|
+
if path is None:
|
|
245
|
+
path = f"cdn/{module}.js"
|
|
246
|
+
# perspective developer affordance: works with your local `pnpm run start blocks`
|
|
247
|
+
# return f"http://localhost:8080/node_modules/@finos/{module}/dist/{path}"
|
|
248
|
+
return f"https://cdn.jsdelivr.net/npm/@finos/{module}@{__version__}/dist/{path}"
|
|
249
|
+
|
|
250
|
+
return super(DOMWidget, self)._repr_mimebundle_(**kwargs) | {
|
|
251
|
+
"text/html": template.render(
|
|
252
|
+
psp_cdn=psp_cdn,
|
|
253
|
+
viewer_id=self.model_id,
|
|
254
|
+
viewer_attrs=viewer_attrs,
|
|
255
|
+
b64_data=b64_data.decode("utf-8"),
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _jupyter_html_export_enabled():
|
|
261
|
+
return os.environ.get("PSP_JUPYTER_HTML_EXPORT", None) == "1"
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def set_jupyter_html_export(val):
|
|
265
|
+
"""Enables HTML export for Jupyter widgets, when set to True.
|
|
266
|
+
HTML export can also be enabled by setting the environment variable
|
|
267
|
+
`PSP_JUPYTER_HTML_EXPORT` to the string `1`.
|
|
268
|
+
"""
|
|
269
|
+
os.environ["PSP_JUPYTER_HTML_EXPORT"] = "1" if val else "0"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@finos/perspective-jupyterlab",
|
|
3
|
+
"version": "3.0.0-rc.1",
|
|
4
|
+
"description": "A Jupyterlab extension for the Perspective library, designed to be used with perspective-python.",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist/**/*",
|
|
7
|
+
"src/**/*"
|
|
8
|
+
],
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"main": "dist/esm/perspective-jupyterlab.js",
|
|
11
|
+
"style": "dist/css/perspective-jupyterlab.css",
|
|
12
|
+
"directories": {
|
|
13
|
+
"dist": "dist/"
|
|
14
|
+
},
|
|
15
|
+
"license": "Apache-2.0",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"bench": "npm-run-all bench:build bench:run",
|
|
21
|
+
"bench:build": "echo \"No Benchmarks\"",
|
|
22
|
+
"bench:run": "echo \"No Benchmarks\"",
|
|
23
|
+
"build": "npm-run-all build:js build:labextension",
|
|
24
|
+
"build:js": "node build.mjs",
|
|
25
|
+
"build:labextension": "jupyter labextension build .",
|
|
26
|
+
"clean": "npm-run-all clean:*",
|
|
27
|
+
"clean:dist": "rimraf dist",
|
|
28
|
+
"clean:lib": "rimraf lib",
|
|
29
|
+
"clean:labextension": "rimraf ../../rust/perspective-python/perspective/labextension",
|
|
30
|
+
"clean:nbextension": "rimraf ../../rust/perspective-python/perspective/nbextension/static",
|
|
31
|
+
"test:build": "node build.mjs --test",
|
|
32
|
+
"test:jupyter:build": "cpy \"test/arrow/*\" dist/esm",
|
|
33
|
+
"test:jupyter": "__JUPYTERLAB_PORT__=6538 npx playwright test --config ../../tools/perspective-test/playwright.config.ts -- --jupyter",
|
|
34
|
+
"test": "npm-run-all test:build",
|
|
35
|
+
"version": "yarn build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@finos/perspective": "workspace:^",
|
|
39
|
+
"@finos/perspective-viewer": "workspace:^",
|
|
40
|
+
"@finos/perspective-viewer-d3fc": "workspace:^",
|
|
41
|
+
"@finos/perspective-viewer-datagrid": "workspace:^",
|
|
42
|
+
"@finos/perspective-viewer-openlayers": "workspace:^",
|
|
43
|
+
"@jupyter-widgets/base": ">2 <5",
|
|
44
|
+
"@jupyterlab/application": ">2 <5",
|
|
45
|
+
"@lumino/application": "<3",
|
|
46
|
+
"@lumino/widgets": "<3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@finos/perspective-esbuild-plugin": "workspace:^",
|
|
50
|
+
"@finos/perspective-test": "workspace:^",
|
|
51
|
+
"@jupyterlab/builder": "^4",
|
|
52
|
+
"@prospective.co/procss": "^0.1.15",
|
|
53
|
+
"cpy": "^9.0.1"
|
|
54
|
+
},
|
|
55
|
+
"jupyterlab": {
|
|
56
|
+
"webpackConfig": "./webpack.config.js",
|
|
57
|
+
"extension": true,
|
|
58
|
+
"outputDir": "../../rust/perspective-python/perspective.data/data/share/jupyter/labextensions/@finos/perspective-jupyterlab",
|
|
59
|
+
"sharedPackages": {
|
|
60
|
+
"@jupyter-widgets/base": {
|
|
61
|
+
"bundled": false,
|
|
62
|
+
"singleton": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"discovery": {
|
|
66
|
+
"server": {
|
|
67
|
+
"base": {
|
|
68
|
+
"name": "perspective-python"
|
|
69
|
+
},
|
|
70
|
+
"managers": [
|
|
71
|
+
"pip"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"_build": {
|
|
76
|
+
"load": "static\\remoteEntry.7044010cbbf2a7208035.js",
|
|
77
|
+
"extension": "./extension",
|
|
78
|
+
"style": "./style"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|