solara-ui 1.45.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.
Files changed (464) hide show
  1. prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  2. prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  3. solara/__init__.py +124 -0
  4. solara/__main__.py +765 -0
  5. solara/_stores.py +297 -0
  6. solara/alias.py +6 -0
  7. solara/autorouting.py +555 -0
  8. solara/cache.py +305 -0
  9. solara/checks.html +71 -0
  10. solara/checks.py +227 -0
  11. solara/comm.py +28 -0
  12. solara/components/__init__.py +77 -0
  13. solara/components/alert.py +155 -0
  14. solara/components/applayout.py +397 -0
  15. solara/components/button.py +85 -0
  16. solara/components/card.py +87 -0
  17. solara/components/checkbox.py +50 -0
  18. solara/components/code_highlight_css.py +11 -0
  19. solara/components/code_highlight_css.vue +63 -0
  20. solara/components/columns.py +159 -0
  21. solara/components/component_vue.py +134 -0
  22. solara/components/cross_filter.py +335 -0
  23. solara/components/dataframe.py +546 -0
  24. solara/components/datatable.py +214 -0
  25. solara/components/datatable.vue +175 -0
  26. solara/components/details.py +56 -0
  27. solara/components/download.vue +35 -0
  28. solara/components/echarts.py +86 -0
  29. solara/components/echarts.vue +139 -0
  30. solara/components/figure_altair.py +39 -0
  31. solara/components/file_browser.py +181 -0
  32. solara/components/file_download.py +199 -0
  33. solara/components/file_drop.py +159 -0
  34. solara/components/file_drop.vue +83 -0
  35. solara/components/file_list_widget.vue +78 -0
  36. solara/components/head.py +27 -0
  37. solara/components/head_tag.py +49 -0
  38. solara/components/head_tag.vue +60 -0
  39. solara/components/image.py +173 -0
  40. solara/components/input.py +456 -0
  41. solara/components/input_text_area.py +86 -0
  42. solara/components/link.py +55 -0
  43. solara/components/markdown.py +441 -0
  44. solara/components/markdown_editor.py +33 -0
  45. solara/components/markdown_editor.vue +359 -0
  46. solara/components/matplotlib.py +74 -0
  47. solara/components/meta.py +47 -0
  48. solara/components/misc.py +333 -0
  49. solara/components/pivot_table.py +258 -0
  50. solara/components/pivot_table.vue +158 -0
  51. solara/components/progress.py +47 -0
  52. solara/components/select.py +182 -0
  53. solara/components/select.vue +27 -0
  54. solara/components/slider.py +442 -0
  55. solara/components/slider_date.vue +56 -0
  56. solara/components/spinner-solara.vue +105 -0
  57. solara/components/spinner.py +45 -0
  58. solara/components/sql_code.py +41 -0
  59. solara/components/sql_code.vue +125 -0
  60. solara/components/style.py +105 -0
  61. solara/components/switch.py +71 -0
  62. solara/components/tab_navigation.py +37 -0
  63. solara/components/title.py +90 -0
  64. solara/components/title.vue +38 -0
  65. solara/components/togglebuttons.py +200 -0
  66. solara/components/tooltip.py +61 -0
  67. solara/core.py +42 -0
  68. solara/datatypes.py +143 -0
  69. solara/express.py +241 -0
  70. solara/hooks/__init__.py +4 -0
  71. solara/hooks/dataframe.py +99 -0
  72. solara/hooks/misc.py +263 -0
  73. solara/hooks/use_reactive.py +151 -0
  74. solara/hooks/use_thread.py +129 -0
  75. solara/kitchensink.py +8 -0
  76. solara/lab/__init__.py +34 -0
  77. solara/lab/components/__init__.py +7 -0
  78. solara/lab/components/chat.py +215 -0
  79. solara/lab/components/confirmation_dialog.py +163 -0
  80. solara/lab/components/cross_filter.py +7 -0
  81. solara/lab/components/input_date.py +339 -0
  82. solara/lab/components/input_time.py +133 -0
  83. solara/lab/components/menu.py +181 -0
  84. solara/lab/components/menu.vue +38 -0
  85. solara/lab/components/tabs.py +274 -0
  86. solara/lab/components/theming.py +98 -0
  87. solara/lab/components/theming.vue +72 -0
  88. solara/lab/hooks/__init__.py +0 -0
  89. solara/lab/hooks/dataframe.py +2 -0
  90. solara/lab/toestand.py +3 -0
  91. solara/lab/utils/__init__.py +2 -0
  92. solara/lab/utils/cookies.py +5 -0
  93. solara/lab/utils/dataframe.py +165 -0
  94. solara/lab/utils/headers.py +5 -0
  95. solara/layout.py +44 -0
  96. solara/lifecycle.py +46 -0
  97. solara/minisettings.py +141 -0
  98. solara/py.typed +0 -0
  99. solara/reactive.py +99 -0
  100. solara/routing.py +268 -0
  101. solara/scope/__init__.py +88 -0
  102. solara/scope/types.py +55 -0
  103. solara/server/__init__.py +0 -0
  104. solara/server/app.py +527 -0
  105. solara/server/assets/custom.css +1 -0
  106. solara/server/assets/custom.js +1 -0
  107. solara/server/assets/favicon.png +0 -0
  108. solara/server/assets/favicon.svg +5 -0
  109. solara/server/assets/style.css +1681 -0
  110. solara/server/assets/theme-dark.css +437 -0
  111. solara/server/assets/theme-light.css +420 -0
  112. solara/server/assets/theme.js +3 -0
  113. solara/server/cdn_helper.py +91 -0
  114. solara/server/esm.py +71 -0
  115. solara/server/fastapi.py +5 -0
  116. solara/server/flask.py +297 -0
  117. solara/server/jupyter/__init__.py +2 -0
  118. solara/server/jupyter/cdn_handler.py +28 -0
  119. solara/server/jupyter/server_extension.py +40 -0
  120. solara/server/jupyter/solara.py +91 -0
  121. solara/server/jupytertools.py +46 -0
  122. solara/server/kernel.py +388 -0
  123. solara/server/kernel_context.py +467 -0
  124. solara/server/patch.py +564 -0
  125. solara/server/pyinstaller/__init__.py +9 -0
  126. solara/server/pyinstaller/hook-ipyreact.py +5 -0
  127. solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
  128. solara/server/pyinstaller/hook-solara.py +9 -0
  129. solara/server/qt.py +113 -0
  130. solara/server/reload.py +251 -0
  131. solara/server/server.py +484 -0
  132. solara/server/settings.py +249 -0
  133. solara/server/shell.py +269 -0
  134. solara/server/starlette.py +770 -0
  135. solara/server/static/ansi.js +270 -0
  136. solara/server/static/highlight-dark.css +82 -0
  137. solara/server/static/highlight.css +43 -0
  138. solara/server/static/main-vuetify.js +272 -0
  139. solara/server/static/main.js +163 -0
  140. solara/server/static/solara_bootstrap.py +129 -0
  141. solara/server/static/sun.svg +23 -0
  142. solara/server/static/webworker.js +42 -0
  143. solara/server/telemetry.py +212 -0
  144. solara/server/templates/index.html.j2 +1 -0
  145. solara/server/templates/loader-plain.css +11 -0
  146. solara/server/templates/loader-plain.html +20 -0
  147. solara/server/templates/loader-solara.css +111 -0
  148. solara/server/templates/loader-solara.html +40 -0
  149. solara/server/templates/plain.html +82 -0
  150. solara/server/templates/solara.html.j2 +486 -0
  151. solara/server/threaded.py +84 -0
  152. solara/server/utils.py +44 -0
  153. solara/server/websocket.py +45 -0
  154. solara/settings.py +86 -0
  155. solara/tasks.py +893 -0
  156. solara/template/button.py +16 -0
  157. solara/template/markdown.py +42 -0
  158. solara/template/portal/.flake8 +6 -0
  159. solara/template/portal/.pre-commit-config.yaml +28 -0
  160. solara/template/portal/LICENSE +21 -0
  161. solara/template/portal/Procfile +7 -0
  162. solara/template/portal/mypy.ini +3 -0
  163. solara/template/portal/pyproject.toml +26 -0
  164. solara/template/portal/solara_portal/__init__.py +4 -0
  165. solara/template/portal/solara_portal/components/__init__.py +2 -0
  166. solara/template/portal/solara_portal/components/article.py +28 -0
  167. solara/template/portal/solara_portal/components/data.py +28 -0
  168. solara/template/portal/solara_portal/components/header.py +6 -0
  169. solara/template/portal/solara_portal/components/layout.py +6 -0
  170. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
  171. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
  172. solara/template/portal/solara_portal/data.py +60 -0
  173. solara/template/portal/solara_portal/pages/__init__.py +67 -0
  174. solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
  175. solara/template/portal/solara_portal/pages/tabular.py +29 -0
  176. solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
  177. solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
  178. solara/test/__init__.py +0 -0
  179. solara/test/pytest_plugin.py +783 -0
  180. solara/toestand.py +998 -0
  181. solara/util.py +348 -0
  182. solara/validate_hooks.py +258 -0
  183. solara/website/__init__.py +0 -0
  184. solara/website/assets/custom.css +444 -0
  185. solara/website/assets/images/logo-small.png +0 -0
  186. solara/website/assets/images/logo.svg +17 -0
  187. solara/website/assets/images/logo_white.svg +50 -0
  188. solara/website/assets/theme.js +8 -0
  189. solara/website/components/__init__.py +5 -0
  190. solara/website/components/algolia.py +6 -0
  191. solara/website/components/algolia.vue +24 -0
  192. solara/website/components/algolia_api.vue +202 -0
  193. solara/website/components/breadcrumbs.py +28 -0
  194. solara/website/components/contact.py +144 -0
  195. solara/website/components/docs.py +143 -0
  196. solara/website/components/header.py +75 -0
  197. solara/website/components/mailchimp.py +12 -0
  198. solara/website/components/mailchimp.vue +47 -0
  199. solara/website/components/markdown.py +99 -0
  200. solara/website/components/markdown_nav.vue +34 -0
  201. solara/website/components/notebook.py +171 -0
  202. solara/website/components/sidebar.py +105 -0
  203. solara/website/pages/__init__.py +370 -0
  204. solara/website/pages/about/__init__.py +9 -0
  205. solara/website/pages/about/about.md +3 -0
  206. solara/website/pages/apps/__init__.py +16 -0
  207. solara/website/pages/apps/authorization/__init__.py +119 -0
  208. solara/website/pages/apps/authorization/admin.py +12 -0
  209. solara/website/pages/apps/authorization/users.py +12 -0
  210. solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
  211. solara/website/pages/apps/layout-demo.py +40 -0
  212. solara/website/pages/apps/multipage/__init__.py +38 -0
  213. solara/website/pages/apps/multipage/page1.py +26 -0
  214. solara/website/pages/apps/multipage/page2.py +34 -0
  215. solara/website/pages/apps/scatter.py +136 -0
  216. solara/website/pages/apps/scrolling.py +63 -0
  217. solara/website/pages/apps/tutorial-streamlit.py +18 -0
  218. solara/website/pages/careers/__init__.py +27 -0
  219. solara/website/pages/changelog/__init__.py +10 -0
  220. solara/website/pages/changelog/changelog.md +372 -0
  221. solara/website/pages/contact/__init__.py +34 -0
  222. solara/website/pages/doc_use_download.py +85 -0
  223. solara/website/pages/documentation/__init__.py +90 -0
  224. solara/website/pages/documentation/advanced/__init__.py +9 -0
  225. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  226. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
  227. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
  228. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
  229. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +417 -0
  230. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
  231. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +50 -0
  232. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
  233. solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
  234. solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
  235. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +72 -0
  236. solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
  237. solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
  238. solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
  239. solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
  240. solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
  241. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
  242. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
  243. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
  244. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
  245. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
  246. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
  247. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +192 -0
  248. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
  249. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
  250. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +256 -0
  251. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +108 -0
  252. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
  253. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +7 -0
  254. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +187 -0
  255. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  256. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
  257. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
  258. solara/website/pages/documentation/api/__init__.py +19 -0
  259. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  260. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +22 -0
  261. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +20 -0
  262. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +20 -0
  263. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +20 -0
  264. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  265. solara/website/pages/documentation/api/hooks/use_cross_filter.py +23 -0
  266. solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
  267. solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
  268. solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
  269. solara/website/pages/documentation/api/hooks/use_exception.py +31 -0
  270. solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
  271. solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
  272. solara/website/pages/documentation/api/hooks/use_previous.py +30 -0
  273. solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
  274. solara/website/pages/documentation/api/hooks/use_state.py +10 -0
  275. solara/website/pages/documentation/api/hooks/use_state_or_update.py +66 -0
  276. solara/website/pages/documentation/api/hooks/use_thread.md +64 -0
  277. solara/website/pages/documentation/api/hooks/use_thread.py +42 -0
  278. solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
  279. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  280. solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
  281. solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
  282. solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
  283. solara/website/pages/documentation/api/routing/route.py +29 -0
  284. solara/website/pages/documentation/api/routing/use_route.py +76 -0
  285. solara/website/pages/documentation/api/routing/use_router.py +16 -0
  286. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  287. solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
  288. solara/website/pages/documentation/api/utilities/computed.py +16 -0
  289. solara/website/pages/documentation/api/utilities/display.py +16 -0
  290. solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
  291. solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
  292. solara/website/pages/documentation/api/utilities/memoize.py +35 -0
  293. solara/website/pages/documentation/api/utilities/on_kernel_start.py +44 -0
  294. solara/website/pages/documentation/api/utilities/reactive.py +16 -0
  295. solara/website/pages/documentation/api/utilities/widget.py +104 -0
  296. solara/website/pages/documentation/components/__init__.py +12 -0
  297. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  298. solara/website/pages/documentation/components/advanced/link.py +25 -0
  299. solara/website/pages/documentation/components/advanced/meta.py +17 -0
  300. solara/website/pages/documentation/components/advanced/style.py +43 -0
  301. solara/website/pages/documentation/components/common.py +9 -0
  302. solara/website/pages/documentation/components/data/__init__.py +9 -0
  303. solara/website/pages/documentation/components/data/dataframe.py +44 -0
  304. solara/website/pages/documentation/components/data/pivot_table.py +81 -0
  305. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  306. solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
  307. solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
  308. solara/website/pages/documentation/components/input/__init__.py +9 -0
  309. solara/website/pages/documentation/components/input/button.py +23 -0
  310. solara/website/pages/documentation/components/input/checkbox.py +10 -0
  311. solara/website/pages/documentation/components/input/file_browser.py +30 -0
  312. solara/website/pages/documentation/components/input/file_drop.py +76 -0
  313. solara/website/pages/documentation/components/input/input.py +43 -0
  314. solara/website/pages/documentation/components/input/select.py +22 -0
  315. solara/website/pages/documentation/components/input/slider.py +29 -0
  316. solara/website/pages/documentation/components/input/switch.py +10 -0
  317. solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
  318. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  319. solara/website/pages/documentation/components/lab/chat.py +109 -0
  320. solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
  321. solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
  322. solara/website/pages/documentation/components/lab/input_date.py +20 -0
  323. solara/website/pages/documentation/components/lab/input_time.py +15 -0
  324. solara/website/pages/documentation/components/lab/menu.py +22 -0
  325. solara/website/pages/documentation/components/lab/tab.py +25 -0
  326. solara/website/pages/documentation/components/lab/tabs.py +45 -0
  327. solara/website/pages/documentation/components/lab/task.py +11 -0
  328. solara/website/pages/documentation/components/lab/theming.py +74 -0
  329. solara/website/pages/documentation/components/lab/use_task.py +11 -0
  330. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  331. solara/website/pages/documentation/components/layout/app_bar.py +16 -0
  332. solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
  333. solara/website/pages/documentation/components/layout/app_layout.py +24 -0
  334. solara/website/pages/documentation/components/layout/card.py +15 -0
  335. solara/website/pages/documentation/components/layout/card_actions.py +16 -0
  336. solara/website/pages/documentation/components/layout/column.py +30 -0
  337. solara/website/pages/documentation/components/layout/columns.py +27 -0
  338. solara/website/pages/documentation/components/layout/columns_responsive.py +66 -0
  339. solara/website/pages/documentation/components/layout/details.py +13 -0
  340. solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
  341. solara/website/pages/documentation/components/layout/gridfixed.py +19 -0
  342. solara/website/pages/documentation/components/layout/hbox.py +18 -0
  343. solara/website/pages/documentation/components/layout/row.py +30 -0
  344. solara/website/pages/documentation/components/layout/sidebar.py +24 -0
  345. solara/website/pages/documentation/components/layout/vbox.py +19 -0
  346. solara/website/pages/documentation/components/output/__init__.py +9 -0
  347. solara/website/pages/documentation/components/output/file_download.py +11 -0
  348. solara/website/pages/documentation/components/output/html.py +19 -0
  349. solara/website/pages/documentation/components/output/image.py +11 -0
  350. solara/website/pages/documentation/components/output/markdown.py +57 -0
  351. solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
  352. solara/website/pages/documentation/components/output/sql_code.py +83 -0
  353. solara/website/pages/documentation/components/output/tooltip.py +11 -0
  354. solara/website/pages/documentation/components/page/__init__.py +9 -0
  355. solara/website/pages/documentation/components/page/head.py +15 -0
  356. solara/website/pages/documentation/components/page/title.py +25 -0
  357. solara/website/pages/documentation/components/status/__init__.py +9 -0
  358. solara/website/pages/documentation/components/status/error.py +39 -0
  359. solara/website/pages/documentation/components/status/info.py +39 -0
  360. solara/website/pages/documentation/components/status/progress.py +10 -0
  361. solara/website/pages/documentation/components/status/spinner.py +11 -0
  362. solara/website/pages/documentation/components/status/success.py +40 -0
  363. solara/website/pages/documentation/components/status/warning.py +47 -0
  364. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  365. solara/website/pages/documentation/components/viz/altair.py +42 -0
  366. solara/website/pages/documentation/components/viz/echarts.py +77 -0
  367. solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
  368. solara/website/pages/documentation/components/viz/plotly.py +63 -0
  369. solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
  370. solara/website/pages/documentation/examples/__init__.py +54 -0
  371. solara/website/pages/documentation/examples/ai/__init__.py +11 -0
  372. solara/website/pages/documentation/examples/ai/chatbot.py +113 -0
  373. solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
  374. solara/website/pages/documentation/examples/basics/__init__.py +10 -0
  375. solara/website/pages/documentation/examples/basics/sine.py +28 -0
  376. solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
  377. solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
  378. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
  379. solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
  380. solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
  381. solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
  382. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
  383. solara/website/pages/documentation/examples/general/__init__.py +10 -0
  384. solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
  385. solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
  386. solara/website/pages/documentation/examples/general/live_update.py +32 -0
  387. solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
  388. solara/website/pages/documentation/examples/general/mycard.vue +58 -0
  389. solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
  390. solara/website/pages/documentation/examples/general/vue_component.py +50 -0
  391. solara/website/pages/documentation/examples/ipycanvas.py +49 -0
  392. solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
  393. solara/website/pages/documentation/examples/libraries/altair.py +65 -0
  394. solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
  395. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
  396. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
  397. solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
  398. solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
  399. solara/website/pages/documentation/examples/utilities/countdown_timer.py +62 -0
  400. solara/website/pages/documentation/examples/utilities/todo.py +196 -0
  401. solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
  402. solara/website/pages/documentation/examples/visualization/annotator.py +67 -0
  403. solara/website/pages/documentation/examples/visualization/linked_views.py +81 -0
  404. solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
  405. solara/website/pages/documentation/faq/__init__.py +12 -0
  406. solara/website/pages/documentation/faq/content/99-faq.md +112 -0
  407. solara/website/pages/documentation/getting_started/__init__.py +9 -0
  408. solara/website/pages/documentation/getting_started/content/00-quickstart.md +107 -0
  409. solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
  410. solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
  411. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
  412. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
  413. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
  414. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
  415. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
  416. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
  417. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +65 -0
  418. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  419. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
  420. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1021 -0
  421. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
  422. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +228 -0
  423. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +278 -0
  424. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
  425. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +305 -0
  426. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
  427. solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
  428. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
  429. solara/website/pages/docutils.py +38 -0
  430. solara/website/pages/home.vue +1199 -0
  431. solara/website/pages/our_team/__init__.py +83 -0
  432. solara/website/pages/pricing/__init__.py +31 -0
  433. solara/website/pages/roadmap/__init__.py +11 -0
  434. solara/website/pages/roadmap/roadmap.md +47 -0
  435. solara/website/pages/scale_ipywidgets.py +45 -0
  436. solara/website/pages/showcase/__init__.py +105 -0
  437. solara/website/pages/showcase/domino_code_assist.py +60 -0
  438. solara/website/pages/showcase/planeto_tessa.py +19 -0
  439. solara/website/pages/showcase/solara_dev.py +54 -0
  440. solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
  441. solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
  442. solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
  443. solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
  444. solara/website/pages/showcase/wanderlust.py +27 -0
  445. solara/website/public/beach.jpeg +0 -0
  446. solara/website/public/logo.svg +6 -0
  447. solara/website/public/social/discord.svg +1 -0
  448. solara/website/public/social/github.svg +1 -0
  449. solara/website/public/social/twitter.svg +3 -0
  450. solara/website/public/success.html +25 -0
  451. solara/website/templates/index.html.j2 +117 -0
  452. solara/website/utils.py +51 -0
  453. solara/widgets/__init__.py +1 -0
  454. solara/widgets/vue/gridlayout.vue +107 -0
  455. solara/widgets/vue/html.vue +4 -0
  456. solara/widgets/vue/navigator.vue +134 -0
  457. solara/widgets/vue/vegalite.vue +130 -0
  458. solara/widgets/widgets.py +74 -0
  459. solara_ui-1.45.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  460. solara_ui-1.45.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  461. solara_ui-1.45.0.dist-info/METADATA +162 -0
  462. solara_ui-1.45.0.dist-info/RECORD +464 -0
  463. solara_ui-1.45.0.dist-info/WHEEL +4 -0
  464. solara_ui-1.45.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <div ref="echarts" class="solara-echarts" v-bind="attributes"></div>
3
+ </template>
4
+ <script>
5
+ module.exports = {
6
+ mounted() {
7
+ const version = "5.4.0";
8
+ (async () => {
9
+ const echarts = (
10
+ await this.import([`${this.getCdn()}/echarts@${version}/dist/echarts.js`])
11
+ )[0];
12
+ this.echarts = echarts;
13
+ this.create();
14
+ })();
15
+ if(this.responsive){
16
+ this.resizeObserver = new ResizeObserver(entries => {
17
+ for (let entry of entries) {
18
+ if (entry.target === this.$refs.echarts) {
19
+ this.handleContainerResize();
20
+ }
21
+ }
22
+ });
23
+ this.resizeObserver.observe(this.$refs.echarts);
24
+ };
25
+ },
26
+ beforeDestroy() {
27
+ if (this.resizeObserver) {
28
+ this.resizeObserver.unobserve(this.$refs.echarts);
29
+ this.resizeObserver.disconnect();
30
+ }
31
+ },
32
+ watch: {
33
+ option() {
34
+ // notMerge, otherwise we're left with axes etc
35
+ // see https://echarts.apache.org/en/api.html#echartsInstance.setOption
36
+ this.chart.setOption(this.option, true);
37
+ },
38
+ },
39
+ methods: {
40
+ create() {
41
+ this.chart = this.echarts.init(this.$refs.echarts);
42
+ Object.keys(this.maps).forEach((mapName) => {
43
+ this.echarts.registerMap(mapName, this.maps[mapName]);
44
+ });
45
+
46
+ this.chart.setOption(this.option, true);
47
+ const eventProps = [
48
+ "componentType",
49
+ "seriesType",
50
+ "seriesIndex",
51
+ "seriesName",
52
+ "name",
53
+ "dataIndex",
54
+ "data",
55
+ "dataType",
56
+ "value",
57
+ "color",
58
+ ];
59
+ this.chart.on("click", (fullEvent) => {
60
+ const eventData = {};
61
+ eventProps.forEach((prop) => {
62
+ eventData[prop] = fullEvent[prop];
63
+ });
64
+ this.on_click(eventData);
65
+ });
66
+ this.chart.on("mouseover", (fullEvent) => {
67
+ const eventData = {};
68
+ eventProps.forEach((prop) => {
69
+ eventData[prop] = fullEvent[prop];
70
+ });
71
+ if (this.on_mouseover_enabled) this.on_mouseover(eventData);
72
+ });
73
+ this.chart.on("mouseout", (fullEvent) => {
74
+ const eventData = {};
75
+ eventProps.forEach((prop) => {
76
+ eventData[prop] = fullEvent[prop];
77
+ });
78
+ if (this.on_mouseout_enabled) this.on_mouseout(eventData);
79
+ });
80
+ },
81
+ handleContainerResize() {
82
+ if (this.chart) {
83
+ this.chart.resize();
84
+ }
85
+ },
86
+ import(deps) {
87
+ return this.loadRequire().then(() => {
88
+ if (window.jupyterVue) {
89
+ // in jupyterlab, we take Vue from ipyvue/jupyterVue
90
+ define("vue", [], () => window.jupyterVue.Vue);
91
+ } else {
92
+ define("vue", ["jupyter-vue"], (jupyterVue) => jupyterVue.Vue);
93
+ }
94
+ return new Promise((resolve, reject) => {
95
+ requirejs(deps, (...modules) => resolve(modules));
96
+ });
97
+ });
98
+ },
99
+ loadRequire() {
100
+ /* Needed in lab */
101
+ if (window.requirejs) {
102
+ console.log("require found");
103
+ return Promise.resolve();
104
+ }
105
+ return new Promise((resolve, reject) => {
106
+ const script = document.createElement("script");
107
+ script.src = `${this.getCdn()}/requirejs@2.3.6/require.js`;
108
+ script.onload = resolve;
109
+ script.onerror = reject;
110
+ document.head.appendChild(script);
111
+ });
112
+ },
113
+ getJupyterBaseUrl() {
114
+ // if base url is set, we use ./ for relative paths compared to the base url
115
+ if (document.getElementsByTagName("base").length) {
116
+ return "./";
117
+ }
118
+ const labConfigData = document.getElementById("jupyter-config-data");
119
+ if (labConfigData) {
120
+ /* lab and Voila */
121
+ return JSON.parse(labConfigData.textContent).baseUrl;
122
+ }
123
+ let base = document.body.dataset.baseUrl || document.baseURI;
124
+ if (!base.endsWith("/")) {
125
+ base += "/";
126
+ }
127
+ return base;
128
+ },
129
+ getCdn() {
130
+ return this.cdn || (window.solara ? window.solara.cdn : `${this.getJupyterBaseUrl()}_solara/cdn`);
131
+ },
132
+ },
133
+ };
134
+ </script>
135
+
136
+ <style id="solara-markdown-editor">
137
+ .solara-echarts {
138
+ }
139
+ </style>
@@ -0,0 +1,39 @@
1
+ from typing import Any, Callable
2
+
3
+ import solara
4
+ import solara.widgets
5
+
6
+
7
+ @solara.component
8
+ def FigureAltair(
9
+ chart,
10
+ on_click: Callable[[Any], None] = None,
11
+ on_hover: Callable[[Any], None] = None,
12
+ ):
13
+ """Renders an Altair chart using VegaLite.
14
+
15
+ See also [our altair example](/documentation/examples/libraries/altair).
16
+
17
+ ## Arguments
18
+
19
+ - chart: Altair chart
20
+ - on_click: Callback function for click events.
21
+ - on_hover: Callback function for hover events.
22
+
23
+ """
24
+ import altair as alt
25
+
26
+ with alt.renderers.enable("mimetype"):
27
+ bundle = chart._repr_mimebundle_()[0]
28
+ key4 = "application/vnd.vegalite.v4+json"
29
+ key5 = "application/vnd.vegalite.v5+json"
30
+ if key4 not in bundle and key5 not in bundle:
31
+ raise KeyError(f"{key4} and {key5} not in mimebundle:\n\n{bundle}")
32
+ spec = bundle.get(key5, bundle.get(key4))
33
+ return solara.widgets.VegaLite.element(
34
+ spec=spec, on_click=on_click, listen_to_click=on_click is not None, on_hover=on_hover, listen_to_hover=on_hover is not None
35
+ )
36
+
37
+
38
+ # alias for backward compatibility
39
+ AltairChart = FigureAltair
@@ -0,0 +1,181 @@
1
+ import os
2
+ from os.path import isfile, join
3
+ from pathlib import Path
4
+ from typing import Callable, Dict, List, Optional, Union, cast
5
+
6
+ import humanize
7
+ import ipyvuetify as vy
8
+ import traitlets
9
+
10
+ import solara
11
+ from solara.components import Div
12
+
13
+
14
+ def list_dir(path, filter: Callable[[Path], bool] = lambda x: True, directory_first: bool = False) -> List[dict]:
15
+ def mk_item(n):
16
+ full_path = join(path, n)
17
+ is_file = isfile(full_path)
18
+ return {"name": n, "is_file": is_file, "size": humanize.naturalsize(os.stat(full_path).st_size) if is_file else None}
19
+
20
+ files = [mk_item(k) for k in os.listdir(path) if not k.startswith(".") if filter(Path(path) / k)]
21
+ sorted_files = sorted(files, key=lambda item: (item["is_file"] == directory_first, item["name"].lower()))
22
+
23
+ return sorted_files
24
+
25
+
26
+ class FileListWidget(vy.VuetifyTemplate):
27
+ template_file = (__file__, "file_list_widget.vue")
28
+
29
+ files = traitlets.List(cast(List[Dict], [])).tag(sync=True)
30
+ clicked = traitlets.Dict(allow_none=True, default_value=None).tag(sync=True)
31
+ double_clicked = traitlets.Dict(allow_none=True, default_value=None).tag(sync=True)
32
+ scroll_pos = traitlets.Int(allow_none=True).tag(sync=True)
33
+
34
+ def test_click(self, path: Union[Path, str], double_click=False):
35
+ """Simulate a click or double click at the Python side"""
36
+ matches = [k for k in self.files if k["name"] == str(path)]
37
+ if len(matches) == 0:
38
+ names = [k["name"] for k in self.files]
39
+ raise NameError(f"Could not find {path}, possible filenames: {names}")
40
+ item = matches[0]
41
+ if double_click:
42
+ self.double_clicked = item
43
+ else:
44
+ self.clicked = item
45
+
46
+ def __contains__(self, name):
47
+ """Test if filename/directory name is in the current directory."""
48
+ return name in [k["name"] for k in self.files]
49
+
50
+
51
+ @solara.component
52
+ def FileBrowser(
53
+ directory: Union[None, str, Path, solara.Reactive[Path]] = None,
54
+ on_directory_change: Optional[Callable[[Path], None]] = None,
55
+ on_path_select: Optional[Callable[[Optional[Path]], None]] = None,
56
+ on_file_open: Optional[Callable[[Path], None]] = None,
57
+ filter: Callable[[Path], bool] = lambda x: True,
58
+ directory_first: bool = False,
59
+ on_file_name: Optional[Callable[[str], None]] = None,
60
+ start_directory=None,
61
+ can_select=False,
62
+ ):
63
+ """File/directory browser at the server side.
64
+
65
+ There are two modes possible
66
+
67
+ * `can_select=False`
68
+ * `on_file_open`: Triggered when **single** clicking a file or directory.
69
+ * `on_path_select`: Never triggered
70
+ * `on_directory_change`: Triggered when clicking a directory
71
+ * `can_select=True`
72
+ * `on_file_open`: Triggered when **double** clicking a file or directory.
73
+ * `on_path_select`: Triggered when clicking a file or directory
74
+ * `on_directory_change`: Triggered when double clicking a directory
75
+
76
+ ## Arguments
77
+
78
+ * `directory`: The directory to start in. If `None` the current working directory is used.
79
+ * `on_directory_change`: Depends on mode, see above.
80
+ * `on_path_select`: Depends on mode, see above.
81
+ * `on_file_open`: Depends on mode, see above.
82
+ * `filter`: A function that takes a `Path` and returns `True` if the file/directory should be shown.
83
+ * `directory_first`: If `True` directories are shown before files. Default: `False`.
84
+ * `on_file_name`: (deprecated) Use on_file_open instead.
85
+ * `start_directory`: (deprecated) Use directory instead.
86
+ """
87
+ if start_directory is not None:
88
+ directory = start_directory # pragma: no cover
89
+ if directory is None:
90
+ directory = os.getcwd() # pragma: no cover
91
+ if isinstance(directory, str):
92
+ directory = Path(directory)
93
+ current_dir = solara.use_reactive(directory)
94
+ selected, set_selected = solara.use_state(None)
95
+ double_clicked, set_double_clicked = solara.use_state(None)
96
+ warning, set_warning = solara.use_state(cast(Optional[str], None))
97
+ scroll_pos_stack, set_scroll_pos_stack = solara.use_state(cast(List[int], []))
98
+ scroll_pos, set_scroll_pos = solara.use_state(0)
99
+ selected, set_selected = solara.use_state(None)
100
+
101
+ def change_dir(new_dir: Path):
102
+ if os.access(new_dir, os.R_OK):
103
+ current_dir.value = new_dir
104
+ if on_directory_change:
105
+ on_directory_change(new_dir)
106
+ set_warning(None)
107
+ return True
108
+ else:
109
+ set_warning(f"[no read access to {new_dir}]")
110
+
111
+ def on_item(item, double_click):
112
+ if item is None:
113
+ if can_select and on_path_select:
114
+ on_path_select(None)
115
+ return
116
+ if item["name"] == "..":
117
+ new_dir = current_dir.value.parent
118
+ action_change_directory = (can_select and double_click) or (not can_select and not double_click)
119
+ if action_change_directory and change_dir(new_dir):
120
+ if scroll_pos_stack:
121
+ last_pos = scroll_pos_stack[-1]
122
+ set_scroll_pos_stack(scroll_pos_stack[:-1])
123
+ set_scroll_pos(last_pos)
124
+ set_selected(None)
125
+ set_double_clicked(None)
126
+ if on_path_select and can_select:
127
+ on_path_select(None)
128
+ if can_select and not double_click:
129
+ if on_path_select:
130
+ on_path_select(new_dir)
131
+ return
132
+
133
+ path = current_dir.value / item["name"]
134
+ is_file = item["is_file"]
135
+ if (can_select and double_click) or (not can_select and not double_click):
136
+ if is_file:
137
+ if on_file_open:
138
+ on_file_open(path)
139
+ if on_file_name is not None:
140
+ on_file_name(str(path))
141
+ else:
142
+ if change_dir(path):
143
+ set_scroll_pos_stack(scroll_pos_stack + [scroll_pos])
144
+ set_scroll_pos(0)
145
+ set_selected(None)
146
+ set_double_clicked(None)
147
+ if on_path_select and can_select:
148
+ on_path_select(None)
149
+ elif can_select and not double_click:
150
+ if on_path_select:
151
+ on_path_select(path)
152
+ else: # not can_select and double_click is ignored
153
+ raise RuntimeError("Combination should not happen") # pragma: no cover
154
+
155
+ def on_click(item):
156
+ set_selected(item)
157
+ on_item(item, False)
158
+
159
+ def on_double_click(item):
160
+ set_double_clicked(item)
161
+ if can_select:
162
+ on_item(item, True)
163
+ # otherwise we can ignore it, single click will handle it
164
+
165
+ files = [{"name": "..", "is_file": False}] + list_dir(current_dir.value, filter=filter, directory_first=directory_first)
166
+ with Div(class_="solara-file-browser") as main:
167
+ Div(children=[str(current_dir.value)])
168
+ FileListWidget.element(
169
+ files=files,
170
+ selected=selected,
171
+ clicked=selected,
172
+ on_clicked=on_click,
173
+ double_clicked=double_clicked,
174
+ on_double_clicked=on_double_click,
175
+ scroll_pos=scroll_pos,
176
+ on_scroll_pos=set_scroll_pos,
177
+ ).key("FileList")
178
+ if warning:
179
+ Div(style_="font-weight: bold; color: red", children=[warning])
180
+
181
+ return main
@@ -0,0 +1,199 @@
1
+ from pathlib import Path
2
+ from typing import BinaryIO, Callable, List, Optional, Union, cast
3
+
4
+ import ipyvuetify as vy
5
+ import ipywidgets as widgets
6
+ import traitlets
7
+
8
+ import solara
9
+
10
+
11
+ class FileDownloadWidget(vy.VuetifyTemplate):
12
+ template_file = (__file__, "download.vue")
13
+ children = traitlets.List(cast(List[solara.Element], [])).tag(sync=True, **widgets.widget_serialization)
14
+ filename = traitlets.Unicode().tag(sync=True)
15
+ bytes = traitlets.Bytes(None, allow_none=True).tag(sync=True)
16
+ mime_type = traitlets.Unicode("application/octet-stream").tag(sync=True)
17
+ request_download = traitlets.Bool(False).tag(sync=True)
18
+
19
+
20
+ @solara.component
21
+ def FileDownload(
22
+ data: Union[str, bytes, BinaryIO, Callable[[], Union[str, bytes, BinaryIO]]],
23
+ filename: Optional[str] = None,
24
+ label: Optional[str] = None,
25
+ icon_name: Optional[str] = "mdi-cloud-download-outline",
26
+ close_file: bool = True,
27
+ mime_type: str = "application/octet-stream",
28
+ string_encoding: str = "utf-8",
29
+ children=[],
30
+ ):
31
+ """Download a file or data.
32
+
33
+ ## Simple usage
34
+
35
+ By default, if no children are provided, a button is created with the label "Download: {filename}".
36
+
37
+ ```solara
38
+ import solara
39
+
40
+ data = "This is the content of the file"
41
+
42
+ @solara.component
43
+ def Page():
44
+ solara.FileDownload(data, filename="solara-download.txt", label="Download file")
45
+ ```
46
+
47
+ ## Advanced usage
48
+
49
+ If children are provided, they are displayed instead of the button. The children can be any solara component,
50
+ including a button, markdown text, or an image.
51
+
52
+ ```solara
53
+ import solara
54
+
55
+ data = "This is the content of the file"
56
+
57
+ @solara.component
58
+ def Page():
59
+ with solara.FileDownload(data, "solara-download-2.txt"):
60
+ solara.Markdown("Any text, or even an image")
61
+ solara.Image("https://solara.dev/static/public/beach.jpeg", width="200px")
62
+ ```
63
+
64
+ ## Custom button
65
+
66
+ If children are provided, they are displayed instead of the button. The children can be any solara component,
67
+ including a button, markdown text, or an image.
68
+
69
+ ```solara
70
+ import solara
71
+
72
+ data = "This is the content of the file"
73
+
74
+ @solara.component
75
+ def Page():
76
+ with solara.FileDownload(data, "solara-download-2.txt"):
77
+ solara.Button("Custom download button", icon_name="mdi-cloud-download-outline", color="primary")
78
+ ```
79
+
80
+ ## Usage with file
81
+
82
+ A file object can be used as data. The file will be closed after downloading by default.
83
+
84
+ ```solara
85
+ import solara
86
+ import pandas as pd
87
+
88
+ df = pd.DataFrame({"id": [1, 2, 3], "name": ["John", "Mary", "Bob"]})
89
+
90
+ @solara.component
91
+ def Page():
92
+ file_object = df.to_csv(index=False)
93
+ solara.FileDownload(file_object, "users.csv", mime_type="application/vnd.ms-excel")
94
+ ```
95
+
96
+ If a file like object is used, we try to base the filename on the file object.
97
+ ```solara
98
+ import solara
99
+ import solara.website.pages
100
+ import os
101
+
102
+ filename = os.path.dirname(solara.website.__file__) + "/public/beach.jpeg"
103
+
104
+ @solara.component
105
+ def Page():
106
+ # only open the file once by using use_memo
107
+ file_object = solara.use_memo(lambda: open(filename, "rb"), [])
108
+ # no filename is provided, but we can extract it from the file object
109
+ solara.FileDownload(file_object, mime_type="image/jpeg", close_file=False)
110
+ ```
111
+
112
+ ## Lazy reading
113
+
114
+ Not only is the data lazily uploaded to the browser, but also the data is only read when the download is requested.
115
+ This happens for files by default, but can also be used by passing in a callback function.
116
+
117
+ ```solara
118
+ import solara
119
+ import time
120
+
121
+ @solara.component
122
+ def Page():
123
+ def get_data():
124
+ # I run in a thread, so I can do some heavy processing
125
+ time.sleep(3)
126
+ # I only get called when the download is requested
127
+ return "This is the content of the file"
128
+ solara.FileDownload(get_data, "solara-lazy-download.txt")
129
+ ```
130
+
131
+ ## Arguments
132
+
133
+ * `data`: The data to download. Can be a string, bytes, or a file like object, or a function that returns one of these.
134
+ * `filename`: The name of the file the user will see as default when downloading (default name is "solara-download.dat").
135
+ If a file object is provided, the filename will be extracted from the file object if possible.
136
+ * `label`: The label of the button. If not provided, the label will be "Download: {filename}".
137
+ - `icon_name`: The name of the icon to display on the button ([Overview of available icons](https://pictogrammers.github.io/@mdi/font/4.9.95/)).
138
+ * `close_file`: If a file object is provided, close the file after downloading (default True).
139
+ * `mime_type`: The mime type of the file. If not provided, the mime type will be "application/octet-stream",
140
+ For instance setting it to "application/vnd.ms-excel" will allow the user OS to directly open the
141
+ file into Excel.
142
+ * `string_encoding`: The encoding to use when converting a string to bytes (default "utf-8").
143
+
144
+ ## Note on file size
145
+
146
+ Note that the data will be kept in memory when downloading.
147
+ If the file is large (>10 MB), and when using [Solara server](/documentation/advanced/understanding/solara-server), we recommend using the
148
+ [static files directory](/documentation/advanced/reference/static-files) instead.
149
+
150
+ """
151
+ request_download, set_request_download = solara.use_state(False)
152
+
153
+ # if the data changes, we 'reset'
154
+ def reset():
155
+ nonlocal request_download
156
+ request_download = False
157
+ set_request_download(False)
158
+
159
+ solara.use_memo(reset, [data])
160
+
161
+ # we only upload to the frontend if clicked
162
+ def get_data() -> Optional[bytes]:
163
+ if request_download:
164
+ if callable(data):
165
+ data_non_lazy = data()
166
+ else:
167
+ data_non_lazy = data
168
+ if hasattr(data_non_lazy, "read"):
169
+ if hasattr(data_non_lazy, "seek"):
170
+ if hasattr(data_non_lazy, "tell") and data_non_lazy.tell() != 0:
171
+ data_non_lazy.seek(0)
172
+ content = data_non_lazy.read() # type: ignore
173
+ if close_file:
174
+ data_non_lazy.close() # type: ignore
175
+ return content
176
+ elif isinstance(data_non_lazy, str):
177
+ return data_non_lazy.encode(string_encoding)
178
+ else:
179
+ return cast(bytes, data_non_lazy)
180
+ return None
181
+
182
+ bytes_result: solara.Result[Optional[bytes]] = solara.use_thread(get_data, dependencies=[request_download, data])
183
+ if filename is None and hasattr(data, "name"):
184
+ try:
185
+ filename = Path(data.name).name # type: ignore
186
+ except Exception:
187
+ pass
188
+ filename = filename or "solara-download.dat"
189
+ label = label or ("Download: " + filename)
190
+ FileDownloadWidget.element(
191
+ filename=filename,
192
+ bytes=bytes_result.value if bytes_result.state == solara.ResultState.FINISHED else None,
193
+ request_download=request_download,
194
+ on_request_download=set_request_download,
195
+ children=children or [solara.Button(label, loading=bytes_result.state == solara.ResultState.RUNNING, icon_name=icon_name)],
196
+ mime_type=mime_type,
197
+ )
198
+ if bytes_result.state == solara.ResultState.ERROR and bytes_result.error:
199
+ raise bytes_result.error