syd 1.0.0__py3-none-any.whl → 1.0.2__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.
syd/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from typing import Callable, Optional
2
2
  from .viewer import Viewer
3
3
 
4
- __version__ = "1.0.0"
4
+ __version__ = "1.0.2"
5
5
 
6
6
 
7
7
  def make_viewer(plot_func: Optional[Callable] = None):
@@ -1,5 +1,7 @@
1
1
  from typing import Literal, Optional
2
2
  import warnings
3
+ import threading
4
+ from contextlib import contextmanager
3
5
  import ipywidgets as widgets
4
6
  from IPython.display import display
5
7
  import matplotlib as mpl
@@ -39,6 +41,7 @@ class NotebookDeployer:
39
41
  controls_width_percent: int = 20,
40
42
  continuous: bool = False,
41
43
  suppress_warnings: bool = True,
44
+ update_threshold: float = 1.0,
42
45
  ):
43
46
  self.viewer = viewer
44
47
  self.components: dict[str, BaseWidget] = {}
@@ -56,12 +59,58 @@ class NotebookDeployer:
56
59
  "The behavior of the viewer will almost definitely not work as expected!"
57
60
  )
58
61
  self._last_figure = None
62
+ self._update_event = threading.Event()
63
+ self.update_threshold = update_threshold
64
+ self._slow_loading_figure = None
65
+ self._display_lock = threading.Lock() # Lock for synchronizing display updates
66
+
67
+ def _show_slow_loading(self):
68
+ if self.backend_type == "inline":
69
+ if not self._update_event.wait(self.update_threshold):
70
+ if self._slow_loading_figure is None:
71
+ fig = plt.figure()
72
+ ax = fig.add_subplot(111)
73
+ ax.text(
74
+ 0.5,
75
+ 0.5,
76
+ "waiting for next figure...",
77
+ ha="center",
78
+ va="center",
79
+ fontsize=12,
80
+ weight="bold",
81
+ color="black",
82
+ )
83
+ ax.axis("off")
84
+ self._slow_loading_figure = fig
85
+ if not self._showing_new_figure:
86
+ self._display_figure(self._slow_loading_figure, store_figure=False)
87
+ self._showing_slow_loading_figure = True
88
+
89
+ @contextmanager
90
+ def _perform_update(self):
91
+ self._updating = True
92
+ self._showing_new_figure = False
93
+ self._showing_slow_loading_figure = False
94
+ self._update_event.clear()
95
+
96
+ thread = threading.Thread(target=self._show_slow_loading, daemon=True)
97
+ thread.start()
98
+
99
+ try:
100
+ yield
101
+ finally:
102
+ self._updating = False
103
+ self._update_event.set()
104
+ thread.join()
105
+ if self._showing_slow_loading_figure:
106
+ self._display_figure(self._last_figure)
107
+ self._update_status("Ready!")
59
108
 
60
109
  def deploy(self) -> None:
61
110
  """Deploy the viewer."""
111
+ self.backend_type = get_backend_type()
62
112
  self.build_components()
63
113
  self.build_layout()
64
- self.backend_type = get_backend_type()
65
114
  display(self.layout)
66
115
  self.update_plot()
67
116
 
@@ -80,6 +129,10 @@ class NotebookDeployer:
80
129
 
81
130
  # Controls width slider for horizontal layouts
82
131
  self.controls = {}
132
+ self.controls["status"] = widgets.HTML(
133
+ value="<b>Syd Controls</b>",
134
+ layout=widgets.Layout(width="95%"),
135
+ )
83
136
  if self.controls_position in ["left", "right"]:
84
137
  self.controls["controls_width"] = widgets.IntSlider(
85
138
  value=self.controls_width_percent,
@@ -90,6 +143,15 @@ class NotebookDeployer:
90
143
  layout=widgets.Layout(width="95%"),
91
144
  style={"description_width": "initial"},
92
145
  )
146
+ if self.backend_type == "inline":
147
+ self.controls["update_threshold"] = widgets.FloatSlider(
148
+ value=self.update_threshold,
149
+ min=0.1,
150
+ max=10.0,
151
+ description="Update Threshold",
152
+ layout=widgets.Layout(width="95%"),
153
+ style={"description_width": "initial"},
154
+ )
93
155
 
94
156
  # Create parameter controls section
95
157
  param_box = widgets.VBox(
@@ -102,7 +164,7 @@ class NotebookDeployer:
102
164
  if self.controls_position in ["left", "right"]:
103
165
  # Create layout controls section if horizontal (might include for vertical later when we have more permanent controls...)
104
166
  layout_box = widgets.VBox(
105
- [widgets.HTML("<b>Syd Controls</b>")] + list(self.controls.values()),
167
+ list(self.controls.values()),
106
168
  layout=widgets.Layout(margin="10px 0px"),
107
169
  )
108
170
 
@@ -112,6 +174,11 @@ class NotebookDeployer:
112
174
  self._handle_container_width_change, names="value"
113
175
  )
114
176
 
177
+ if "update_threshold" in self.controls:
178
+ self.controls["update_threshold"].observe(
179
+ self._handle_update_threshold_change, names="value"
180
+ )
181
+
115
182
  widgets_elements = [param_box, layout_box]
116
183
  else:
117
184
  widgets_elements = [param_box]
@@ -154,6 +221,8 @@ class NotebookDeployer:
154
221
  else:
155
222
  self.layout = widgets.VBox([self.widgets_container, self.plot_container])
156
223
 
224
+ self._update_status("Ready!")
225
+
157
226
  def handle_component_engagement(self, name: str) -> None:
158
227
  """Handle engagement with an interactive component."""
159
228
  if self._updating:
@@ -164,9 +233,8 @@ class NotebookDeployer:
164
233
  )
165
234
  return
166
235
 
167
- try:
168
- self._updating = True
169
-
236
+ with self._perform_update():
237
+ self._update_status(f"Updating {name}")
170
238
  # Optionally suppress warnings during parameter updates
171
239
  with warnings.catch_warnings():
172
240
  if self.suppress_warnings:
@@ -188,9 +256,6 @@ class NotebookDeployer:
188
256
  # Update the plot
189
257
  self.update_plot()
190
258
 
191
- finally:
192
- self._updating = False
193
-
194
259
  def sync_components_with_state(self, exclude: Optional[str] = None) -> None:
195
260
  """Sync component values with viewer state."""
196
261
  for name, parameter in self.viewer.parameters.items():
@@ -211,25 +276,32 @@ class NotebookDeployer:
211
276
  # Update components if plot function updated a parameter
212
277
  self.sync_components_with_state()
213
278
 
214
- # Close the last figure if it exists to keep matplotlib clean
215
- if self._last_figure is not None:
216
- plt.close(self._last_figure)
279
+ self._display_figure(figure)
280
+
281
+ self._showing_new_figure = True
217
282
 
218
- self.plot_output.clear_output(wait=True)
219
- with self.plot_output:
220
- if self.backend_type == "inline":
221
- display(figure)
283
+ def _display_figure(self, figure: plt.Figure, store_figure: bool = True) -> None:
284
+ with self._display_lock:
285
+ # Close the last figure if it exists to keep matplotlib clean
286
+ if self._last_figure is not None:
287
+ plt.close(self._last_figure)
222
288
 
223
- # Also required to make sure a second figure window isn't opened
224
- plt.close(figure)
289
+ self.plot_output.clear_output(wait=True)
290
+ with self.plot_output:
291
+ if self.backend_type == "inline":
292
+ display(figure)
225
293
 
226
- elif self.backend_type == "widget":
227
- display(figure.canvas)
294
+ # Also required to make sure a second figure window isn't opened
295
+ plt.close(figure)
228
296
 
229
- else:
230
- raise ValueError(f"Unsupported backend type: {self.backend_type}")
297
+ elif self.backend_type == "widget":
298
+ display(figure.canvas)
231
299
 
232
- self._last_figure = figure
300
+ else:
301
+ raise ValueError(f"Unsupported backend type: {self.backend_type}")
302
+
303
+ if store_figure:
304
+ self._last_figure = figure
233
305
 
234
306
  def _handle_container_width_change(self, _) -> None:
235
307
  """Handle changes to container width proportions."""
@@ -239,3 +311,15 @@ class NotebookDeployer:
239
311
  # Update container widths
240
312
  self.widgets_container.layout.width = f"{width_percent}%"
241
313
  self.plot_container.layout.width = f"{100 - width_percent}%"
314
+
315
+ def _handle_update_threshold_change(self, _) -> None:
316
+ """Handle changes to update threshold."""
317
+ self.update_threshold = self.controls["update_threshold"].value
318
+
319
+ def _update_status(self, status: str) -> None:
320
+ """Update the status text."""
321
+ value = "<b>Syd Controls</b> "
322
+ value += "<span style='background-color: #e0e0e0; color: #000; padding: 2px 6px; border-radius: 4px; font-size: 90%;'>"
323
+ value += f"Status: {status}"
324
+ value += "</span>"
325
+ self.controls["status"].value = value
syd/viewer.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import List, Any, Callable, Dict, Tuple, Union, Optional
1
+ from typing import List, Any, Callable, Dict, Tuple, Union, Optional, Literal
2
2
  from functools import wraps, partial
3
3
  import inspect
4
4
  from contextlib import contextmanager
@@ -212,6 +212,54 @@ class Viewer:
212
212
  """Set the plot method for the viewer"""
213
213
  self.plot = self._prepare_function(func, context="Setting plot:")
214
214
 
215
+ def show(
216
+ self,
217
+ controls_position: Literal["left", "top", "right", "bottom"] = "left",
218
+ controls_width_percent: int = 20,
219
+ continuous: bool = False,
220
+ suppress_warnings: bool = True,
221
+ update_threshold: float = 1.0,
222
+ ):
223
+ """Show the viewer in a notebook
224
+
225
+ Same as deploy(env="notebook") except it doesn't return the viewer object.
226
+ """
227
+ _ = self.deploy(
228
+ env="notebook",
229
+ controls_position=controls_position,
230
+ controls_width_percent=controls_width_percent,
231
+ continuous=continuous,
232
+ suppress_warnings=suppress_warnings,
233
+ update_threshold=update_threshold,
234
+ )
235
+
236
+ def share(
237
+ self,
238
+ controls_position: str = "left",
239
+ fig_dpi: int = 300,
240
+ controls_width_percent: int = 20,
241
+ suppress_warnings: bool = True,
242
+ debug: bool = False,
243
+ host: str = "127.0.0.1",
244
+ port: Optional[int] = None,
245
+ open_browser: bool = True,
246
+ ):
247
+ """Share the viewer on a web browser using Flask
248
+
249
+ Same as deploy(env="browser") except it doesn't return the viewer object.
250
+ """
251
+ _ = self.deploy(
252
+ env="browser",
253
+ controls_position=controls_position,
254
+ fig_dpi=fig_dpi,
255
+ controls_width_percent=controls_width_percent,
256
+ suppress_warnings=suppress_warnings,
257
+ debug=debug,
258
+ host=host,
259
+ port=port,
260
+ open_browser=open_browser,
261
+ )
262
+
215
263
  def deploy(self, env: str = "notebook", **kwargs):
216
264
  """Deploy the app in a notebook or standalone environment"""
217
265
  env = env.lower()
@@ -223,7 +271,7 @@ class Viewer:
223
271
  deployer.deploy()
224
272
  return self
225
273
 
226
- elif env == "browser" or env == "flask":
274
+ elif env == "browser":
227
275
  # On demand import because the deployers need to import the viewer
228
276
  from .flask_deployment.deployer import FlaskDeployer
229
277
 
@@ -238,7 +286,7 @@ class Viewer:
238
286
 
239
287
  else:
240
288
  raise ValueError(
241
- f"Unsupported environment: {env}, only 'notebook', 'flask'/'browser' are supported right now."
289
+ f"Unsupported environment: {env}, only 'notebook', 'browser' are supported right now."
242
290
  )
243
291
 
244
292
  @contextmanager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syd
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: A Python package for making GUIs for data science easy.
5
5
  Project-URL: Homepage, https://github.com/landoskape/syd
6
6
  Author-email: Andrew Landau <andrew+tyler+landau+getridofthisanddtheplusses@gmail.com>
@@ -37,13 +37,17 @@ Description-Content-Type: text/markdown
37
37
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
38
38
 
39
39
 
40
+ <div>
41
+ <img src="./docs/assets/syd-logo-white.png" alt="Syd" width="350" align="right"/>
42
+ </div>
43
+
40
44
  A package to help you share your data!
41
45
 
42
46
  Have you ever wanted to look through all your data really quickly interactively? Of course you have. Mo data mo problems, but only if you don't know what to do with it. And that's why Syd stands for show your data!
43
47
 
44
48
  Syd is a system for creating a data viewing GUI that you can view in a jupyter notebook or in a web browser. And guess what? Since it can open in a web browser, you can even open it on any other computer on your local network! For example, your PI's computer. Gone are the days of single random examples that they make infinitely stubborn conclusions about. Now, you can look at all the examples, quickly and easily, on their computer. And that's why Syd stands for share your data!
45
49
 
46
- Okay, so what is it? Syd is an automated system to convert some basic python plotting code into an interactive GUI. This means you only have to think about _**what**_ you want to plot and _**which**_ parameters you want to be interactive. Syd handles all the behind-the-scenes action required to make an interface. And do you know what that means? It means you get to spend your time _thinking_ about your data, rather than writing code to look at it. And that's why Syd stands for Science, Yes! Dayummmm!
50
+ Okay, so what is it? Syd is an automated system to convert some basic python plotting code into an interactive GUI. This means you only have to think about what you want to _**plot**_ and which _**parameters**_ you want to be interactive. Syd handles all the behind-the-scenes action required to make an interface. And guess what? That means you get to spend your time _**thinking**_ about your data, rather than writing code to look at it. And that's why Syd stands for Science, Yes! Dayummmm!
47
51
 
48
52
  ## Installation
49
53
  It's easy, just use pip install. The dependencies are light so it should work in most environments.
@@ -56,27 +60,31 @@ The full documentation is available at [shareyourdata.readthedocs.io](https://sh
56
60
 
57
61
  ## Quick Start
58
62
  This is an example of a sine wave viewer which is about as simple as it gets. You can choose which env to use - if you use ``env="notebook"`` then the GUI will deploy as the output of a jupyter cell (this only works in jupyter!). If you use ``env="browser"`` then the GUI will open a page in your default web browser and you can interact with the data there (works in jupyter notebooks and also from python scripts!).
63
+
59
64
  ```python
60
- import matplotlib.pyplot as plt
61
65
  import numpy as np
66
+ import matplotlib.pyplot as plt
62
67
  from syd import make_viewer
63
- def plot(viewer, state):
64
- fig, ax = plt.subplots()
65
- x = np.linspace(0, 10, 1000)
66
- y = state['amplitude'] * np.sin(state['frequency'] * x)
67
- ax.plot(x, y)
68
+ def plot(state):
69
+ # Here's a simple plot function that plots a sine wave
70
+ fig = plt.figure()
71
+ t = np.linspace(0, 2 * np.pi, 1000)
72
+ ax = plt.gca()
73
+ ax.plot(t, state["amplitude"] * np.sin(state["frequency"] * t), color=state["color"])
68
74
  return fig
69
-
70
- viewer = make_viewer()
71
- viewer.set_plot(plot)
72
- viewer.add_float('amplitude', value=1.0, min=0, max=2)
73
- viewer.add_float('frequency', value=1.0, min=0.1, max=5)
75
+
76
+ viewer = make_viewer(plot)
77
+ viewer.add_float("amplitude", value=1.0, min=0.1, max=2.0)
78
+ viewer.add_float("frequency", value=1.0, min=0.1, max=5.0)
79
+ viewer.add_selection("color", value="red", options=["red", "blue", "green", "black"])
74
80
 
75
81
  # env = "browser" # for viewing in a web browser
76
82
  env = "notebook" # for viewing within a jupyter notebook
77
- viewer.deploy(env=env)
83
+ viewer.show()
78
84
  ```
79
85
 
86
+ ![Quick Start Viewer](./docs/assets/viewer_screenshots/readme_example_gif.gif)
87
+
80
88
  ### More Examples
81
89
  We have several examples of more complex viewers with detailed explanations in the comments. Here are the links and descriptions to each of them:
82
90
 
@@ -90,7 +98,7 @@ We have several examples of more complex viewers with detailed explanations in t
90
98
 
91
99
 
92
100
  ### Data loading
93
- Thinking about how to get data into a Syd viewer can be non-intuitive. For some examples that showcase different ways to get your data into a Syd viewer, check out the [data loading example](examples/3-data_loading.ipynb). Or, if you just want a quick example, check this out:
101
+ Thinking about how to get data into a Syd viewer can be non-intuitive. For some examples that showcase different ways to get your data into a Syd viewer, check out the [data loading example](examples/3-data_loading.ipynb). Or, if you just want a quick and fast example, check this one out:
94
102
  ```python
95
103
  import numpy as np
96
104
  from matplotlib import pyplot as plt
@@ -111,15 +119,15 @@ def plot(state):
111
119
  # Since plot "knows" about the data variable, all you need to do is pass the plot
112
120
  # function to the syd viewer and it'll be able to access the data once deployed!
113
121
  viewer = make_viewer(plot)
114
- viewer.deploy(env="browser")
122
+ viewer.show()
115
123
  ```
116
124
 
117
125
  ### Handling Hierarchical Callbacks
118
- Syd dramatically reduces the amount of work you need to do to build a GUI for viewing your data. However, it can still be a bit complicated to think about callbacks. Below is a quick demonstration, to try it yourself, check out the full example [here](examples/4-hierarchical_callbacks.ipynb).
126
+ Syd dramatically reduces the amount of work you need to do to build a GUI for viewing your data. However, it can still be a bit complicated to think about callbacks. Below is a quick demonstration. To try it yourself, check out the full example [here](examples/4-hierarchical_callbacks.ipynb) or open it in colab [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/landoskape/syd/blob/main/examples/4-hierarchical_callbacks.ipynb).
119
127
 
120
- For example, suppose your dataset is composed of electrophysiology recordings from 3 mice, where each mouse has a different number of sesssions, and each session has a different number of neurons. You want to build a viewer to choose the mouse, then choose the session, and then view a particular neuron from within that session. But the viewer will break if you try to index to session 5 for mouse 2 but mouse 2 only has 4 sessions!
128
+ For example, suppose your dataset is composed of electrophysiology recordings from 3 mice, where each mouse has a different number of sesssions, and each session has a different number of neurons. You want to build a viewer to view a particular neuron from a particular session from a particular mouse. But the viewer will break if you try to index to session 5 for mouse 2 when mouse 2 has less than 5 sessions!
121
129
 
122
- This is where hierarchical callbacks come in. There's a straightforward pattern to handling this kind of situation that you can follow. You can write a callback for each **level** of the hierarchy. Then, each callback can call the next callback in the hierarchy. It looks like this:
130
+ This is where hierarchical callbacks come in. There's a straightforward pattern to handling this kind of situation that you can follow. You can write a callback for each **level** of the hierarchy. Then, each callback can **update** the state and call the next callback in the hierarchy once it's finished. It looks like this:
123
131
  ```python
124
132
  import numpy as np
125
133
  from syd import Viewer # Much easier to build a Viewer class for hierarchical callbacks
@@ -130,19 +138,22 @@ class MouseViewer(Viewer):
130
138
 
131
139
  self.add_selection("mouse", options=list(mice_names))
132
140
 
133
- # We don't know how many sessions or neurons to pick from yet!
141
+ # We don't know how many sessions or neurons to pick from yet,
142
+ # so just set the max to 1 for now.
134
143
  self.add_integer("session", min=0, max=1)
135
144
  self.add_integer("neuron", min=0, max=1)
136
145
 
137
- # Any time the mouse changes, update the sessions to pick from
146
+ # Any time the mouse changes, update the sessions to pick from!
138
147
  self.on_change("mouse", self.update_mouse)
139
148
 
140
- # Any time the session changes, update the neurons to pick from
149
+ # Any time the session changes, update the neurons to pick from!
141
150
  self.on_change("session", self.update_session)
142
151
 
143
152
  # Since we built callbacks for setting the range of the session
144
- # and neuron parameters, we can use them here!
145
- # To get the state, we can use self.state, which is the current
153
+ # and neuron parameters, we can use them here so the viewer is
154
+ # fully ready and up to date.
155
+
156
+ # To get the state, use self.state, which is the current
146
157
  # state of the viewer (in the init function, it'll just be the
147
158
  # default value for each parameter you've added already).
148
159
  self.update_mouse(self.state)
@@ -155,9 +166,13 @@ class MouseViewer(Viewer):
155
166
  self.update_integer("session", max=num_sessions - 1)
156
167
 
157
168
  # Now we need to update the neurons to choose from ....
158
- # But! Updating the session parameter might trigger a change to the
159
- # session value. So, instead of using the state dictionary that was
160
- # passed into the function, we can get the ~NEW~ state dictionary like this:
169
+
170
+ # But! Updating the session parameter's max value might trigger a change
171
+ # to the current session value. This ~won't be reflected~ in the state
172
+ # dictionary that was passed to this function.
173
+
174
+ # So, we need to load the ~NEW~ state dictionary, which is always
175
+ # accessible as self.state (or viewer.state if you're not using a class).
161
176
  new_state = self.state
162
177
 
163
178
  # Then perform the session update callback!
@@ -178,7 +193,7 @@ class MouseViewer(Viewer):
178
193
 
179
194
  # Now we can create a viewer and deploy it
180
195
  viewer = MouseViewer(["Mouse 1", "Mouse 2", "Mouse 3"])
181
- viewer.deploy(env="browser")
196
+ viewer.show()
182
197
  ```
183
198
 
184
199
  ## License
@@ -197,8 +212,11 @@ Contributions are welcome! Here's how you can help:
197
212
  6. Push to the branch (`git push origin feature/amazing-feature`)
198
213
  7. Open a Pull Request online
199
214
 
200
- Please make sure to update tests as appropriate and adhere to the existing coding style (black, line-length=88, other style guidelines not capture by black, generally following pep8 guidelines).
201
-
215
+ Please make sure to update tests as appropriate and adhere to the existing coding style (black, line-length=88, other style guidelines not capture by black, generally following pep8 guidelines). Try to make the code coverage report improve or stay the same rather than decrease (right now the deployment system isn't covered by tests). I don't have any precommit hooks or anything so you're responsible for checking this yourself. You can process the code with black as follows:
216
+ ```bash
217
+ pip install black
218
+ black . # from the root directory of the repo
219
+ ```
202
220
 
203
221
  ## To-Do List
204
222
  - Layout controls
@@ -208,12 +226,6 @@ Please make sure to update tests as appropriate and adhere to the existing codin
208
226
  - [ ] Add a "freeze" button that allows the user to update state variables without updating the plot until unfreezing
209
227
  - [ ] Add a window for capturing any error messages that might be thrown by the plot function. Maybe we could have a little interface for looking at each one (up to a point) and the user could press a button to throw an error for the traceback.
210
228
  - [ ] Consider "app_deployed" context for each deployer...
211
- - [ ] Consider adding a step to the integer parameters...
212
- - Idea for figure management:
213
- - [ ] We could make fig=?, ax=? arguments optional for the plot function and add a
214
- "recycle_figure: bool = False" flag be part of the deploy API. This way, an
215
- advanced user that wants snappy responsivity or complex figure management can
216
- do so, but the default is for the user to generate a new figure object each time.
217
229
  - Export options:
218
230
  - [ ] Export lite: export the viewer as a HTML/Java package that contains an incomplete set of renderings of figures -- using a certain set of parameters.
219
231
  - [ ] Export full: export the viewer in a way that contains the data to give full functionality.
@@ -1,7 +1,7 @@
1
- syd/__init__.py,sha256=LSf7L9CZ7WVB6qb88vX6YgnCffcQLsDdhIggNMEGd10,250
1
+ syd/__init__.py,sha256=X6Ij4JC9wWFTejHeTRAhKNze3H6WZNVHHRehRq2jmlQ,250
2
2
  syd/parameters.py,sha256=dlnYOVsi1CDtC2toVECf0kNBRipVrtUjr6XVX86b5MA,42886
3
3
  syd/support.py,sha256=7wztPMaL750opyBDnaYYRVyBR5QUJtVspDzQWpu50rk,6106
4
- syd/viewer.py,sha256=UYDfH9TNds0CiC3vThINLrMNZE8ikSFqJHgjM8yMD94,49323
4
+ syd/viewer.py,sha256=I2uWCup3AZkF-CZ4Ux_glTZWKrPcqERAsO3HqXziomg,50846
5
5
  syd/flask_deployment/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  syd/flask_deployment/deployer.py,sha256=w-zuXX1PCnWRa_VCevbQ7yqMTNH5x3Dri-sQQXOF1sM,25110
7
7
  syd/flask_deployment/testing_principles.md,sha256=GyULM97sDeie8h3tSPoduOckdMNGyWuwm1RdHo5jzK0,10130
@@ -11,9 +11,9 @@ syd/flask_deployment/static/js/viewer.js,sha256=kSY24VGjlQLe-jtPOEU1nE7U0ALC_ZaV
11
11
  syd/flask_deployment/templates/__init__.py,sha256=ieWE8NKR-APw7h4Ge0ooZGk6wZrneSSs_1cMyTPbQSA,65
12
12
  syd/flask_deployment/templates/index.html,sha256=fr1g9IOwNttULhQCIcw_fo0sNpmdgznSGfPStQllR_E,1594
13
13
  syd/notebook_deployment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- syd/notebook_deployment/deployer.py,sha256=LcKq0Jy_znrVFF7S0uBJrQUWf1hB-NKmDYiq1OG0Jr8,8930
14
+ syd/notebook_deployment/deployer.py,sha256=sf3f9STRXpU1ac-OGENYv1g5yBpUaiIcREBKtKWvIlA,12324
15
15
  syd/notebook_deployment/widgets.py,sha256=UbkasRf8wY9beUwpwJYjv9X0Lus3DvgAEIORHwaC-zA,20058
16
- syd-1.0.0.dist-info/METADATA,sha256=xEpq6sJo2eE6uMZDCwgLwS1yMQd1ZRoz--SWDE4t0F0,13043
17
- syd-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- syd-1.0.0.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
19
- syd-1.0.0.dist-info/RECORD,,
16
+ syd-1.0.2.dist-info/METADATA,sha256=NtVVyB_wKzL9lDzjVgOkz_D1bcSp_6MiJVv9uDBUi2k,13741
17
+ syd-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ syd-1.0.2.dist-info/licenses/LICENSE,sha256=YF6QR6Vjxcg5b_sYIyqkME7FZYau5TfEUGTG-0JeRK0,35129
19
+ syd-1.0.2.dist-info/RECORD,,
File without changes