supervisely 6.73.288__py3-none-any.whl → 6.73.289__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.
@@ -4,17 +4,13 @@ import asyncio
4
4
  import re
5
5
  from abc import ABC, abstractmethod
6
6
  from datetime import datetime
7
- from typing import Any, Callable, Dict, List, Literal, Optional, Union
7
+ from typing import Any, Callable, List, Literal, Optional
8
8
  from uuid import uuid4
9
9
 
10
10
  from fastapi.responses import HTMLResponse
11
11
  from pydantic import BaseModel
12
12
 
13
- from supervisely._utils import is_production
14
- from supervisely.api.api import Api
15
13
  from supervisely.app.widgets import Widget
16
- from supervisely.io.env import task_id
17
- from supervisely.sly_logger import logger
18
14
 
19
15
 
20
16
  class DebouncedEventHandler:
@@ -37,7 +33,6 @@ class DebouncedEventHandler:
37
33
 
38
34
  class SelectedIds(BaseModel):
39
35
  selected_ids: List[int]
40
- plot_id: Optional[Union[str, int]] = None
41
36
 
42
37
 
43
38
  class Bokeh(Widget):
@@ -77,14 +72,25 @@ class Bokeh(Widget):
77
72
 
78
73
  from supervisely.app.widgets import Bokeh, IFrame
79
74
 
80
- plot = Bokeh.Circle(
81
- x_coordinates=[1, 2, 3, 4, 5],
82
- y_coordinates=[1, 2, 3, 4, 5],
83
- radii=10,
84
- colors="red",
85
- legend_label="Circle plot",
75
+ data = {
76
+ "x": [1, 2, 3, 4, 5],
77
+ "y": [1, 2, 3, 4, 5],
78
+ "radius": [10, 20, 30, 40, 50],
79
+ "colors": ["red", "green", "blue", "yellow", "purple"],
80
+ "ids": [1, 2, 3, 4, 5],
81
+ "names": ["kiwi", "kiwi", "lemon", "lemon", "lemon"],
82
+ }
83
+
84
+ plot_lemon = Bokeh.Circle(name="lemon")
85
+ plot_kiwi = Bokeh.Circle(name="kiwi")
86
+ bokeh = Bokeh(
87
+ x_axis_visible=True,
88
+ y_axis_visible=True,
89
+ grid_visible=True,
90
+ show_legend=True,
86
91
  )
87
- bokeh = Bokeh(plots=[plot], width=1000, height=600)
92
+ bokeh.add_data(**data)
93
+ bokeh.add_plots([plot_lemon, plot_kiwi])
88
94
 
89
95
  # To allow the widget to be interacted with, you need to add it to the IFrame widget.
90
96
  iframe = IFrame()
@@ -96,126 +102,72 @@ class Bokeh(Widget):
96
102
  HTML_ROUTE = "bokeh.html"
97
103
 
98
104
  class Plot(ABC):
99
- @abstractmethod
100
- def add(self, plot) -> None:
101
- pass
105
+ def __init__(self, name: Optional[str] = None, **kwargs):
106
+
107
+ self._name = name or str(uuid4())
108
+ self.kwargs = kwargs
102
109
 
103
110
  @abstractmethod
104
- def register(self, route_path: str) -> None:
111
+ def add(self, plot, source) -> None:
105
112
  pass
106
113
 
114
+ @property
115
+ def name(self) -> str:
116
+ return self._name
117
+
107
118
  class Circle(Plot):
108
- def __init__(
109
- self,
110
- x_coordinates: List[Union[int, float]],
111
- y_coordinates: List[Union[int, float]],
112
- radii: Optional[Union[Union[int, float], List[Union[int, float]]]] = None,
113
- colors: Optional[Union[str, List[str]]] = None,
114
- data: Optional[List[Any]] = None,
115
- dynamic_selection: bool = False,
116
- fill_alpha: float = 0.5,
117
- line_color: Optional[str] = None,
118
- legend_label: Optional[str] = None,
119
- plot_id: Optional[Union[str, int]] = None,
120
- ):
121
- if not colors:
122
- colors = Bokeh._generate_colors(x_coordinates, y_coordinates)
123
- elif isinstance(colors, str):
124
- colors = [colors] * len(x_coordinates)
125
-
126
- if not radii:
127
- radii = Bokeh._generate_radii(x_coordinates, y_coordinates)
128
- elif isinstance(radii, (int, float)):
129
- radii = [radii] * len(x_coordinates)
130
-
131
- if not len(x_coordinates) == len(y_coordinates) == len(radii) == len(colors):
132
- raise ValueError(
133
- "x_coordinates, y_coordinates, radii, and colors must have the same length"
134
- )
135
-
136
- if data is not None and len(data) != len(x_coordinates):
137
- raise ValueError("data must have the same length as x_coordinates")
138
-
139
- if data is None:
140
- data = list(range(len(x_coordinates)))
141
-
142
- self._x_coordinates = x_coordinates
143
- self._y_coordinates = y_coordinates
144
- self._radii = radii
145
- self._colors = colors
146
- self._data = data
147
- self._source = None
148
- self._dynamic_selection = dynamic_selection
149
- self._fill_alpha = fill_alpha
150
- self._line_color = line_color
151
- self._plot_id = plot_id or uuid4().hex
152
- self._legend_label = legend_label or str(self._plot_id)
153
-
154
- def add(self, plot) -> None:
119
+ def add(self, plot, source) -> None:
155
120
  from bokeh.models import ( # pylint: disable=import-error
156
- ColumnDataSource,
157
- LassoSelectTool,
158
- )
159
-
160
- data = dict(
161
- x=self._x_coordinates,
162
- y=self._y_coordinates,
163
- radius=self._radii,
164
- colors=self._colors,
165
- ids=self._data,
121
+ CDSView,
122
+ GroupFilter,
166
123
  )
167
- self._source = ColumnDataSource(data=data)
168
124
 
169
- renderer = plot.circle(
125
+ filters = [GroupFilter(column_name="names", group=self.name, name=self.name)]
126
+ view = CDSView(source=source, filters=filters)
127
+ return plot.circle(
170
128
  "x",
171
129
  "y",
172
130
  radius="radius",
173
131
  fill_color="colors",
174
- fill_alpha=self._fill_alpha,
175
- line_color=self._line_color,
176
- source=self._source,
177
- legend_label=self._legend_label,
132
+ fill_alpha=0.5,
133
+ source=source,
134
+ line_color=None,
135
+ view=view,
178
136
  )
179
- if not self._dynamic_selection:
180
- for tool in plot.tools:
181
- if isinstance(tool, (LassoSelectTool)):
182
- tool.continuous = False
183
-
184
- return renderer
185
-
186
- def register(self, route_path: str) -> None:
187
- from bokeh.models import CustomJS # pylint: disable=import-error
188
-
189
- if not hasattr(self, "_source"):
190
- raise ValueError("Plot must be added to a Bokeh plot before registering")
191
-
192
- if is_production():
193
- api = Api()
194
- task_info = api.task.get_info_by_id(task_id())
195
- if task_info is not None:
196
- route_path = f"/net/{task_info['meta']['sessionToken']}{route_path}"
197
- callback = CustomJS(
198
- args=dict(source=self._source),
199
- code="""
200
- var indices = source.selected.indices;
201
- var selected_ids = [];
202
- for (var i = 0; i < indices.length; i++) {{
203
- selected_ids.push(source.data['ids'][indices[i]]);
204
- }}
205
- var xhr = new XMLHttpRequest();
206
- xhr.open("POST", "{route_path}", true);
207
- xhr.setRequestHeader("Content-Type", "application/json");
208
- xhr.send(JSON.stringify({{selected_ids: selected_ids, plot_id: '{plot_id}'}}));
209
- """.format(
210
- route_path=route_path,
211
- plot_id=self._plot_id,
212
- ),
137
+
138
+ class Scatter(Plot):
139
+ def add(self, plot, source) -> None:
140
+ from bokeh.models import ( # pylint: disable=import-error
141
+ CDSView,
142
+ GroupFilter,
143
+ )
144
+
145
+ filters = [GroupFilter(column_name="names", group=self.name, name=self.name)]
146
+ view = CDSView(source=source, filters=filters)
147
+ return plot.scatter(
148
+ "x",
149
+ "y",
150
+ size="radius",
151
+ color="colors",
152
+ fill_alpha=0.5,
153
+ source=source,
154
+ view=view,
155
+ )
156
+
157
+ class Line(Plot):
158
+ def add(self, plot, source) -> None:
159
+ from bokeh.models import ( # pylint: disable=import-error
160
+ CDSView,
161
+ GroupFilter,
213
162
  )
214
- self._source.selected.js_on_change("indices", callback)
163
+
164
+ filters = [GroupFilter(column_name="names", group=self.name, name=self.name)]
165
+ view = CDSView(source=source, filters=filters)
166
+ return plot.line("x", "y", source=source, view=view, line_width=2)
215
167
 
216
168
  def __init__(
217
169
  self,
218
- plots: List[Plot],
170
+ plots: List[Plot] = None,
219
171
  width: int = 1000,
220
172
  height: int = 600,
221
173
  tools: List[str] = [
@@ -223,7 +175,7 @@ class Bokeh(Widget):
223
175
  "wheel_zoom",
224
176
  "box_zoom",
225
177
  "reset",
226
- "save",
178
+ # "save",
227
179
  "poly_select",
228
180
  "tap",
229
181
  "lasso_select",
@@ -244,8 +196,11 @@ class Bokeh(Widget):
244
196
  if bokeh.__version__ != "3.1.1":
245
197
  raise RuntimeError(f"Bokeh version {bokeh.__version__} is not supported. Use 3.1.1")
246
198
 
199
+ self._source_data = {"x": [], "y": [], "radius": [], "colors": [], "ids": [], "names": []}
200
+ self._source = None
247
201
  self.widget_id = widget_id
248
- self._plots = plots
202
+ self._plots = plots or []
203
+ self._view = None
249
204
 
250
205
  self._width = width
251
206
  self._height = height
@@ -259,56 +214,14 @@ class Bokeh(Widget):
259
214
  self._legend_click_policy = legend_click_policy
260
215
 
261
216
  super().__init__(widget_id=widget_id, file_path=__file__)
262
- self._load_chart()
217
+
218
+ self._update()
263
219
 
264
220
  server = self._sly_app.get_server()
265
221
 
266
222
  @server.get(self.html_route)
267
223
  def _html_response() -> None:
268
- return HTMLResponse(content=self.get_html())
269
-
270
- # TODO: support for offline mode
271
- # JinjaWidgets().context.pop(self.widget_id, None) # remove the widget from index.html
272
-
273
- def _load_chart(self, **kwargs):
274
- from bokeh.models import Legend # pylint: disable=import-error
275
- from bokeh.plotting import figure # pylint: disable=import-error
276
-
277
- self._width = kwargs.get("width", self._width)
278
- self._height = kwargs.get("height", self._height)
279
- self._tools = kwargs.get("tools", self._tools)
280
- self._toolbar_location = kwargs.get("toolbar_location", self._toolbar_location)
281
- self._show_legend = kwargs.get("show_legend", self._show_legend)
282
- self._legend_location = kwargs.get("legend_location", self._legend_location)
283
- self._legend_click_policy = kwargs.get("legend_click_policy", self._legend_click_policy)
284
- self._x_axis_visible = kwargs.get("x_axis_visible", self._x_axis_visible)
285
- self._y_axis_visible = kwargs.get("y_axis_visible", self._y_axis_visible)
286
- self._grid_visible = kwargs.get("grid_visible", self._grid_visible)
287
-
288
- self._plot = figure(
289
- width=self._width,
290
- height=self._height,
291
- tools=self._tools,
292
- toolbar_location=self._toolbar_location,
293
- )
294
-
295
- if self._show_legend:
296
- self._plot.add_layout(
297
- Legend(click_policy=self._legend_click_policy),
298
- self._legend_location,
299
- )
300
-
301
- self._plot.xaxis.visible = self._x_axis_visible
302
- self._plot.yaxis.visible = self._y_axis_visible
303
- self._plot.grid.visible = self._grid_visible
304
-
305
- self._renderers = []
306
- self._process_plots(self._plots)
307
- self._update_html()
308
-
309
- @property
310
- def route_path(self) -> str:
311
- return self.get_route_path(Bokeh.Routes.VALUE_CHANGED)
224
+ return HTMLResponse(content=self._get_html())
312
225
 
313
226
  @property
314
227
  def html_route(self) -> str:
@@ -318,48 +231,75 @@ class Bokeh(Widget):
318
231
  def html_route_with_timestamp(self) -> str:
319
232
  return f".{self.html_route}?t={datetime.now().timestamp()}"
320
233
 
321
- def add_plots(self, plots: List[Plot]) -> None:
322
- self._plots.extend(plots)
323
- self._process_plots(plots)
324
- self._update_html()
234
+ def get_json_data(self):
235
+ return {}
325
236
 
326
- def clear(self) -> None:
327
- self._plots = []
328
- self._renderers = []
329
- self._plot.renderers = []
330
- self._update_html()
237
+ def get_json_state(self):
238
+ return {}
331
239
 
332
- def remove_plot(self, idx: int) -> None:
333
- renderer = self._renderers.pop(idx)
334
- self._plot.renderers.remove(renderer)
335
- self._update_html()
240
+ def _add_callbacks(self):
241
+ from bokeh.models import CustomJS # pylint: disable=import-error
242
+
243
+ route_path = self.get_route_path(Bokeh.Routes.VALUE_CHANGED)
244
+ callback = CustomJS(
245
+ args=dict(source=self._source),
246
+ code=f"""
247
+ var indices = source.selected.indices;
248
+ var selected_ids = [];
249
+ for (var i = 0; i < indices.length; i++) {{
250
+ selected_ids.push(source.data['ids'][indices[i]]);
251
+ }}
252
+ var xhr = new XMLHttpRequest();
253
+ xhr.open("POST", "{route_path}", true);
254
+ xhr.setRequestHeader("Content-Type", "application/json");
255
+ xhr.send(JSON.stringify({{selected_ids: selected_ids}}));
256
+ """,
257
+ )
258
+ self._source.selected.js_on_change("indices", callback)
336
259
 
337
- def _process_plots(self, plots: List[Plot]) -> None:
338
- for plot in plots:
339
- renderer = plot.add(self._plot)
340
- plot.register(self.route_path)
341
- self._renderers.append(renderer)
260
+ def _get_html(self) -> str:
261
+ return f"""<div>
262
+ <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js"></script>
263
+ {self._script}
264
+ {self._div}
265
+ </div>"""
266
+
267
+ def _create_figure(self):
268
+ from bokeh.models import ( # pylint: disable=import-error
269
+ ColumnDataSource,
270
+ Legend,
271
+ )
272
+ from bokeh.plotting import figure # pylint: disable=import-error
273
+
274
+ self._plot = figure(width=self._width, height=self._height, tools=self._tools)
275
+
276
+ self._plot.xaxis.visible = self._x_axis_visible
277
+ self._plot.yaxis.visible = self._y_axis_visible
278
+ self._plot.grid.visible = self._grid_visible
342
279
 
343
- def _update_html(self) -> None:
280
+ self._source = ColumnDataSource(data=self._source_data)
281
+ self._add_callbacks()
282
+ legend_items = []
283
+ for plot in self._plots:
284
+ r = plot.add(self._plot, self._source)
285
+ legend_items.append((plot.name, [r]))
286
+
287
+ if self._show_legend:
288
+ self._plot.add_layout(
289
+ Legend(items=legend_items, click_policy=self._legend_click_policy),
290
+ self._legend_location,
291
+ )
292
+
293
+ def _update_html(self):
344
294
  from bokeh.embed import components # pylint: disable=import-error
345
295
 
346
- script, self._div = components(self._plot, wrap_script=False)
296
+ script, self._div = components(self._plot)
347
297
  self._div_id = self._get_div_id(self._div)
348
298
  self._script = self._update_script(script)
349
299
 
350
- @staticmethod
351
- def _generate_colors(x_coordinates: List[int], y_coordinates: List[int]) -> List[str]:
352
- colors = [
353
- "#%02x%02x%02x" % (int(r), int(g), 150)
354
- for r, g in zip(
355
- [50 + 2 * xi for xi in x_coordinates], [30 + 2 * yi for yi in y_coordinates]
356
- )
357
- ]
358
- return colors
359
-
360
- @staticmethod
361
- def _generate_radii(x_coordinates: List[int], y_coordinates: List[int]) -> List[int]:
362
- return [1] * len(x_coordinates)
300
+ def _update(self):
301
+ self._create_figure()
302
+ self._update_html()
363
303
 
364
304
  def _get_div_id(self, div: str) -> str:
365
305
  match = re.search(r'id="([^"]+)"', div)
@@ -368,69 +308,98 @@ class Bokeh(Widget):
368
308
  raise ValueError(f"No div id found in {div}")
369
309
 
370
310
  def _update_script(self, script: str) -> str:
371
- # TODO: Reimplement using regex.
372
311
  insert_after = "const fn = function() {"
373
312
  updated_script = ""
374
313
  for line in script.split("\n"):
375
314
  if line.strip().startswith(insert_after):
376
- line = line + f"\n const el = document.querySelector('#{self._div_id}');"
377
- line += "\n if (el === null) {"
378
- line += "\n setTimeout(fn, 500);"
379
- line += "\n return;"
380
- line += "\n }"
315
+ line += f"""
316
+ const el = document.querySelector('#{self._div_id}');
317
+ if (el === null) {{
318
+ setTimeout(fn, 200);
319
+ return;
320
+ }}
321
+ """
381
322
  updated_script += line + "\n"
382
323
  return updated_script
383
324
 
384
- def get_json_data(self):
385
- return {}
386
-
387
- def get_json_state(self):
388
- return {}
389
-
390
325
  def value_changed(self, func: Callable) -> Callable:
326
+ """Registers a callback function that will be called when the chart is clicked."""
327
+
391
328
  server = self._sly_app.get_server()
329
+ route_path = self.get_route_path(Bokeh.Routes.VALUE_CHANGED)
392
330
  self._changes_handled = True
393
- debounced_handler = DebouncedEventHandler(debounce_time=0.2) # TODO: check if it's enough
331
+ debounced_handler = DebouncedEventHandler(debounce_time=0.2)
394
332
 
395
- @server.post(self.route_path)
333
+ @server.post(route_path)
396
334
  async def _click(data: SelectedIds) -> None:
397
- debounced_handler.handle_event(data, func)
335
+ debounced_handler.handle_event(data.selected_ids, func)
398
336
 
399
337
  return _click
400
338
 
401
- def get_html(self) -> str:
402
- return f"""<div>
403
- <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js"></script>
404
- <script type="text/javascript"> {self._script} </script>
405
- {self._div}
406
- </div>"""
339
+ def clear(self) -> None:
340
+ """Clears all data in the ColumnDataSource and removes plots."""
407
341
 
408
- def update_radii(self, new_radii: Union[List[Union[list, int, float]], int, float]) -> None:
409
- if isinstance(new_radii, (int, float)):
410
- new_radii = [new_radii] * len(self._plots)
411
- elif len(new_radii) != len(self._plots):
412
- logger.warning(
413
- f"{len(new_radii)} != {len(self._plots)}: new_radii will be broadcasted to all plots"
414
- )
415
- new_radii = [new_radii[0]] * len(self._plots)
416
- for idx, radii in enumerate(new_radii):
417
- self.update_radii_by_plot_idx(idx, radii)
418
-
419
- def update_radii_by_plot_idx(self, plot_idx: int, new_radii: List[Union[int, float]]) -> None:
420
- coords_length = len(self._plots[plot_idx]._x_coordinates)
421
- if isinstance(new_radii, (int, float)):
422
- new_radii = [new_radii] * coords_length
423
- elif len(new_radii) != coords_length:
424
- logger.warning(
425
- f"{len(new_radii)} != {coords_length}: new_radii will be broadcasted to all plots"
426
- )
427
- new_radii = [new_radii[0]] * coords_length
342
+ self._source_data = {key: [] for key in self._source_data.keys()}
343
+ self._plots = []
344
+ self._update()
345
+
346
+ def refresh(self) -> None:
347
+ """Refreshes the chart by reloading the existing data and updating the HTML."""
348
+
349
+ self._update()
350
+
351
+ def update_chart_size(self, width: Optional[int] = None, height: Optional[int] = None):
352
+ """Updates the size of the chart."""
353
+
354
+ if width:
355
+ self._width = width
356
+ if height:
357
+ self._height = height
358
+ self._update()
359
+
360
+ def add_data(
361
+ self,
362
+ x: List[float],
363
+ y: List[float],
364
+ radius: List[float],
365
+ colors: List[str],
366
+ ids: List[Any],
367
+ names: List[str],
368
+ append: bool = True,
369
+ ):
370
+ """Adds data to the chart."""
371
+
372
+ if append:
373
+ self._source.data["x"] += x
374
+ self._source.data["y"] += y
375
+ self._source.data["radius"] += radius
376
+ self._source.data["colors"] += colors
377
+ self._source.data["ids"] += ids
378
+ self._source.data["names"] += names
379
+ else:
380
+ self._source.data = {
381
+ "x": x,
382
+ "y": y,
383
+ "radius": radius,
384
+ "colors": colors,
385
+ "ids": ids,
386
+ "names": names,
387
+ }
388
+
389
+ def add_plot(self, plot: Plot):
390
+ """Adds a plot to the chart."""
391
+
392
+ self._plots.append(plot)
393
+ self._update()
394
+
395
+ def add_plots(self, plots: List[Plot]):
396
+ """Adds multiple plots to the chart."""
397
+
398
+ self._plots.extend(plots)
399
+ self._update()
428
400
 
429
- self._plots[plot_idx]._radii = new_radii
430
- self._plots[plot_idx]._source.data["radius"] = new_radii
431
- self._load_chart()
401
+ def update_point_size(self, size: float):
402
+ """Updates the size of the points in the chart."""
432
403
 
433
- def update_chart_size(self, width: Optional[int] = None, height: Optional[int] = None) -> None:
434
- self._width = width or self._width
435
- self._height = height or self._height
436
- self._load_chart()
404
+ self._source_data["radius"] = [size] * len(self._source_data["x"])
405
+ self._update()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.288
3
+ Version: 6.73.289
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -129,7 +129,7 @@ supervisely/app/widgets/binded_input_number/__init__.py,sha256=47DEQpj8HBSa-_TIm
129
129
  supervisely/app/widgets/binded_input_number/binded_input_number.py,sha256=RXTAGaMXtGOl4pprVLyQosr61t2rI_U_U8VNHhSyBhA,6251
130
130
  supervisely/app/widgets/binded_input_number/template.html,sha256=uCEZ54BNC2itr39wxxThXw62WlJ9659cuz8osCm0WZE,162
131
131
  supervisely/app/widgets/bokeh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
- supervisely/app/widgets/bokeh/bokeh.py,sha256=zob2F-cJ6JX_Dk2FANfN94uHDyxvgoxuBpeL0OebVyg,16128
132
+ supervisely/app/widgets/bokeh/bokeh.py,sha256=H53AqKc3sGJU3aoYeIdFfJoeIquyxbIHCDV8CRBjrUs,13262
133
133
  supervisely/app/widgets/bokeh/template.html,sha256=ntsh7xx4q9OHG62sa_r3INDxsXgvdPFIWTtYaWn_0t8,12
134
134
  supervisely/app/widgets/button/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
135
  supervisely/app/widgets/button/button.py,sha256=zDQinhOOjNNxdP2GIFrwTmVfGAeJJoKV6CT6C8KzQNI,10405
@@ -1071,9 +1071,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
1071
1071
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
1072
1072
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
1073
1073
  supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
1074
- supervisely-6.73.288.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1075
- supervisely-6.73.288.dist-info/METADATA,sha256=bY0YA_vkWd0RNep6zrPSU0itBr5BQBWR8J6aHKBkzQw,33573
1076
- supervisely-6.73.288.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1077
- supervisely-6.73.288.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1078
- supervisely-6.73.288.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1079
- supervisely-6.73.288.dist-info/RECORD,,
1074
+ supervisely-6.73.289.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1075
+ supervisely-6.73.289.dist-info/METADATA,sha256=RMgZIP_bwLgos0vF9tP2PFNzmKVI5h1VFkdK_bX7WKE,33573
1076
+ supervisely-6.73.289.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1077
+ supervisely-6.73.289.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1078
+ supervisely-6.73.289.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1079
+ supervisely-6.73.289.dist-info/RECORD,,