nova-trame 0.27.0__py3-none-any.whl → 1.0.0__py3-none-any.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.
@@ -129,7 +129,7 @@ class DataSelector(datagrid.VGrid):
129
129
  return get_server(None, client_type="vue3").state
130
130
 
131
131
  def create_ui(self, *args: Any, **kwargs: Any) -> None:
132
- with VBoxLayout(classes="nova-data-selector", height="100%") as self._layout:
132
+ with VBoxLayout(classes="nova-data-selector", stretch=True) as self._layout:
133
133
  with HBoxLayout(valign="center"):
134
134
  self._layout.filter = html.Div(classes="flex-1-1")
135
135
  with vuetify.VBtn(
@@ -138,9 +138,9 @@ class DataSelector(datagrid.VGrid):
138
138
  vuetify.VIcon("mdi-refresh")
139
139
  vuetify.VTooltip("Refresh Contents", activator="parent")
140
140
 
141
- with GridLayout(columns=2, classes="flex-1-0 h-0", valign="start"):
141
+ with GridLayout(columns=2, stretch=True):
142
142
  if isinstance(self._subdirectory, tuple) or not self._subdirectory:
143
- with html.Div(classes="d-flex flex-column h-100 overflow-hidden"):
143
+ with VBoxLayout(stretch=True):
144
144
  vuetify.VListSubheader("Available Directories", classes="flex-0-1 justify-center px-0")
145
145
  vuetify.VTreeview(
146
146
  v_if=(f"{self._directories_name}.length > 0",),
@@ -292,6 +292,8 @@ class NeutronDataSelector(DataSelector):
292
292
  projection=set_state_param(self.state, self._projection, projection)
293
293
  )
294
294
 
295
+ super()._setup_bindings()
296
+
295
297
  # These update methods notify the rest of the application when the component changes bound parameters.
296
298
  def update_facility(self, facility: str) -> None:
297
299
  self._vm.set_binding_parameters(
@@ -9,10 +9,11 @@ from mimetypes import types_map
9
9
  from pathlib import Path
10
10
  from threading import Thread
11
11
  from typing import Any, Optional
12
+ from warnings import warn
12
13
 
13
14
  import tornado
14
15
  from aiohttp import ClientSession, WSMsgType, web
15
- from matplotlib import get_data_path
16
+ from matplotlib import get_data_path, rcParams
16
17
  from matplotlib.backends.backend_webagg import FigureManagerWebAgg, new_figure_manager_given_figure # type: ignore
17
18
  from matplotlib.figure import Figure
18
19
  from trame.app import get_server
@@ -55,7 +56,10 @@ class _MPLApplication(tornado.web.Application):
55
56
  self.supports_binary = message["value"]
56
57
  else:
57
58
  manager = self.application.manager # type: ignore
58
- manager.handle_json(message)
59
+ try:
60
+ manager.handle_json(message)
61
+ except Exception:
62
+ manager.refresh_all()
59
63
 
60
64
  def send_json(self, content: Any) -> None:
61
65
  set_event_loop(self.application.loop) # type: ignore
@@ -69,6 +73,13 @@ class _MPLApplication(tornado.web.Application):
69
73
  data_uri = "data:image/png;base64," + blob.encode("base64").replace("\n", "")
70
74
  self.write_message(data_uri)
71
75
 
76
+ def write_message(self, *args: Any, **kwargs: Any) -> Any:
77
+ # We need the websocket to remain alive if a message fails to write.
78
+ try:
79
+ super().write_message(*args, **kwargs)
80
+ except Exception:
81
+ pass
82
+
72
83
  def __init__(self, figure: Figure) -> None:
73
84
  self.figure = figure
74
85
  self.manager = new_figure_manager_given_figure(id(figure), figure)
@@ -214,17 +225,22 @@ class MatplotlibFigure(matplotlib.Figure):
214
225
  -------
215
226
  None
216
227
  """ # noqa: E501
228
+ self._server = get_server(None, client_type="vue3")
217
229
  self._webagg = webagg
230
+ if "classes" in kwargs:
231
+ kwargs["classes"] += " flex-1-1"
232
+ else:
233
+ kwargs["classes"] = "flex-1-1"
218
234
  if webagg:
219
- self._port = MatplotlibFigure._get_free_port()
220
- if "classes" in kwargs:
221
- kwargs["classes"] += " nova-mpl"
222
- else:
223
- kwargs["classes"] = "nova-mpl"
235
+ if "id" in kwargs:
236
+ kwargs.pop("id")
237
+ warn("id parameter to MatplotlibFigure is ignored when webagg=True.", stacklevel=1)
224
238
 
225
- html.Div(id=f"nova_mpl_{self._port}", **kwargs)
239
+ self._port = MatplotlibFigure._get_free_port()
240
+ self._id = f"nova_mpl_{self._port}"
241
+ kwargs["classes"] += " nova-mpl"
226
242
 
227
- self._server = get_server(None, client_type="vue3")
243
+ html.Div(id=self._id, **kwargs)
228
244
 
229
245
  self._figure = figure
230
246
  self._initialized = False
@@ -236,8 +252,63 @@ class MatplotlibFigure(matplotlib.Figure):
236
252
  self.update()
237
253
  else:
238
254
  super().__init__(figure, **kwargs)
239
-
240
- def update(self, figure: Optional[Figure] = None) -> None:
255
+ self._id = self._key
256
+
257
+ self._query_selector = f"window.document.querySelector('#{self._id}')"
258
+ self._trigger = (
259
+ f"if ({self._query_selector} === null) {{ return; }}"
260
+ # webagg figures receive a fixed width and height. This blocks the flexbox scaling, so I temporarily hide
261
+ # the figure to allow the container to grow/shrink naturally in flexbox.
262
+ f"window.document.querySelectorAll('.nova-mpl').forEach((item) => {{ item.style.display = 'none'; }});"
263
+ f"const height = {self._query_selector}.parentNode.offsetHeight;"
264
+ f"const width = {self._query_selector}.parentNode.offsetWidth;"
265
+ # Revert the display value to allow the figure to render again.
266
+ f"window.document.querySelectorAll('.nova-mpl').forEach((item) => {{ item.style.display = ''; }});"
267
+ "window.trame.trigger("
268
+ f" '{self._id}_resize',"
269
+ f" [height, width]"
270
+ ");"
271
+ )
272
+ self._resize_figure = client.JSEval(exec=self._trigger).exec
273
+ self._resize_listener = client.JSEval(
274
+ exec=(
275
+ # ResizeObserver is necessary to detect changes in size unrelated to the viewport size such as when
276
+ # content is conditionally rendered that changes the size of the figure's container.
277
+ "const resizeObserver = new window.ResizeObserver(() => {"
278
+ f" window.delay_manager.debounce('{self._id}', function() {{ {self._trigger} }}, 500);"
279
+ "});"
280
+ f"resizeObserver.observe({self._query_selector}.parentNode);"
281
+ )
282
+ ).exec
283
+
284
+ @self._server.controller.trigger(f"{self._id}_resize")
285
+ def resize_figure(height: int, width: int) -> None:
286
+ if self._figure:
287
+ if self._webagg:
288
+ # Reserve space for the controls injected by webagg.
289
+ height -= 48
290
+ width -= 4
291
+
292
+ if height <= 0 or width <= 0:
293
+ return
294
+
295
+ if self._webagg:
296
+ # Webagg does not respect the Figure object's DPI.
297
+ dpi = rcParams["figure.dpi"]
298
+ else:
299
+ dpi = self._figure.get_dpi()
300
+ new_width = width / dpi
301
+ new_height = height / dpi
302
+ current_size = self._figure.get_size_inches()
303
+ if current_size[0] != new_width or current_size[1] != new_height:
304
+ self._figure.set_size_inches(new_width, new_height)
305
+
306
+ self.update(skip_resize=True)
307
+
308
+ client.ClientTriggers(mounted=self._resize_listener)
309
+ client.ClientTriggers(mounted=self._resize_figure)
310
+
311
+ def update(self, figure: Optional[Figure] = None, skip_resize: bool = False) -> None:
241
312
  if self._webagg:
242
313
  if figure:
243
314
  self._figure = figure
@@ -255,7 +326,10 @@ class MatplotlibFigure(matplotlib.Figure):
255
326
  else:
256
327
  super().update(figure)
257
328
 
258
- self._server.state.flush()
329
+ if not skip_resize and hasattr(self, "_resize_figure"):
330
+ self._resize_figure()
331
+ else:
332
+ self._server.state.flush()
259
333
 
260
334
  def _setup_figure_websocket(self) -> None:
261
335
  thread = Thread(target=self._mpl_run_ws_server, daemon=True)
@@ -1,6 +1,7 @@
1
1
  """Trame implementation of the GridLayout class."""
2
2
 
3
3
  from typing import Any, Optional, Union
4
+ from warnings import warn
4
5
 
5
6
  from trame.widgets import html
6
7
  from trame_client.widgets.core import AbstractElement
@@ -19,6 +20,7 @@ class GridLayout(html.Div):
19
20
  halign: Optional[str] = None,
20
21
  valign: Optional[str] = None,
21
22
  gap: Optional[Union[int, str]] = "0em",
23
+ stretch: bool = False,
22
24
  **kwargs: Any,
23
25
  ) -> None:
24
26
  """Constructor for GridLayout.
@@ -38,10 +40,14 @@ class GridLayout(html.Div):
38
40
  <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>`__ for available options.
39
41
  valign : optional[str]
40
42
  The vertical alignment of items in the grid. See `MDN
41
- <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options.
43
+ <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options. Note that this
44
+ parameter is ignored when stretch=True.
42
45
  gap : optional[str]
43
46
  The gap to place between items (works both horizontally and vertically). Can be any CSS gap value (e.g.
44
47
  "4px" or "0.25em"). Defaults to no gap between items.
48
+ stretch : optional[bool]
49
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
50
+ Defaults to False.
45
51
  kwargs : Any
46
52
  Additional keyword arguments to pass to html.Div.
47
53
 
@@ -69,6 +75,13 @@ class GridLayout(html.Div):
69
75
  if isinstance(classes, list):
70
76
  classes = " ".join(classes)
71
77
  classes += " d-grid"
78
+ if stretch:
79
+ if valign:
80
+ warn("Ignoring valign parameter to GridLayout since stretch=True.", stacklevel=1)
81
+ valign = "stretch"
82
+ classes += " flex-1-1 overflow-y-auto"
83
+ else:
84
+ classes += " flex-0-1"
72
85
 
73
86
  widget_style = self.get_root_styles(columns, height, width, halign, valign, gap)
74
87
  user_style = kwargs.pop("style", {})
@@ -18,6 +18,7 @@ class HBoxLayout(html.Div):
18
18
  valign: Optional[str] = None,
19
19
  gap: Optional[Union[int, str]] = "0em",
20
20
  vspace: Optional[Union[int, str]] = "0em",
21
+ stretch: bool = False,
21
22
  **kwargs: Any,
22
23
  ) -> None:
23
24
  """Constructor for HBoxLayout.
@@ -42,6 +43,9 @@ class HBoxLayout(html.Div):
42
43
  vspace : optional[str]
43
44
  The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
45
  gap between items.
46
+ stretch : optional[bool]
47
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
48
+ Defaults to False.
45
49
  kwargs : Any
46
50
  Additional keyword arguments to pass to html.Div.
47
51
 
@@ -60,6 +64,10 @@ class HBoxLayout(html.Div):
60
64
  if isinstance(classes, list):
61
65
  classes = " ".join(classes)
62
66
  classes += " d-flex flex-row"
67
+ if stretch:
68
+ classes += " flex-1-1 overflow-y-auto"
69
+ else:
70
+ classes += " flex-0-1"
63
71
 
64
72
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
73
  user_style = kwargs.pop("style", {})
@@ -18,6 +18,7 @@ class VBoxLayout(html.Div):
18
18
  valign: Optional[str] = None,
19
19
  gap: Optional[Union[int, str]] = "0em",
20
20
  vspace: Optional[Union[int, str]] = "0em",
21
+ stretch: bool = False,
21
22
  **kwargs: Any,
22
23
  ) -> None:
23
24
  """Constructor for VBoxLayout.
@@ -42,6 +43,9 @@ class VBoxLayout(html.Div):
42
43
  vspace : optional[str]
43
44
  The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
45
  gap between items.
46
+ stretch : optional[bool]
47
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
48
+ Defaults to False.
45
49
  kwargs : Any
46
50
  Additional keyword arguments to pass to html.Div.
47
51
 
@@ -60,6 +64,10 @@ class VBoxLayout(html.Div):
60
64
  if isinstance(classes, list):
61
65
  classes = " ".join(classes)
62
66
  classes += " d-flex flex-column"
67
+ if stretch:
68
+ classes += " flex-1-1 overflow-y-auto"
69
+ else:
70
+ classes += " flex-0-1"
63
71
 
64
72
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
73
  user_style = kwargs.pop("style", {})
@@ -70,12 +70,24 @@ html {
70
70
  }
71
71
 
72
72
  .v-window {
73
+ display: flex;
74
+ flex: 1 1;
73
75
  overflow-x: visible !important;
74
76
  overflow-y: visible !important;
77
+
78
+ .v-window__container {
79
+ flex: 1 1;
80
+
81
+ .v-window-item {
82
+ flex: 1 1;
83
+ }
84
+ }
75
85
  }
76
86
 
77
87
  @media only screen and (max-width: 959px) {
78
88
  .d-grid {
89
+ /* This forces all grid rows to have the same height. If one doesn't want this to happen, then they should use the box layouts. :) */
90
+ grid-auto-rows: 1fr;
79
91
  grid-template-columns: repeat(1, 1fr) !important;
80
92
  }
81
93
 
@@ -288,11 +288,13 @@ class ThemedApp:
288
288
 
289
289
  with vuetify.VMain(classes="align-stretch d-flex flex-column h-screen"):
290
290
  # [slot override example]
291
- layout.pre_content = vuetify.VSheet(classes="bg-background ")
291
+ layout.pre_content = vuetify.VSheet(classes="bg-background flex-0-1 mt-1 ")
292
292
  # [slot override example complete]
293
- with vuetify.VContainer(classes="flex-0-1 overflow-hidden pt-0 pb-0", fluid=True):
294
- layout.content = html.Div(classes="h-100 overflow-y-auto pb-1 ")
295
- layout.post_content = vuetify.VSheet(classes="bg-background ")
293
+ with vuetify.VContainer(classes="flex-1-1 overflow-hidden pt-0 pb-2", fluid=True):
294
+ layout.content = vuetify.VCard(
295
+ classes="d-flex flex-column flex-1-1 h-100 overflow-y-auto pa-1 "
296
+ )
297
+ layout.post_content = vuetify.VSheet(classes="bg-background flex-0-1 mb-1 ")
296
298
 
297
299
  with vuetify.VFooter(
298
300
  app=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nova-trame
3
- Version: 0.27.0
3
+ Version: 1.0.0
4
4
  Summary: A Python Package for injecting curated themes and custom components into Trame applications
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -38,7 +38,7 @@ Description-Content-Type: text/markdown
38
38
  nova-trame
39
39
  ==========
40
40
 
41
- `nova-trame` is a Python package for streamlining development of Trame applications used in the NOVA project.
41
+ `nova-trame` is a Python package for streamlining development of Trame applications used in the NOVA framework.
42
42
 
43
43
  You can install this package directly with
44
44
 
@@ -46,6 +46,13 @@ You can install this package directly with
46
46
  pip install nova-trame
47
47
  ```
48
48
 
49
+ Once installed, you can check that it's working by running the widget gallery we use for visually testing components available through NOVA and Trame. We use [Poetry](https://python-poetry.org/) internally and recommend it for running the gallery.
50
+
51
+ ```commandline
52
+ poetry install
53
+ poetry run app
54
+ ```
55
+
49
56
  A user guide, examples, and a full API for this package can be found at [https://nova-application-development.readthedocs.io/en/stable/](https://nova-application-development.readthedocs.io/projects/nova-trame/en/stable/).
50
57
 
51
58
  Developers: please read [this document](DEVELOPMENT.md)
@@ -7,32 +7,32 @@ nova/trame/model/ornl/neutron_data_selector.py,sha256=YMoNEpDKgjP_y18oYj-N9Ijkxt
7
7
  nova/trame/model/ornl/oncat_data_selector.py,sha256=3JEkWGMU-esWA9DUTglju9hEP9LyZ7EUXLj1yO5BIDs,4755
8
8
  nova/trame/model/remote_file_input.py,sha256=eAk7ZsFgNKcnpJ6KmOQDhiI6pPZpcrr1GMKkRLEWht8,4338
9
9
  nova/trame/view/components/__init__.py,sha256=60BeS69aOrFnkptjuD17rfPE1f4Z35iBH56TRmW5MW8,451
10
- nova/trame/view/components/data_selector.py,sha256=T5CFtWPio3YwiPvPEBrWn7vgRo-3l0GqdGKzonc_cwc,14970
10
+ nova/trame/view/components/data_selector.py,sha256=ByZ1RTyJRfmHNfN-nFi_Ihljo0yjbyfa_El-jHl9oyM,14907
11
11
  nova/trame/view/components/execution_buttons.py,sha256=Br6uAmE5bY67TTYc5ZTHECNJ_RJqKmv17HAKPpQtbeg,4576
12
12
  nova/trame/view/components/file_upload.py,sha256=WOaFXeNNwN0DYZJr-W6vWdBiTpr7m-lq3WKJaHmeMe8,4560
13
13
  nova/trame/view/components/input_field.py,sha256=xzCmNEoB4ljGx99-gGgTV0UwriwtS8ce22zPA4QneZw,17372
14
14
  nova/trame/view/components/ornl/__init__.py,sha256=HnxzzSsxw0vQSDCVFfWsAxx1n3HnU37LMuQkfiewmSU,90
15
- nova/trame/view/components/ornl/neutron_data_selector.py,sha256=6X4sz54DaVYfW8LYOazpA-paGy1mc4gLoka--34GMdE,16762
15
+ nova/trame/view/components/ornl/neutron_data_selector.py,sha256=3IxEYM3wK7RskxbjDG94JeWBCEWXBeF3xBDWt3Bh1OU,16797
16
16
  nova/trame/view/components/progress_bar.py,sha256=zhbJwPy_HPQ8YL-ISN8sCRUQ7qY6qqo9wiV59BmvL8I,3038
17
17
  nova/trame/view/components/remote_file_input.py,sha256=mcz_bmI2rD8gdmIOKLhlzfj-XoWBwC99T9ZgQORaKqE,14674
18
18
  nova/trame/view/components/tool_outputs.py,sha256=IbYV4VjrkWAE354Bh5KH76SPsxGLIkOXChijS4-ce_Y,2408
19
19
  nova/trame/view/components/visualization/__init__.py,sha256=reqkkbhD5uSksHHlhVMy1qNUCwSekS5HlXk6wCREYxU,152
20
20
  nova/trame/view/components/visualization/interactive_2d_plot.py,sha256=z2s1janxAclpMEdDJk3z-CQ6r3KPNoR_SXPx9ppWnuQ,3481
21
- nova/trame/view/components/visualization/matplotlib_figure.py,sha256=q0HLaaLFjM3_V1oUk-VBHWvokFY6AQZzmnMcynTroik,12488
21
+ nova/trame/view/components/visualization/matplotlib_figure.py,sha256=8JgbF6elZC8EFZn-c2mLqGSyg0Lb4NLVAKJVSBb9-5g,16010
22
22
  nova/trame/view/layouts/__init__.py,sha256=cMrlB5YMUoK8EGB83b34UU0kPTVrH8AxsYvKRtpUNEc,141
23
- nova/trame/view/layouts/grid.py,sha256=vqEX-jghs6j9_sVtijdRH7uhlD9loWNi90k2qgg4Dhg,5534
24
- nova/trame/view/layouts/hbox.py,sha256=cdwnGk93ec6dXAeEamRQx1WTj5T7Ygsmsy0xz130tWM,3519
23
+ nova/trame/view/layouts/grid.py,sha256=DU5u5JTE0ulzCaJsEWyTenBH9lOQD7mtoC6RZXxDTPE,6110
24
+ nova/trame/view/layouts/hbox.py,sha256=w6ow7Qzmq4slODz_9f7kEigCVPE2PhUmPODedYH34f4,3850
25
25
  nova/trame/view/layouts/utils.py,sha256=Hg34VQWTG3yHBsgNvmfatR4J-uL3cko7UxSJpT-h3JI,376
26
- nova/trame/view/layouts/vbox.py,sha256=XRV14e32MY1HWc9FTVTv1vOatWWbhLMd0lYwZP-isTg,3520
26
+ nova/trame/view/layouts/vbox.py,sha256=Kkci79zDKF6qNH4HeDPYquJcixXx3BS63NVmS3FlOiw,3851
27
27
  nova/trame/view/theme/__init__.py,sha256=70_marDlTigIcPEOGiJb2JTs-8b2sGM5SlY7XBPtBDM,54
28
- nova/trame/view/theme/assets/core_style.scss,sha256=3-3qMc5gpaDhfuVWAF_psBH5alxwiuK-hPGhVgi2cW0,4335
28
+ nova/trame/view/theme/assets/core_style.scss,sha256=Bf7ajLULXPoJWH2KZk47VsAsMMC7DOYBjG_54l0qsjs,4652
29
29
  nova/trame/view/theme/assets/favicon.png,sha256=Xbp1nUmhcBDeObjsebEbEAraPDZ_M163M_ZLtm5AbQc,1927
30
30
  nova/trame/view/theme/assets/js/delay_manager.js,sha256=BN4OL88QsyZG4XQ1sTorHpN1rwD4GnWoVKHvl5F5ydo,776
31
31
  nova/trame/view/theme/assets/js/lodash.min.js,sha256=KCyAYJ-fsqtp_HMwbjhy6IKjlA5lrVrtWt1JdMsC57k,73016
32
32
  nova/trame/view/theme/assets/js/revo_grid.js,sha256=73v-GP4IUIg8OgMnRCoHB6ERFU18nx0VYaEecV_7u-o,5695
33
33
  nova/trame/view/theme/assets/vuetify_config.json,sha256=a0FSgpLYWGFlRGSMhMq61MyDFBEBwvz55G4qjkM08cs,5627
34
34
  nova/trame/view/theme/exit_button.py,sha256=Kqv1GVJZGrSsj6_JFjGU3vm3iNuMolLC2T1x2IsdmV0,3094
35
- nova/trame/view/theme/theme.py,sha256=bwKzMkGcqoIx_H70FOYIwG3QYQ6tya0dXJaUoxGWQn0,14575
35
+ nova/trame/view/theme/theme.py,sha256=DMA53DYUS6qpLkqAlfEMOuNlyNgHD13uBMfSeLytGyw,14698
36
36
  nova/trame/view/utilities/local_storage.py,sha256=vD8f2VZIpxhIKjZwEaD7siiPCTZO4cw9AfhwdawwYLY,3218
37
37
  nova/trame/view_model/data_selector.py,sha256=jAtq5hpohQ6YiLBbgLJfNUzWZBpN2bjCG_c_FCJu2ns,3186
38
38
  nova/trame/view_model/execution_buttons.py,sha256=MfKSp95D92EqpD48C15cBo6dLO0Yld4FeRZMJNxJf7Y,3551
@@ -40,8 +40,8 @@ nova/trame/view_model/ornl/neutron_data_selector.py,sha256=PIKQyzcHpwu81DNk3d8Af
40
40
  nova/trame/view_model/progress_bar.py,sha256=6AUKHF3hfzbdsHqNEnmHRgDcBKY5TT8ywDx9S6ovnsc,2854
41
41
  nova/trame/view_model/remote_file_input.py,sha256=zWOflmCDJYYR_pacHphwzricV667GSRokh-mlxpBAOo,3646
42
42
  nova/trame/view_model/tool_outputs.py,sha256=ev6LY7fJ0H2xAJn9f5ww28c8Kpom2SYc2FbvFcoN4zg,829
43
- nova_trame-0.27.0.dist-info/METADATA,sha256=pj-cjaC_mkFmqwPXwbOyDi0R8UdhikVQKD4jf_H0Kjc,1796
44
- nova_trame-0.27.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
45
- nova_trame-0.27.0.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
46
- nova_trame-0.27.0.dist-info/licenses/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
47
- nova_trame-0.27.0.dist-info/RECORD,,
43
+ nova_trame-1.0.0.dist-info/METADATA,sha256=nqvFzLDJCyIuPqZmNK9rIXR6x0nfjIRt0cmU17zDFXI,2096
44
+ nova_trame-1.0.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
45
+ nova_trame-1.0.0.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
46
+ nova_trame-1.0.0.dist-info/licenses/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
47
+ nova_trame-1.0.0.dist-info/RECORD,,