perspective-python 4.2.0__cp311-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 +396 -0
- perspective/extension/finos-perspective-nbextension.json +5 -0
- perspective/handlers/__init__.py +11 -0
- perspective/handlers/aiohttp.py +61 -0
- perspective/handlers/starlette.py +55 -0
- perspective/handlers/tornado.py +184 -0
- perspective/perspective.pyd +0 -0
- perspective/templates/exported_widget.html.template +35 -0
- perspective/tests/__init__.py +11 -0
- perspective/tests/async/test_async_client.py +83 -0
- perspective/tests/async/test_websocket_client.py +124 -0
- perspective/tests/conftest.py +272 -0
- perspective/tests/core/__init__.py +11 -0
- perspective/tests/core/test_async.py +351 -0
- perspective/tests/multi_threaded/__init__.py +11 -0
- perspective/tests/multi_threaded/test_multi_threaded.py +201 -0
- perspective/tests/server/__init__.py +11 -0
- perspective/tests/server/test_server.py +1016 -0
- perspective/tests/server/test_session.py +110 -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_column_paths.py +89 -0
- perspective/tests/table/test_delete.py +124 -0
- perspective/tests/table/test_exception.py +65 -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 +641 -0
- perspective/tests/table/test_table_arrow.py +503 -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 +45 -0
- perspective/tests/table/test_table_numpy.py +1022 -0
- perspective/tests/table/test_table_pandas.py +1018 -0
- perspective/tests/table/test_table_polars.py +251 -0
- perspective/tests/table/test_table_view_table.py +130 -0
- perspective/tests/table/test_to_arrow.py +417 -0
- perspective/tests/table/test_to_arrow_lz4.py +32 -0
- perspective/tests/table/test_to_format.py +1024 -0
- perspective/tests/table/test_to_polars.py +26 -0
- perspective/tests/table/test_update.py +545 -0
- perspective/tests/table/test_update_arrow.py +980 -0
- perspective/tests/table/test_update_pandas.py +211 -0
- perspective/tests/table/test_view.py +2261 -0
- perspective/tests/table/test_view_expression.py +1940 -0
- perspective/tests/test_dependencies.py +53 -0
- perspective/tests/viewer/__init__.py +11 -0
- perspective/tests/viewer/test_viewer.py +246 -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/virtual_servers/__init__.py +134 -0
- perspective/virtual_servers/clickhouse.py +245 -0
- perspective/virtual_servers/duckdb.py +236 -0
- perspective/widget/__init__.py +349 -0
- perspective/widget/viewer/__init__.py +15 -0
- perspective/widget/viewer/validate.py +22 -0
- perspective/widget/viewer/viewer.py +343 -0
- perspective/widget/viewer/viewer_traitlets.py +101 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/install.json +5 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/package.json +71 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js +2 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js.LICENSE.txt +25 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/523.c030af5d3c4f67ff83f6.js +1 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/remoteEntry.95a8ea1b44d96032833f.js +1 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/style.js +4 -0
- perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/third-party-licenses.json +16 -0
- perspective_python-4.2.0.dist-info/METADATA +27 -0
- perspective_python-4.2.0.dist-info/RECORD +79 -0
- perspective_python-4.2.0.dist-info/WHEEL +4 -0
- perspective_python-4.2.0.dist-info/licenses/LICENSE.md +193 -0
- perspective_python-4.2.0.dist-info/licenses/LICENSE_THIRDPARTY_cargo.yml +17395 -0
|
@@ -0,0 +1,343 @@
|
|
|
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
|
+
from random import random
|
|
14
|
+
from .viewer_traitlets import PerspectiveTraitlets
|
|
15
|
+
import perspective
|
|
16
|
+
|
|
17
|
+
# from .. import Server
|
|
18
|
+
|
|
19
|
+
# ─ │ ┌ ┬ ┐
|
|
20
|
+
# ┄ ┆ ├ ┼ ┤ ╲ ╱
|
|
21
|
+
# ┈ ┊ └ ┴ ┘
|
|
22
|
+
# ━ ┃ ┏ ┳ ┓ ┏ ┯ ┓ ┏ ┳ ┓ ┏ ┯ ┓
|
|
23
|
+
# ┅ ┇ ┣ ╋ ┫ ┣ ┿ ┫ ┠ ╂ ┨ ┠ ┼ ┨
|
|
24
|
+
# ┉ ┋ ┗ ┻ ┛ ┗ ┷ ┛ ┗ ┻ ┛ ┗ ┷ ┛
|
|
25
|
+
|
|
26
|
+
# global_server = PySyncServer()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PerspectiveViewer(PerspectiveTraitlets, object):
|
|
30
|
+
"""PerspectiveViewer wraps the `perspective.Table` API and exposes an API
|
|
31
|
+
around creating views, loading data, and updating data.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Viewer attributes that should be saved in `save()` and restored using
|
|
35
|
+
# `restore()`. Symmetric to `PERSISTENT_ATTRIBUTES` in `perspective-viewer`.
|
|
36
|
+
PERSISTENT_ATTRIBUTES = (
|
|
37
|
+
"group_by",
|
|
38
|
+
"split_by",
|
|
39
|
+
"filter",
|
|
40
|
+
"sort",
|
|
41
|
+
"aggregates",
|
|
42
|
+
"columns",
|
|
43
|
+
"expressions",
|
|
44
|
+
"plugin",
|
|
45
|
+
"plugin_config",
|
|
46
|
+
"theme",
|
|
47
|
+
"settings",
|
|
48
|
+
"title",
|
|
49
|
+
"version",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
plugin="Datagrid",
|
|
55
|
+
columns=None,
|
|
56
|
+
group_by=None,
|
|
57
|
+
split_by=None,
|
|
58
|
+
aggregates=None,
|
|
59
|
+
sort=None,
|
|
60
|
+
filter=None,
|
|
61
|
+
expressions=None,
|
|
62
|
+
plugin_config=None,
|
|
63
|
+
settings=True,
|
|
64
|
+
theme=None,
|
|
65
|
+
title=None,
|
|
66
|
+
# ignored, here for restore compatibility
|
|
67
|
+
version=None,
|
|
68
|
+
):
|
|
69
|
+
"""Initialize an instance of `PerspectiveViewer` with the given viewer
|
|
70
|
+
configuration. Do not pass a `Table` or data into the constructor -
|
|
71
|
+
use the :func:`load()` method to provide the viewer with data.
|
|
72
|
+
|
|
73
|
+
Keyword Arguments:
|
|
74
|
+
columns (:obj:`list` of :obj:`str`): A list of column names to be
|
|
75
|
+
visible to the user.
|
|
76
|
+
group_by (:obj:`list` of :obj:`str`): A list of column names to
|
|
77
|
+
use as group by.
|
|
78
|
+
split_by (:obj:`list` of :obj:`str`): A list of column names
|
|
79
|
+
to use as split by.
|
|
80
|
+
aggregates (:obj:`dict` of :obj:`str` to :obj:`str`): A dictionary
|
|
81
|
+
of column names to aggregate types, which specify aggregates
|
|
82
|
+
for individual columns.
|
|
83
|
+
sort (:obj:`list` of :obj:`list` of :obj:`str`): A list of lists,
|
|
84
|
+
each list containing a column name and a sort direction
|
|
85
|
+
(``asc``, ``desc``, ``asc abs``, ``desc abs``, ``col asc``,
|
|
86
|
+
``col desc``, ``col asc abs``, ``col desc abs``).
|
|
87
|
+
filter (:obj:`list` of :obj:`list` of :obj:`str`): A list of lists,
|
|
88
|
+
each list containing a column name, a filter comparator, and a
|
|
89
|
+
value to filter by.
|
|
90
|
+
expressions (:obj:`list` of :obj:`str`): A list of string
|
|
91
|
+
expressions which are applied to the view.
|
|
92
|
+
plugin (:obj:`str`/:obj:`perspective.Plugin`): Which plugin to
|
|
93
|
+
select by default.
|
|
94
|
+
plugin_config (:obj:`dict`): A configuration for the plugin, i.e.
|
|
95
|
+
the datagrid plugin or a chart plugin.
|
|
96
|
+
settings(:obj:`bool`): Whether the perspective query settings
|
|
97
|
+
panel should be open.
|
|
98
|
+
theme (:obj:`str`): The color theme to use.
|
|
99
|
+
version (:obj:`str`): The version this configuration is restored from.
|
|
100
|
+
This should only be used when restoring a configuration,
|
|
101
|
+
and should not be set manually.
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
>>> viewer = PerspectiveViewer(
|
|
105
|
+
... aggregates={"a": "avg"},
|
|
106
|
+
... group_by=["a"],
|
|
107
|
+
... sort=[["b", "desc"]],
|
|
108
|
+
... filter=[["a", ">", 1]],
|
|
109
|
+
... expressions=["\"a\" + 100"]
|
|
110
|
+
... )
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
# The Table under management by this viewer and its
|
|
114
|
+
# attached PerspectiveManager
|
|
115
|
+
self._table = None
|
|
116
|
+
self._client = None
|
|
117
|
+
|
|
118
|
+
# Viewer configuration
|
|
119
|
+
self.plugin = plugin # validate_plugin(plugin)
|
|
120
|
+
self.columns = columns or [] # validate_columns(columns) or []
|
|
121
|
+
self.group_by = group_by or [] # validate_group_by(group_by) or []
|
|
122
|
+
self.split_by = split_by or [] # validate_split_by(split_by) or []
|
|
123
|
+
self.aggregates = aggregates or {} # validate_aggregates(aggregates) or {}
|
|
124
|
+
self.sort = sort or [] # validate_sort(sort) or []
|
|
125
|
+
self.filter = filter or [] # validate_filter(filter) or []
|
|
126
|
+
self.expressions = expressions or {} # validate_expressions(expressions) or {}
|
|
127
|
+
self.plugin_config = (
|
|
128
|
+
plugin_config or {}
|
|
129
|
+
) # validate_plugin_config(plugin_config) or {}
|
|
130
|
+
self.settings = settings
|
|
131
|
+
self.theme = theme
|
|
132
|
+
self.title = title
|
|
133
|
+
|
|
134
|
+
def new_proxy_session(self, cb):
|
|
135
|
+
return perspective.ProxySession(self._client, cb)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def client(self):
|
|
139
|
+
"""Returns the ``perspective.Client`` or ``perspective.AsyncClient`` under management by the viewer."""
|
|
140
|
+
return self._client
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def table(self):
|
|
144
|
+
"""Returns the ``perspective.Table`` or ``perspective.AsyncTable`` under management by the viewer."""
|
|
145
|
+
return self._table
|
|
146
|
+
|
|
147
|
+
def is_async(self):
|
|
148
|
+
"""Returns whether this widget has an async interface or synchronous"""
|
|
149
|
+
return isinstance(self._table, perspective.perspective.AsyncTable)
|
|
150
|
+
|
|
151
|
+
def load(self, data, **options):
|
|
152
|
+
"""Given a ``perspective.Table``, a ``perspective.AsyncTable``,
|
|
153
|
+
or data that can be handled by ``perspective.Table``, pass it to the
|
|
154
|
+
viewer. Like `__init__`, load accepts a `perspective.Table`, a dataset,
|
|
155
|
+
or a schema.
|
|
156
|
+
|
|
157
|
+
``load()`` resets the state of the viewer: if a ``perspective.Table``
|
|
158
|
+
has already been loaded, ``**options`` is ignored as the options
|
|
159
|
+
already set on the ``Table`` take precedence.
|
|
160
|
+
|
|
161
|
+
If data is passed in, a ``perspective.Table`` is automatically created
|
|
162
|
+
by this method, and the options passed to ``**config`` are extended to
|
|
163
|
+
the new Table. If the widget already has a dataset, and the new data
|
|
164
|
+
has different columns to the old one, then the widget state (pivots,
|
|
165
|
+
sort, etc.) is cleared to prevent applying settings on columns that
|
|
166
|
+
don't exist.
|
|
167
|
+
|
|
168
|
+
When a ``perspective.AsyncTable`` is loaded, the widget's interface
|
|
169
|
+
becomes async. Methods which operate on the underlying Perspective
|
|
170
|
+
view, inclusive of the ``load()`` call itself, return coroutine values
|
|
171
|
+
which must be awaited.
|
|
172
|
+
|
|
173
|
+
Loading a ``perspective.Table`` or plain data will make the interface
|
|
174
|
+
synchronous again.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
data (:obj:`Table`|:obj:`AsyncTable`|:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`|:obj:`bytes`|:obj:`str`): a
|
|
178
|
+
`perspective.Table` instance, a `perspective.AsyncTable`
|
|
179
|
+
instance, or a dataset to be loaded in the viewer.
|
|
180
|
+
|
|
181
|
+
Keyword Arguments:
|
|
182
|
+
name (:obj:`str`): An optional name to reference the table by so it can
|
|
183
|
+
be accessed from the front-end. If not provided, a name will
|
|
184
|
+
be generated.
|
|
185
|
+
index (:obj:`str`): A column name to be used as the primary key.
|
|
186
|
+
Ignored if a ``Table`` or ``AsyncTable`` is supplied.
|
|
187
|
+
limit (:obj:`int`): A upper limit on the number of rows in the Table.
|
|
188
|
+
Cannot be set at the same time as `index`. Ignored if a
|
|
189
|
+
``Table`` or ``AsyncTable`` is supplied.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
coro (:obj:`coroutine`): when `AsyncTable` is passed, the `load()` call must be awaited
|
|
193
|
+
"""
|
|
194
|
+
name = options.pop("name", str(random()))
|
|
195
|
+
|
|
196
|
+
# Reset the viewer when `load()` is called multiple times.
|
|
197
|
+
if self.table is not None:
|
|
198
|
+
self.reset()
|
|
199
|
+
|
|
200
|
+
if isinstance(data, perspective.perspective.AsyncTable):
|
|
201
|
+
self._table = data
|
|
202
|
+
async def load_table():
|
|
203
|
+
self._client = await self.table.get_client()
|
|
204
|
+
self.table_name = self.table.get_name()
|
|
205
|
+
# If the user does not set columns to show, synchronize viewer state
|
|
206
|
+
# with dataset.
|
|
207
|
+
if len(self.columns) == 0:
|
|
208
|
+
self.columns = await self.table.columns()
|
|
209
|
+
|
|
210
|
+
return load_table()
|
|
211
|
+
elif isinstance(data, perspective.perspective.Table):
|
|
212
|
+
self._table = data
|
|
213
|
+
self._client = data.get_client()
|
|
214
|
+
elif isinstance(data, perspective.perspective.View) or isinstance(data, perspective.perspective.AsyncView):
|
|
215
|
+
raise TypeError(
|
|
216
|
+
"Views cannot be loaded directly, load a table or raw data instead"
|
|
217
|
+
)
|
|
218
|
+
else:
|
|
219
|
+
self._table = perspective.table(data, name=name, **options)
|
|
220
|
+
self._client = perspective.GLOBAL_CLIENT
|
|
221
|
+
|
|
222
|
+
# If the user does not set columns to show, synchronize viewer state
|
|
223
|
+
# with dataset.
|
|
224
|
+
if len(self.columns) == 0:
|
|
225
|
+
self.columns = self.table.columns()
|
|
226
|
+
|
|
227
|
+
self.table_name = self.table.get_name()
|
|
228
|
+
|
|
229
|
+
def update(self, data):
|
|
230
|
+
"""Update the table under management by the viewer with new data.
|
|
231
|
+
This function follows the semantics of `Table.update()`, and will be
|
|
232
|
+
affected by whether an index is set on the underlying table.
|
|
233
|
+
|
|
234
|
+
When this widget has loaded an ``AsyncTable``, returns a coroutine
|
|
235
|
+
which must be awaited.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
data (:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`): the
|
|
239
|
+
update data for the table.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
coro (:obj:`coroutine`): when async, must be awaited
|
|
243
|
+
"""
|
|
244
|
+
return self.table.update(data)
|
|
245
|
+
|
|
246
|
+
def clear(self):
|
|
247
|
+
"""Clears the rows of this viewer's ``Table``."""
|
|
248
|
+
if self.table is not None:
|
|
249
|
+
return self.table.clear()
|
|
250
|
+
|
|
251
|
+
def replace(self, data):
|
|
252
|
+
"""Replaces the rows of this viewer's `Table` with new data.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
data (:obj:`dict`|:obj:`list`|:obj:`pandas.DataFrame`): new data
|
|
256
|
+
to set into the table - must conform to the table's schema.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
coro (:obj:`coroutine`): when async, must be awaited
|
|
260
|
+
"""
|
|
261
|
+
if self.table is not None:
|
|
262
|
+
return self.table.replace(data)
|
|
263
|
+
|
|
264
|
+
def save(self):
|
|
265
|
+
"""Get the viewer's attributes as a dictionary, symmetric with `restore`
|
|
266
|
+
so that a viewer's configuration can be reproduced."""
|
|
267
|
+
return {
|
|
268
|
+
attr: getattr(self, attr)
|
|
269
|
+
for attr in PerspectiveViewer.PERSISTENT_ATTRIBUTES
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
def restore(self, **kwargs):
|
|
273
|
+
"""Restore a given set of attributes, passed as kwargs
|
|
274
|
+
(e.g. dictionary). Symmetric with `save` so that a given viewer's
|
|
275
|
+
configuration can be reproduced."""
|
|
276
|
+
for k, v in kwargs.items():
|
|
277
|
+
if k in PerspectiveViewer.PERSISTENT_ATTRIBUTES:
|
|
278
|
+
setattr(self, k, v)
|
|
279
|
+
|
|
280
|
+
def to_kwargs(self):
|
|
281
|
+
"""Get the viewer's attributes as a list of kwargs, which can be passed to
|
|
282
|
+
the viewer constructor"""
|
|
283
|
+
attrs = self.save()
|
|
284
|
+
defaults = {
|
|
285
|
+
"columns": [],
|
|
286
|
+
"group_by": [],
|
|
287
|
+
"split_by": [],
|
|
288
|
+
"aggregates": {},
|
|
289
|
+
"sort": [],
|
|
290
|
+
"filter": [],
|
|
291
|
+
"expressions": {},
|
|
292
|
+
"plugin_config": {},
|
|
293
|
+
"version": "2.10.0",
|
|
294
|
+
}
|
|
295
|
+
kwargs = {}
|
|
296
|
+
for key, default in defaults.items():
|
|
297
|
+
if attrs.get(key) != default:
|
|
298
|
+
kwargs[key] = attrs[key]
|
|
299
|
+
return ", ".join(
|
|
300
|
+
["{}={}".format(attr, repr(val)) for attr, val in kwargs.items()]
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def reset(self):
|
|
304
|
+
"""Resets the viewer's attributes and state, but does not delete or
|
|
305
|
+
modify the underlying `Table`.
|
|
306
|
+
|
|
307
|
+
Example:
|
|
308
|
+
widget = PerspectiveWidget(data, group_by=["date"], plugin=Plugin.XBAR)
|
|
309
|
+
widget.reset()
|
|
310
|
+
widget.plugin #
|
|
311
|
+
"""
|
|
312
|
+
self.group_by = []
|
|
313
|
+
self.split_by = []
|
|
314
|
+
self.filter = []
|
|
315
|
+
self.sort = []
|
|
316
|
+
self.expressions = {}
|
|
317
|
+
self.aggregates = {}
|
|
318
|
+
self.columns = []
|
|
319
|
+
self.plugin = "Datagrid"
|
|
320
|
+
self.plugin_config = {}
|
|
321
|
+
|
|
322
|
+
def delete(self, delete_table=True):
|
|
323
|
+
"""Delete the Viewer's data and clears its internal state. If
|
|
324
|
+
``delete_table`` is True, the underlying `perspective.Table` and the
|
|
325
|
+
internal `View` object will be deleted.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
delete_table (:obj:`bool`) : whether the underlying `Table` will be
|
|
329
|
+
deleted. Defaults to True.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
coro (:obj:`coroutine`): when async and `delete_table` is `True`,
|
|
333
|
+
must be awaited
|
|
334
|
+
"""
|
|
335
|
+
ret = None
|
|
336
|
+
if delete_table:
|
|
337
|
+
# Delete table
|
|
338
|
+
ret = self.table.delete()
|
|
339
|
+
self.table_name = None
|
|
340
|
+
self._table = None
|
|
341
|
+
|
|
342
|
+
self.reset()
|
|
343
|
+
return ret
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
+
from traitlets import HasTraits, Unicode, List, Bool, Dict, validate, Enum
|
|
14
|
+
|
|
15
|
+
import importlib.metadata
|
|
16
|
+
|
|
17
|
+
__version__ = importlib.metadata.version("perspective-python")
|
|
18
|
+
|
|
19
|
+
from .validate import (
|
|
20
|
+
validate_version,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PerspectiveTraitlets(HasTraits):
|
|
25
|
+
"""Define the traitlet interface with `PerspectiveJupyterWidget` on the
|
|
26
|
+
front end. Attributes which are set here are synchronized between the
|
|
27
|
+
front-end and back-end.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
>>> widget = perspective.PerspectiveWidget(
|
|
31
|
+
... data, group_by=["a", "b", "c"])
|
|
32
|
+
PerspectiveWidget(group_by=["a", "b", "c"])
|
|
33
|
+
>>> widget.split_by=["b"]
|
|
34
|
+
>>> widget
|
|
35
|
+
PerspectiveWidget(group_by=["a", "b", "c"], split_by=["b"])
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# `perspective-viewer` options
|
|
39
|
+
plugin = Unicode("Datagrid").tag(sync=True)
|
|
40
|
+
columns = List(default_value=[]).tag(sync=True)
|
|
41
|
+
group_by = List(trait=Unicode(), default_value=[]).tag(sync=True, o=True)
|
|
42
|
+
split_by = List(trait=Unicode(), default_value=[]).tag(sync=True)
|
|
43
|
+
aggregates = Dict(default_value={}).tag(sync=True)
|
|
44
|
+
sort = List(default_value=[]).tag(sync=True)
|
|
45
|
+
filter = List(default_value=[]).tag(sync=True)
|
|
46
|
+
expressions = Dict(default_value=[]).tag(sync=True)
|
|
47
|
+
plugin_config = Dict(default_value={}).tag(sync=True)
|
|
48
|
+
settings = Bool(True).tag(sync=True)
|
|
49
|
+
theme = Unicode("Pro Light", allow_none=True).tag(sync=True)
|
|
50
|
+
|
|
51
|
+
# used to tell the frontend which table to connect to
|
|
52
|
+
table_name = Unicode(None, allow_none=True).tag(sync=True)
|
|
53
|
+
|
|
54
|
+
server = Bool(False).tag(sync=True)
|
|
55
|
+
binding_mode = Enum(("server", "client-server")).tag(default="server", sync=True)
|
|
56
|
+
title = Unicode(None, allow_none=True).tag(sync=True)
|
|
57
|
+
version = Unicode(__version__).tag(sync=True)
|
|
58
|
+
|
|
59
|
+
# @validate("plugin")
|
|
60
|
+
# def _validate_plugin(self, proposal):
|
|
61
|
+
# return validate_plugin(proposal.value)
|
|
62
|
+
|
|
63
|
+
# @validate("columns")
|
|
64
|
+
# def _validate_columns(self, proposal):
|
|
65
|
+
# return validate_columns(proposal.value)
|
|
66
|
+
|
|
67
|
+
# @validate("group_by")
|
|
68
|
+
# def _validate_group_by(self, proposal):
|
|
69
|
+
# return validate_group_by(proposal.value)
|
|
70
|
+
|
|
71
|
+
# @validate("split_by")
|
|
72
|
+
# def _validate_split_by(self, proposal):
|
|
73
|
+
# return validate_split_by(proposal.value)
|
|
74
|
+
|
|
75
|
+
# @validate("aggregates")
|
|
76
|
+
# def _validate_aggregates(self, proposal):
|
|
77
|
+
# return validate_aggregates(proposal.value)
|
|
78
|
+
|
|
79
|
+
# @validate("sort")
|
|
80
|
+
# def _validate_sort(self, proposal):
|
|
81
|
+
# return validate_sort(proposal.value)
|
|
82
|
+
|
|
83
|
+
# @validate("filter")
|
|
84
|
+
# def _validate_filter(self, proposal):
|
|
85
|
+
# return validate_filter(proposal.value)
|
|
86
|
+
|
|
87
|
+
# @validate("expressions")
|
|
88
|
+
# def _validate_expressions(self, proposal):
|
|
89
|
+
# return validate_expressions(proposal.value)
|
|
90
|
+
|
|
91
|
+
# @validate("plugin_config")
|
|
92
|
+
# def _validate_plugin_config(self, proposal):
|
|
93
|
+
# return validate_plugin_config(proposal.value)
|
|
94
|
+
|
|
95
|
+
# @validate("title")
|
|
96
|
+
# def _validate_title(self, proposal):
|
|
97
|
+
# return validate_title(proposal.value)
|
|
98
|
+
|
|
99
|
+
@validate("version")
|
|
100
|
+
def _validate_version(self, proposal):
|
|
101
|
+
return validate_version(proposal.value)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@perspective-dev/jupyterlab",
|
|
3
|
+
"version": "4.2.0",
|
|
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
|
+
"build": "node ./build.mjs",
|
|
21
|
+
"clean": "node ./clean.mjs",
|
|
22
|
+
"test:jupyter": "__JUPYTERLAB_PORT__=6538 npx playwright test --config ../../tools/test/playwright.config.ts -- --jupyter",
|
|
23
|
+
"test:jupyter:build": "node ./build.mjs --test"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@perspective-dev/viewer-d3fc": "workspace:",
|
|
27
|
+
"@perspective-dev/viewer-datagrid": "workspace:",
|
|
28
|
+
"@perspective-dev/viewer-openlayers": "workspace:",
|
|
29
|
+
"@perspective-dev/viewer": "workspace:",
|
|
30
|
+
"@perspective-dev/client": "workspace:",
|
|
31
|
+
"@perspective-dev/server": "workspace:",
|
|
32
|
+
"@jupyter-widgets/base": ">2 <5",
|
|
33
|
+
"@jupyterlab/application": ">2 <5",
|
|
34
|
+
"@lumino/application": "<3",
|
|
35
|
+
"@lumino/widgets": "<3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@perspective-dev/esbuild-plugin": "workspace:",
|
|
39
|
+
"@perspective-dev/test": "workspace:",
|
|
40
|
+
"@jupyterlab/builder": "^4",
|
|
41
|
+
"@prospective.co/procss": "^0.1.16",
|
|
42
|
+
"copy-webpack-plugin": "~12",
|
|
43
|
+
"zx": "^8.1.8"
|
|
44
|
+
},
|
|
45
|
+
"jupyterlab": {
|
|
46
|
+
"webpackConfig": "./webpack.config.js",
|
|
47
|
+
"extension": true,
|
|
48
|
+
"outputDir": "./dist/cjs",
|
|
49
|
+
"sharedPackages": {
|
|
50
|
+
"@jupyter-widgets/base": {
|
|
51
|
+
"bundled": false,
|
|
52
|
+
"singleton": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"discovery": {
|
|
56
|
+
"server": {
|
|
57
|
+
"base": {
|
|
58
|
+
"name": "perspective-python"
|
|
59
|
+
},
|
|
60
|
+
"managers": [
|
|
61
|
+
"pip"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"_build": {
|
|
66
|
+
"load": "static\\remoteEntry.95a8ea1b44d96032833f.js",
|
|
67
|
+
"extension": "./extension",
|
|
68
|
+
"style": "./style"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|