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.
Files changed (79) hide show
  1. perspective/__init__.py +396 -0
  2. perspective/extension/finos-perspective-nbextension.json +5 -0
  3. perspective/handlers/__init__.py +11 -0
  4. perspective/handlers/aiohttp.py +61 -0
  5. perspective/handlers/starlette.py +55 -0
  6. perspective/handlers/tornado.py +184 -0
  7. perspective/perspective.pyd +0 -0
  8. perspective/templates/exported_widget.html.template +35 -0
  9. perspective/tests/__init__.py +11 -0
  10. perspective/tests/async/test_async_client.py +83 -0
  11. perspective/tests/async/test_websocket_client.py +124 -0
  12. perspective/tests/conftest.py +272 -0
  13. perspective/tests/core/__init__.py +11 -0
  14. perspective/tests/core/test_async.py +351 -0
  15. perspective/tests/multi_threaded/__init__.py +11 -0
  16. perspective/tests/multi_threaded/test_multi_threaded.py +201 -0
  17. perspective/tests/server/__init__.py +11 -0
  18. perspective/tests/server/test_server.py +1016 -0
  19. perspective/tests/server/test_session.py +110 -0
  20. perspective/tests/table/__init__.py +11 -0
  21. perspective/tests/table/arrow/date32.arrow +0 -0
  22. perspective/tests/table/arrow/date64.arrow +0 -0
  23. perspective/tests/table/arrow/dict.arrow +0 -0
  24. perspective/tests/table/arrow/dict_update.arrow +0 -0
  25. perspective/tests/table/arrow/int_float_str.arrow +0 -0
  26. perspective/tests/table/arrow/int_float_str_file.arrow +0 -0
  27. perspective/tests/table/arrow/int_float_str_update.arrow +0 -0
  28. perspective/tests/table/object_sequence.py +402 -0
  29. perspective/tests/table/test_column_paths.py +89 -0
  30. perspective/tests/table/test_delete.py +124 -0
  31. perspective/tests/table/test_exception.py +65 -0
  32. perspective/tests/table/test_leaks.py +54 -0
  33. perspective/tests/table/test_ports.py +178 -0
  34. perspective/tests/table/test_remove.py +102 -0
  35. perspective/tests/table/test_table.py +641 -0
  36. perspective/tests/table/test_table_arrow.py +503 -0
  37. perspective/tests/table/test_table_datetime.py +2409 -0
  38. perspective/tests/table/test_table_infer.py +201 -0
  39. perspective/tests/table/test_table_limit.py +45 -0
  40. perspective/tests/table/test_table_numpy.py +1022 -0
  41. perspective/tests/table/test_table_pandas.py +1018 -0
  42. perspective/tests/table/test_table_polars.py +251 -0
  43. perspective/tests/table/test_table_view_table.py +130 -0
  44. perspective/tests/table/test_to_arrow.py +417 -0
  45. perspective/tests/table/test_to_arrow_lz4.py +32 -0
  46. perspective/tests/table/test_to_format.py +1024 -0
  47. perspective/tests/table/test_to_polars.py +26 -0
  48. perspective/tests/table/test_update.py +545 -0
  49. perspective/tests/table/test_update_arrow.py +980 -0
  50. perspective/tests/table/test_update_pandas.py +211 -0
  51. perspective/tests/table/test_view.py +2261 -0
  52. perspective/tests/table/test_view_expression.py +1940 -0
  53. perspective/tests/test_dependencies.py +53 -0
  54. perspective/tests/viewer/__init__.py +11 -0
  55. perspective/tests/viewer/test_viewer.py +246 -0
  56. perspective/tests/widget/__init__.py +11 -0
  57. perspective/tests/widget/test_widget.py +278 -0
  58. perspective/tests/widget/test_widget_pandas.py +453 -0
  59. perspective/virtual_servers/__init__.py +134 -0
  60. perspective/virtual_servers/clickhouse.py +245 -0
  61. perspective/virtual_servers/duckdb.py +236 -0
  62. perspective/widget/__init__.py +349 -0
  63. perspective/widget/viewer/__init__.py +15 -0
  64. perspective/widget/viewer/validate.py +22 -0
  65. perspective/widget/viewer/viewer.py +343 -0
  66. perspective/widget/viewer/viewer_traitlets.py +101 -0
  67. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/install.json +5 -0
  68. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/package.json +71 -0
  69. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js +2 -0
  70. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/253.5f5c9e80605aa4106a28.js.LICENSE.txt +25 -0
  71. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/523.c030af5d3c4f67ff83f6.js +1 -0
  72. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/remoteEntry.95a8ea1b44d96032833f.js +1 -0
  73. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/style.js +4 -0
  74. perspective_python-4.2.0.data/data/share/jupyter/labextensions/@perspective-dev/jupyterlab/static/third-party-licenses.json +16 -0
  75. perspective_python-4.2.0.dist-info/METADATA +27 -0
  76. perspective_python-4.2.0.dist-info/RECORD +79 -0
  77. perspective_python-4.2.0.dist-info/WHEEL +4 -0
  78. perspective_python-4.2.0.dist-info/licenses/LICENSE.md +193 -0
  79. 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,5 @@
1
+ {
2
+ "packageManager": "python",
3
+ "packageName": "perspective-python",
4
+ "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package perspective-python"
5
+ }
@@ -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
+ }