solara-ui 1.48.0__py3-none-any.whl → 1.49.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.
solara/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Build webapps using IPywidgets"""
2
2
 
3
- __version__ = "1.48.0"
3
+ __version__ = "1.49.0"
4
4
  github_url = "https://github.com/widgetti/solara"
5
5
  git_branch = "master"
6
6
 
@@ -1,7 +1,8 @@
1
1
  import os
2
2
  from os.path import isfile, join
3
3
  from pathlib import Path
4
- from typing import Callable, Dict, List, Optional, Union, cast
4
+ from typing import Callable, Dict, List, Optional, TypeVar, Union, cast
5
+ import logging
5
6
 
6
7
  import humanize
7
8
  import ipyvuetify as vy
@@ -10,6 +11,9 @@ import traitlets
10
11
  import solara
11
12
  from solara.components import Div
12
13
 
14
+ T = TypeVar("T")
15
+ logger = logging.getLogger(__name__)
16
+
13
17
 
14
18
  def list_dir(path, filter: Callable[[Path], bool] = lambda x: True, directory_first: bool = False) -> List[dict]:
15
19
  def mk_item(n):
@@ -48,9 +52,30 @@ class FileListWidget(vy.VuetifyTemplate):
48
52
  return name in [k["name"] for k in self.files]
49
53
 
50
54
 
55
+ def use_reactive_or_value(
56
+ value: Union[T, solara.Reactive[T]], on_value: Optional[Callable[[T], None]] = None, value_name="value", on_value_name="on_value", use_internal_value=False
57
+ ):
58
+ def hookup_on_value():
59
+ if isinstance(value, solara.Reactive) and on_value:
60
+ return value.subscribe(on_value)
61
+
62
+ solara.use_effect(hookup_on_value, [isinstance(value, solara.Reactive), on_value])
63
+ internal_value, set_internal_value = solara.use_state(value.value if isinstance(value, solara.Reactive) else value)
64
+ if use_internal_value:
65
+ return internal_value, set_internal_value
66
+ if isinstance(value, solara.Reactive):
67
+ return value.value, value.set
68
+ elif on_value:
69
+ return value, on_value
70
+ else:
71
+ logger.warning("You should provide an %s callback if you are not using a reactive value, otherwise %s input will not update", on_value_name, value_name)
72
+ return value, lambda x: None
73
+
74
+
51
75
  @solara.component
52
76
  def FileBrowser(
53
77
  directory: Union[None, str, Path, solara.Reactive[Path]] = None,
78
+ selected: Union[None, Path, solara.Reactive[Optional[Path]]] = None,
54
79
  on_directory_change: Optional[Callable[[Path], None]] = None,
55
80
  on_path_select: Optional[Callable[[Optional[Path]], None]] = None,
56
81
  on_file_open: Optional[Callable[[Path], None]] = None,
@@ -75,7 +100,8 @@ def FileBrowser(
75
100
 
76
101
  ## Arguments
77
102
 
78
- * `directory`: The directory to start in. If `None` the current working directory is used.
103
+ * `directory`: The directory to start in. If `None`, the current working directory is used.
104
+ * `selected`: The selected file or directory. If `None`, no file or directory is selected (requires `can_select=True`).
79
105
  * `on_directory_change`: Depends on mode, see above.
80
106
  * `on_path_select`: Depends on mode, see above.
81
107
  * `on_file_open`: Depends on mode, see above.
@@ -90,13 +116,30 @@ def FileBrowser(
90
116
  directory = os.getcwd() # pragma: no cover
91
117
  if isinstance(directory, str):
92
118
  directory = Path(directory)
119
+ # directory = directory.resolve()
93
120
  current_dir = solara.use_reactive(directory)
94
- selected, set_selected = solara.use_state(None)
95
121
  double_clicked, set_double_clicked = solara.use_state(None)
96
122
  warning, set_warning = solara.use_state(cast(Optional[str], None))
97
123
  scroll_pos_stack, set_scroll_pos_stack = solara.use_state(cast(List[int], []))
98
124
  scroll_pos, set_scroll_pos = solara.use_state(0)
99
- selected, set_selected = solara.use_state(None)
125
+ selected_private, set_selected_private = use_reactive_or_value(
126
+ selected,
127
+ on_value=on_path_select if can_select else lambda x: None,
128
+ value_name="selected",
129
+ on_value_name="on_path_select",
130
+ use_internal_value=not can_select,
131
+ )
132
+ # remove so we don't accidentally use it
133
+ del selected
134
+
135
+ def sync_directory_from_selected():
136
+ if selected_private is not None:
137
+ # if we select a file, we need to make sure the directory is correct
138
+ # NOTE: although we expect a Path, abuse might make it a string
139
+ if isinstance(selected_private, Path):
140
+ current_dir.value = selected_private.resolve().parent
141
+
142
+ solara.use_effect(sync_directory_from_selected, [selected_private])
100
143
 
101
144
  def change_dir(new_dir: Path):
102
145
  if os.access(new_dir, os.R_OK):
@@ -114,14 +157,14 @@ def FileBrowser(
114
157
  on_path_select(None)
115
158
  return
116
159
  if item["name"] == "..":
117
- new_dir = current_dir.value.parent
160
+ new_dir = current_dir.value.resolve().parent
118
161
  action_change_directory = (can_select and double_click) or (not can_select and not double_click)
119
162
  if action_change_directory and change_dir(new_dir):
120
163
  if scroll_pos_stack:
121
164
  last_pos = scroll_pos_stack[-1]
122
165
  set_scroll_pos_stack(scroll_pos_stack[:-1])
123
166
  set_scroll_pos(last_pos)
124
- set_selected(None)
167
+ set_selected_private(None)
125
168
  set_double_clicked(None)
126
169
  if on_path_select and can_select:
127
170
  on_path_select(None)
@@ -142,7 +185,7 @@ def FileBrowser(
142
185
  if change_dir(path):
143
186
  set_scroll_pos_stack(scroll_pos_stack + [scroll_pos])
144
187
  set_scroll_pos(0)
145
- set_selected(None)
188
+ set_selected_private(None)
146
189
  set_double_clicked(None)
147
190
  if on_path_select and can_select:
148
191
  on_path_select(None)
@@ -153,7 +196,7 @@ def FileBrowser(
153
196
  raise RuntimeError("Combination should not happen") # pragma: no cover
154
197
 
155
198
  def on_click(item):
156
- set_selected(item)
199
+ set_selected_private(item["name"] if item else None)
157
200
  on_item(item, False)
158
201
 
159
202
  def on_double_click(item):
@@ -163,12 +206,20 @@ def FileBrowser(
163
206
  # otherwise we can ignore it, single click will handle it
164
207
 
165
208
  files = [{"name": "..", "is_file": False}] + list_dir(current_dir.value, filter=filter, directory_first=directory_first)
209
+ clicked = (
210
+ {
211
+ "name": selected_private.name if isinstance(selected_private, Path) else selected_private,
212
+ "is_file": isinstance(selected_private, Path),
213
+ "size": None,
214
+ }
215
+ if selected_private is not None
216
+ else None
217
+ )
166
218
  with Div(class_="solara-file-browser") as main:
167
- Div(children=[str(current_dir.value)])
219
+ Div(children=[str(current_dir.value.resolve())])
168
220
  FileListWidget.element(
169
221
  files=files,
170
- selected=selected,
171
- clicked=selected,
222
+ clicked=clicked,
172
223
  on_clicked=on_click,
173
224
  double_clicked=double_clicked,
174
225
  on_double_clicked=on_double_click,
@@ -119,7 +119,7 @@ async def main():
119
119
  ]
120
120
  for dep in requirements:
121
121
  await micropip.install(dep, keep_going=True)
122
- await micropip.install("/wheels/solara-1.48.0-py2.py3-none-any.whl", keep_going=True)
122
+ await micropip.install("/wheels/solara-1.49.0-py2.py3-none-any.whl", keep_going=True)
123
123
  import solara
124
124
 
125
125
  el = solara.Warning("lala")
@@ -2,29 +2,37 @@
2
2
 
3
3
  from pathlib import Path
4
4
  from typing import Optional, cast
5
-
5
+ import random
6
6
  import solara
7
7
  from solara.website.utils import apidoc
8
8
 
9
+ opened = solara.reactive(cast(Optional[Path], None))
10
+ selected = solara.reactive(cast(Optional[Path], None))
11
+ directory = solara.reactive(Path("~").expanduser())
12
+ can_select = solara.reactive(False)
13
+
9
14
 
10
15
  @solara.component
11
16
  def Page():
12
- file, set_file = solara.use_state(cast(Optional[Path], None))
13
- path, set_path = solara.use_state(cast(Optional[Path], None))
14
- directory, set_directory = solara.use_state(Path("~").expanduser())
15
-
16
- can_select = solara.ui_checkbox("Enable select")
17
-
18
17
  def reset_path():
19
- set_path(None)
20
- set_file(None)
18
+ opened.value = None
19
+ selected.value = None
20
+
21
+ def select_random_file():
22
+ files = list(directory.value.glob("*"))
23
+ if files:
24
+ selected.value = random.choice(files)
21
25
 
22
26
  # reset path and file when can_select changes
23
- solara.use_memo(reset_path, [can_select])
24
- solara.FileBrowser(directory, on_directory_change=set_directory, on_path_select=set_path, on_file_open=set_file, can_select=can_select)
27
+ solara.use_memo(reset_path, [can_select.value])
28
+ solara.Checkbox(label="Enable select", value=can_select)
29
+ solara.FileBrowser(directory, selected=selected, on_file_open=opened.set, can_select=can_select.value)
25
30
  solara.Info(f"You are in directory: {directory}")
26
- solara.Info(f"You selected path: {path}")
27
- solara.Info(f"You opened file: {file}")
31
+ solara.Info(f"You selected path: {selected}")
32
+ solara.Info(f"You opened file: {opened}")
33
+
34
+ if can_select.value:
35
+ solara.Button(label="Select random file", on_click=select_random_file)
28
36
 
29
37
 
30
38
  __doc__ += apidoc(solara.FileBrowser.f) # type: ignore
@@ -32,7 +32,7 @@ def Page():
32
32
  with solara.Card("TESSA", style={"height": "100%"}):
33
33
  solara.Markdown(
34
34
  """
35
- [TESSA](https://planeto-energy.ch/solution/) is a tool developed by Planeto for district heating & cooling planning.
35
+ [TESSA](https://planeto-energy.ch/) is a tool developed by Planeto for district heating & cooling planning.
36
36
  """
37
37
  )
38
38
  with solara.Link("./planeto_tessa"):
@@ -10,7 +10,7 @@ def Page():
10
10
  """
11
11
  # TESSA by Planeto
12
12
 
13
- [Planeto](https://planeto-energy.ch/) developed a tool called [TESSA](https://planeto-energy.ch/solution/) for district heating & cooling planning.
13
+ [Planeto](https://planeto-energy.ch/) developed a tool called TESSA for district heating & cooling planning.
14
14
 
15
15
  TESSA was prototyped in the Jupyter notebook using ipywidgets. Using solara, they are able to bring TESSA into production using the
16
16
  same technology stack.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solara-ui
3
- Version: 1.48.0
3
+ Version: 1.49.0
4
4
  Dynamic: Summary
5
5
  Project-URL: Home, https://www.github.com/widgetti/solara
6
6
  Project-URL: Documentation, https://solara.dev
@@ -1,6 +1,6 @@
1
1
  prefix/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
2
2
  prefix/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
3
- solara/__init__.py,sha256=8GsgAErkS5dA1fa2M7LKzN6p6qy9IyZYYBcU0mS8yuo,3647
3
+ solara/__init__.py,sha256=wkvVNU53A8t1_3SujgqIpjFmcWrnOx_JyZzVmpAcpm8,3647
4
4
  solara/__main__.py,sha256=pm79jfba-0ZapLR0PtwZfMeiTHrLz8kEt79EygRyXxQ,24828
5
5
  solara/_stores.py,sha256=N2Ec-61XNFXwigBx8f5QYPx7gDXenCOBdmLPXiJB45E,12320
6
6
  solara/alias.py,sha256=9vfLzud77NP8in3OID9b5mmIO8NyrnFjN2_aE0lSb1k,216
@@ -43,7 +43,7 @@ solara/components/download.vue,sha256=xdh4olwVvGkQwGNRMU5eVUW1FGvcXrYrCyjddJbvH7
43
43
  solara/components/echarts.py,sha256=aAedLqKuVJnBi3FwhSdQIgAn-w55sNb_hGSmqkosfuA,3069
44
44
  solara/components/echarts.vue,sha256=7TGmxaRUmH-LeH16jHiUzyuZgebGu_JDiWsa2DBSWW4,4056
45
45
  solara/components/figure_altair.py,sha256=t4EEwXrdoisrbV5j2MS-HBlPc5HSFCK5r4mRXvYRH9w,1150
46
- solara/components/file_browser.py,sha256=701vg4_c0au9va206sx3pQDX6NL1VFqs7ewQ0RAbn6k,7331
46
+ solara/components/file_browser.py,sha256=x4NdYmazI2NChq9x_I7lqcpFOIdX_A4avRPjoB5bvKw,9585
47
47
  solara/components/file_download.py,sha256=Lil0qyiozU_Pxyb_HgnJXOumrxMeDwwavEmZZw6kAs8,7475
48
48
  solara/components/file_drop.py,sha256=BA53EZsCzzPCS8i2ZH_S1NAkmmQlTOvNEoXAt0_1l4A,5239
49
49
  solara/components/file_drop.vue,sha256=7V6YjHhoqOCVDMVPtObNwfHz2MdXLCFlNEqK1brl3zI,2243
@@ -146,7 +146,7 @@ solara/server/static/highlight-dark.css,sha256=xO8-vta9vG4s1OfJNHXWqiLWzx_gM03jo
146
146
  solara/server/static/highlight.css,sha256=k8ZdT5iwrGQ5tXTQHAXuxvZrSUq3kwCdEpy3mlFoZjs,2637
147
147
  solara/server/static/main-vuetify.js,sha256=R3qM4xMlstMpRUdRaul78p34z_Av2ONSTXksg2V9TqQ,9503
148
148
  solara/server/static/main.js,sha256=mcx4JNQ4Lg4pNdUIqMoZos1mZyYFS48yd_JNFFJUqIE,5679
149
- solara/server/static/solara_bootstrap.py,sha256=Vsr4ZZQFyG6LDNyYOGEK84uIlP3-_eYF6IDcFv36-gE,3195
149
+ solara/server/static/solara_bootstrap.py,sha256=1du6V59LpN8Al8-Lrir3kR3_uG0HpcbYB25mq0hRDks,3195
150
150
  solara/server/static/sun.svg,sha256=jEKBAGCr7b9zNYv0VUb7lMWKjnU2dX69_Ye_DZWGXJI,6855
151
151
  solara/server/static/webworker.js,sha256=cjAFz7-SygStHJnYlJUlJs-gE_7YQeQ-WBDcmKYyjvo,1372
152
152
  solara/server/templates/index.html.j2,sha256=JXQo1M-STFHLBOFetgG7509cAq8xUP0VAEtYDzz35fY,31
@@ -312,7 +312,7 @@ solara/website/pages/documentation/components/enterprise/avatar_menu.py,sha256=T
312
312
  solara/website/pages/documentation/components/input/__init__.py,sha256=5qmC4lE7WKhZ-NCpOXfINltTKpiC0mBW86vHoGb9Mdk,179
313
313
  solara/website/pages/documentation/components/input/button.py,sha256=MB46yBccVgFc-CM9rs1_GzuXoA2PzCfNsn3qbyguums,433
314
314
  solara/website/pages/documentation/components/input/checkbox.py,sha256=OdbHlLOrEPc3a2R8-UY0q9e4bnCgzgatVG9yHSftNqk,187
315
- solara/website/pages/documentation/components/input/file_browser.py,sha256=USZvDaYo53XxMCHXu64EKJAp2upzaHUwevxwFjRoGAE,933
315
+ solara/website/pages/documentation/components/input/file_browser.py,sha256=dBhvhd5PUTZql0DsvIiASOt30QtSR3xLx97xXDQVU6k,1188
316
316
  solara/website/pages/documentation/components/input/file_drop.py,sha256=Khj_ge7vlwdTLhHqzEwWAJ7GBHTM63NvHPREv7u_Rx8,2290
317
317
  solara/website/pages/documentation/components/input/input.py,sha256=WpHuv40mrl0yGxipcvEoF2TkBPpqyNdjHlNwEBdpg8k,1156
318
318
  solara/website/pages/documentation/components/input/select.py,sha256=PWvUsJHSyNJNenLcj2XSMD3NnclkxcxpBk553-RXNOc,439
@@ -434,9 +434,9 @@ solara/website/pages/our_team/__init__.py,sha256=sLTqx4rw1HuXr-HEXUsexjfGn9IkVx9
434
434
  solara/website/pages/pricing/__init__.py,sha256=wYlHoEE6A3fVY_K47LuS2txXJifOSHhMI9dN3-jfW8s,1362
435
435
  solara/website/pages/roadmap/__init__.py,sha256=T7NULo-JEldhIpKaj_NQ_ka8iFGijUxk6f1LN-rvVUk,283
436
436
  solara/website/pages/roadmap/roadmap.md,sha256=rRD9EH4mUlCQezbI52-MQBWL1mAQQJ6GUdUuasPnZiQ,3634
437
- solara/website/pages/showcase/__init__.py,sha256=_6VP_Lxomr-hQz-hceEyLKo503gmcuuxqwJQW7Ps8Vo,6326
437
+ solara/website/pages/showcase/__init__.py,sha256=p3a_6dIcHrw8kipIUz7jBM_AIPWUs0VMkfeHdHU5h68,6317
438
438
  solara/website/pages/showcase/domino_code_assist.py,sha256=dxEbAYeZwiSx1_JHVd1dsnEqpPwiv3TcmYSonwjc-PE,2297
439
- solara/website/pages/showcase/planeto_tessa.py,sha256=7uFsWvzOenyJIKW88ZF7PmkEStdySinUEgraeU6LKCE,723
439
+ solara/website/pages/showcase/planeto_tessa.py,sha256=DqRZO7oVEN4kJyzHTKixEILXMwJFzEUFElstSWS5Ybc,684
440
440
  solara/website/pages/showcase/solara_dev.py,sha256=Rpjp6sMg5kZSM4z5K-oZ5T3cyAhvnQS9n8cX4seR27U,2028
441
441
  solara/website/pages/showcase/solarathon_2023_team_2.py,sha256=NT_TffxdrOG-puaIDYVepJH2bX_yH4AaiUIWRJ6wACg,1084
442
442
  solara/website/pages/showcase/solarathon_2023_team_4.py,sha256=F8hvevZ2wqqf8agWHjKFUEhrxCxPJkd19uJ4tv2HkAs,1078
@@ -456,9 +456,9 @@ solara/widgets/vue/gridlayout.vue,sha256=LZk-YlqM7nv_7Y5TTq2xqfH1j2SLP1QOH5eiz7G
456
456
  solara/widgets/vue/html.vue,sha256=48K5rjp0AdJDeRV6F3nOHW3J0WXPeHn55r5pGClK2fU,112
457
457
  solara/widgets/vue/navigator.vue,sha256=7fkX-4_YSnnMIPUMKMvQVVEzrmhY9BFAYvHMqZqTXpI,4790
458
458
  solara/widgets/vue/vegalite.vue,sha256=zhocRsUCNIRQCEbD16er5sYnuHU0YThatRHnorA3P18,4596
459
- solara_ui-1.48.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
460
- solara_ui-1.48.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
461
- solara_ui-1.48.0.dist-info/METADATA,sha256=89gyWKym-70PtLtlRfc7Wre6bWfW5He78idYwUoM1hM,7459
462
- solara_ui-1.48.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
463
- solara_ui-1.48.0.dist-info/licenses/LICENSE,sha256=fFJUz-CWzZ9nEc4QZKu44jMEoDr5fEW-SiqljKpD82E,1086
464
- solara_ui-1.48.0.dist-info/RECORD,,
459
+ solara_ui-1.49.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
460
+ solara_ui-1.49.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
461
+ solara_ui-1.49.0.dist-info/METADATA,sha256=NVpNXdQ7OF1dnnWLInqm9L7OFq-trlhtFgiF4AHgimE,7459
462
+ solara_ui-1.49.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
463
+ solara_ui-1.49.0.dist-info/licenses/LICENSE,sha256=fFJUz-CWzZ9nEc4QZKu44jMEoDr5fEW-SiqljKpD82E,1086
464
+ solara_ui-1.49.0.dist-info/RECORD,,