solara 1.30.0__py2.py3-none-any.whl → 1.31.0__py2.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 (439) hide show
  1. {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/METADATA +7 -42
  2. solara-1.31.0.dist-info/RECORD +5 -0
  3. {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/WHEEL +1 -1
  4. {solara/template/portal → solara-1.31.0.dist-info/licenses}/LICENSE +1 -1
  5. solara/__init__.py +0 -123
  6. solara/__main__.py +0 -734
  7. solara/alias.py +0 -6
  8. solara/autorouting.py +0 -554
  9. solara/cache.py +0 -294
  10. solara/checks.html +0 -71
  11. solara/checks.py +0 -224
  12. solara/comm.py +0 -28
  13. solara/components/__init__.py +0 -59
  14. solara/components/alert.py +0 -155
  15. solara/components/applayout.py +0 -393
  16. solara/components/button.py +0 -85
  17. solara/components/card.py +0 -87
  18. solara/components/checkbox.py +0 -50
  19. solara/components/code_highlight_css.py +0 -11
  20. solara/components/code_highlight_css.vue +0 -63
  21. solara/components/columns.py +0 -159
  22. solara/components/component_vue.py +0 -109
  23. solara/components/cross_filter.py +0 -335
  24. solara/components/dataframe.py +0 -546
  25. solara/components/datatable.py +0 -221
  26. solara/components/datatable.vue +0 -175
  27. solara/components/details.py +0 -21
  28. solara/components/download.vue +0 -35
  29. solara/components/echarts.py +0 -75
  30. solara/components/echarts.vue +0 -128
  31. solara/components/figure_altair.py +0 -39
  32. solara/components/file_browser.py +0 -182
  33. solara/components/file_download.py +0 -199
  34. solara/components/file_drop.py +0 -139
  35. solara/components/file_drop.vue +0 -83
  36. solara/components/file_list_widget.vue +0 -78
  37. solara/components/head.py +0 -27
  38. solara/components/head_tag.py +0 -49
  39. solara/components/head_tag.vue +0 -60
  40. solara/components/image.py +0 -173
  41. solara/components/input.py +0 -440
  42. solara/components/link.py +0 -55
  43. solara/components/markdown.py +0 -371
  44. solara/components/markdown_editor.py +0 -25
  45. solara/components/markdown_editor.vue +0 -362
  46. solara/components/matplotlib.py +0 -74
  47. solara/components/meta.py +0 -47
  48. solara/components/misc.py +0 -333
  49. solara/components/pivot_table.py +0 -258
  50. solara/components/pivot_table.vue +0 -158
  51. solara/components/progress.py +0 -47
  52. solara/components/select.py +0 -186
  53. solara/components/select.vue +0 -27
  54. solara/components/slider.py +0 -442
  55. solara/components/slider_date.vue +0 -56
  56. solara/components/spinner-solara.vue +0 -105
  57. solara/components/spinner.py +0 -30
  58. solara/components/sql_code.py +0 -33
  59. solara/components/sql_code.vue +0 -128
  60. solara/components/style.py +0 -105
  61. solara/components/switch.py +0 -68
  62. solara/components/tab_navigation.py +0 -37
  63. solara/components/title.py +0 -90
  64. solara/components/title.vue +0 -38
  65. solara/components/togglebuttons.py +0 -202
  66. solara/components/tooltip.py +0 -61
  67. solara/datatypes.py +0 -143
  68. solara/express.py +0 -241
  69. solara/hooks/__init__.py +0 -4
  70. solara/hooks/dataframe.py +0 -99
  71. solara/hooks/misc.py +0 -263
  72. solara/hooks/use_reactive.py +0 -129
  73. solara/hooks/use_thread.py +0 -129
  74. solara/kitchensink.py +0 -8
  75. solara/lab/__init__.py +0 -34
  76. solara/lab/components/__init__.py +0 -6
  77. solara/lab/components/chat.py +0 -203
  78. solara/lab/components/confirmation_dialog.py +0 -165
  79. solara/lab/components/cross_filter.py +0 -7
  80. solara/lab/components/input_date.py +0 -298
  81. solara/lab/components/menu.py +0 -181
  82. solara/lab/components/menu.vue +0 -38
  83. solara/lab/components/tabs.py +0 -274
  84. solara/lab/components/theming.py +0 -98
  85. solara/lab/components/theming.vue +0 -72
  86. solara/lab/hooks/__init__.py +0 -0
  87. solara/lab/hooks/dataframe.py +0 -12
  88. solara/lab/toestand.py +0 -3
  89. solara/lab/utils/__init__.py +0 -2
  90. solara/lab/utils/cookies.py +0 -5
  91. solara/lab/utils/dataframe.py +0 -115
  92. solara/lab/utils/headers.py +0 -5
  93. solara/layout.py +0 -44
  94. solara/minisettings.py +0 -133
  95. solara/py.typed +0 -0
  96. solara/reactive.py +0 -93
  97. solara/routing.py +0 -268
  98. solara/scope/__init__.py +0 -87
  99. solara/scope/types.py +0 -55
  100. solara/server/__init__.py +0 -0
  101. solara/server/app.py +0 -490
  102. solara/server/assets/custom.css +0 -1
  103. solara/server/assets/custom.js +0 -1
  104. solara/server/assets/favicon.png +0 -0
  105. solara/server/assets/favicon.svg +0 -5
  106. solara/server/assets/style.css +0 -1665
  107. solara/server/assets/theme-dark.css +0 -437
  108. solara/server/assets/theme-light.css +0 -420
  109. solara/server/assets/theme.js +0 -3
  110. solara/server/cdn_helper.py +0 -77
  111. solara/server/esm.py +0 -69
  112. solara/server/fastapi.py +0 -5
  113. solara/server/flask.py +0 -286
  114. solara/server/jupyter/__init__.py +0 -2
  115. solara/server/jupyter/cdn_handler.py +0 -28
  116. solara/server/jupyter/server_extension.py +0 -29
  117. solara/server/jupytertools.py +0 -46
  118. solara/server/kernel.py +0 -319
  119. solara/server/kernel_context.py +0 -393
  120. solara/server/patch.py +0 -552
  121. solara/server/reload.py +0 -242
  122. solara/server/server.py +0 -437
  123. solara/server/settings.py +0 -212
  124. solara/server/shell.py +0 -240
  125. solara/server/starlette.py +0 -597
  126. solara/server/static/ansi.js +0 -270
  127. solara/server/static/highlight-dark.css +0 -82
  128. solara/server/static/highlight.css +0 -43
  129. solara/server/static/main-vuetify.js +0 -260
  130. solara/server/static/main.js +0 -163
  131. solara/server/static/solara_bootstrap.py +0 -129
  132. solara/server/static/sun.svg +0 -23
  133. solara/server/static/webworker.js +0 -42
  134. solara/server/telemetry.py +0 -212
  135. solara/server/templates/index.html.j2 +0 -1
  136. solara/server/templates/loader-plain.css +0 -11
  137. solara/server/templates/loader-plain.html +0 -20
  138. solara/server/templates/loader-solara.css +0 -111
  139. solara/server/templates/loader-solara.html +0 -40
  140. solara/server/templates/plain.html +0 -82
  141. solara/server/templates/solara.html.j2 +0 -446
  142. solara/server/threaded.py +0 -75
  143. solara/server/utils.py +0 -30
  144. solara/server/websocket.py +0 -44
  145. solara/settings.py +0 -56
  146. solara/tasks.py +0 -847
  147. solara/template/button.py +0 -16
  148. solara/template/markdown.py +0 -42
  149. solara/template/portal/.flake8 +0 -6
  150. solara/template/portal/.pre-commit-config.yaml +0 -28
  151. solara/template/portal/Procfile +0 -7
  152. solara/template/portal/mypy.ini +0 -3
  153. solara/template/portal/pyproject.toml +0 -26
  154. solara/template/portal/solara_portal/__init__.py +0 -3
  155. solara/template/portal/solara_portal/components/__init__.py +0 -2
  156. solara/template/portal/solara_portal/components/article.py +0 -28
  157. solara/template/portal/solara_portal/components/data.py +0 -28
  158. solara/template/portal/solara_portal/components/header.py +0 -6
  159. solara/template/portal/solara_portal/components/layout.py +0 -6
  160. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +0 -85
  161. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +0 -70
  162. solara/template/portal/solara_portal/data.py +0 -60
  163. solara/template/portal/solara_portal/pages/__init__.py +0 -67
  164. solara/template/portal/solara_portal/pages/article/__init__.py +0 -26
  165. solara/template/portal/solara_portal/pages/tabular.py +0 -29
  166. solara/template/portal/solara_portal/pages/viz/__init__.py +0 -69
  167. solara/template/portal/solara_portal/pages/viz/overview.py +0 -14
  168. solara/test/__init__.py +0 -0
  169. solara/test/pytest_plugin.py +0 -698
  170. solara/toestand.py +0 -772
  171. solara/util.py +0 -308
  172. solara/website/__init__.py +0 -0
  173. solara/website/assets/custom.css +0 -462
  174. solara/website/assets/images/logo-small.png +0 -0
  175. solara/website/assets/images/logo.svg +0 -17
  176. solara/website/assets/images/logo_white.svg +0 -50
  177. solara/website/assets/theme.js +0 -8
  178. solara/website/components/__init__.py +0 -5
  179. solara/website/components/algolia.vue +0 -24
  180. solara/website/components/algolia_api.vue +0 -157
  181. solara/website/components/docs.py +0 -118
  182. solara/website/components/header.py +0 -72
  183. solara/website/components/hero.py +0 -15
  184. solara/website/components/mailchimp.py +0 -12
  185. solara/website/components/mailchimp.vue +0 -47
  186. solara/website/components/notebook.py +0 -172
  187. solara/website/pages/__init__.py +0 -564
  188. solara/website/pages/apps/__init__.py +0 -16
  189. solara/website/pages/apps/authorization/__init__.py +0 -118
  190. solara/website/pages/apps/authorization/admin.py +0 -12
  191. solara/website/pages/apps/authorization/users.py +0 -12
  192. solara/website/pages/apps/jupyter-dashboard-1.py +0 -116
  193. solara/website/pages/apps/layout-demo.py +0 -40
  194. solara/website/pages/apps/multipage/__init__.py +0 -38
  195. solara/website/pages/apps/multipage/page1.py +0 -26
  196. solara/website/pages/apps/multipage/page2.py +0 -34
  197. solara/website/pages/apps/scatter.py +0 -136
  198. solara/website/pages/apps/scrolling.py +0 -63
  199. solara/website/pages/apps/tutorial-streamlit.py +0 -18
  200. solara/website/pages/changelog/__init__.py +0 -8
  201. solara/website/pages/changelog/changelog.md +0 -180
  202. solara/website/pages/contact/__init__.py +0 -8
  203. solara/website/pages/contact/contact.md +0 -17
  204. solara/website/pages/doc_use_download.py +0 -85
  205. solara/website/pages/documentation/__init__.py +0 -184
  206. solara/website/pages/documentation/advanced/__init__.py +0 -36
  207. solara/website/pages/documentation/advanced/content/00-overview.md +0 -1
  208. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +0 -1
  209. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +0 -191
  210. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +0 -120
  211. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +0 -149
  212. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +0 -66
  213. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +0 -43
  214. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +0 -120
  215. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +0 -4
  216. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +0 -30
  217. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +0 -38
  218. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +0 -24
  219. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +0 -104
  220. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +0 -19
  221. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +0 -3
  222. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +0 -160
  223. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +0 -13
  224. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +0 -236
  225. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +0 -81
  226. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +0 -7
  227. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +0 -1
  228. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +0 -167
  229. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  230. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +0 -41
  231. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +0 -72
  232. solara/website/pages/documentation/advanced/content/__init__.py +0 -0
  233. solara/website/pages/documentation/api/__init__.py +0 -19
  234. solara/website/pages/documentation/api/cross_filter/__init__.py +0 -9
  235. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +0 -23
  236. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +0 -22
  237. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +0 -22
  238. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +0 -22
  239. solara/website/pages/documentation/api/hooks/__init__.py +0 -9
  240. solara/website/pages/documentation/api/hooks/use_cross_filter.py +0 -25
  241. solara/website/pages/documentation/api/hooks/use_dark_effective.py +0 -13
  242. solara/website/pages/documentation/api/hooks/use_effect.md +0 -43
  243. solara/website/pages/documentation/api/hooks/use_effect.py +0 -9
  244. solara/website/pages/documentation/api/hooks/use_exception.py +0 -33
  245. solara/website/pages/documentation/api/hooks/use_memo.md +0 -16
  246. solara/website/pages/documentation/api/hooks/use_memo.py +0 -9
  247. solara/website/pages/documentation/api/hooks/use_previous.py +0 -32
  248. solara/website/pages/documentation/api/hooks/use_reactive.py +0 -15
  249. solara/website/pages/documentation/api/hooks/use_state.py +0 -11
  250. solara/website/pages/documentation/api/hooks/use_state_or_update.py +0 -68
  251. solara/website/pages/documentation/api/hooks/use_thread.md +0 -58
  252. solara/website/pages/documentation/api/hooks/use_thread.py +0 -44
  253. solara/website/pages/documentation/api/hooks/use_trait_observe.py +0 -13
  254. solara/website/pages/documentation/api/routing/__init__.py +0 -9
  255. solara/website/pages/documentation/api/routing/generate_routes.py +0 -11
  256. solara/website/pages/documentation/api/routing/generate_routes_directory.py +0 -11
  257. solara/website/pages/documentation/api/routing/resolve_path.py +0 -36
  258. solara/website/pages/documentation/api/routing/route.py +0 -32
  259. solara/website/pages/documentation/api/routing/use_route.py +0 -80
  260. solara/website/pages/documentation/api/routing/use_router.py +0 -15
  261. solara/website/pages/documentation/api/utilities/__init__.py +0 -9
  262. solara/website/pages/documentation/api/utilities/component_vue.py +0 -11
  263. solara/website/pages/documentation/api/utilities/computed.py +0 -16
  264. solara/website/pages/documentation/api/utilities/display.py +0 -15
  265. solara/website/pages/documentation/api/utilities/get_kernel_id.py +0 -16
  266. solara/website/pages/documentation/api/utilities/get_session_id.py +0 -16
  267. solara/website/pages/documentation/api/utilities/memoize.py +0 -36
  268. solara/website/pages/documentation/api/utilities/on_kernel_start.py +0 -27
  269. solara/website/pages/documentation/api/utilities/reactive.py +0 -15
  270. solara/website/pages/documentation/api/utilities/widget.py +0 -104
  271. solara/website/pages/documentation/components/__init__.py +0 -12
  272. solara/website/pages/documentation/components/advanced/__init__.py +0 -9
  273. solara/website/pages/documentation/components/advanced/link.py +0 -28
  274. solara/website/pages/documentation/components/advanced/meta.py +0 -21
  275. solara/website/pages/documentation/components/advanced/style.py +0 -44
  276. solara/website/pages/documentation/components/common.py +0 -9
  277. solara/website/pages/documentation/components/data/__init__.py +0 -9
  278. solara/website/pages/documentation/components/data/dataframe.py +0 -44
  279. solara/website/pages/documentation/components/data/pivot_table.py +0 -81
  280. solara/website/pages/documentation/components/enterprise/__init__.py +0 -9
  281. solara/website/pages/documentation/components/enterprise/avatar.py +0 -19
  282. solara/website/pages/documentation/components/enterprise/avatar_menu.py +0 -20
  283. solara/website/pages/documentation/components/input/__init__.py +0 -9
  284. solara/website/pages/documentation/components/input/button.py +0 -22
  285. solara/website/pages/documentation/components/input/checkbox.py +0 -12
  286. solara/website/pages/documentation/components/input/file_browser.py +0 -33
  287. solara/website/pages/documentation/components/input/file_drop.py +0 -75
  288. solara/website/pages/documentation/components/input/input.py +0 -18
  289. solara/website/pages/documentation/components/input/select.py +0 -21
  290. solara/website/pages/documentation/components/input/slider.py +0 -28
  291. solara/website/pages/documentation/components/input/switch.py +0 -12
  292. solara/website/pages/documentation/components/input/togglebuttons.py +0 -20
  293. solara/website/pages/documentation/components/lab/__init__.py +0 -9
  294. solara/website/pages/documentation/components/lab/chat.py +0 -108
  295. solara/website/pages/documentation/components/lab/confirmation_dialog.py +0 -55
  296. solara/website/pages/documentation/components/lab/cookies_headers.py +0 -48
  297. solara/website/pages/documentation/components/lab/input_date.py +0 -19
  298. solara/website/pages/documentation/components/lab/menu.py +0 -21
  299. solara/website/pages/documentation/components/lab/tab.py +0 -24
  300. solara/website/pages/documentation/components/lab/tabs.py +0 -44
  301. solara/website/pages/documentation/components/lab/task.py +0 -12
  302. solara/website/pages/documentation/components/lab/theming.py +0 -72
  303. solara/website/pages/documentation/components/lab/use_task.py +0 -12
  304. solara/website/pages/documentation/components/layout/__init__.py +0 -9
  305. solara/website/pages/documentation/components/layout/app_bar.py +0 -15
  306. solara/website/pages/documentation/components/layout/app_bar_title.py +0 -15
  307. solara/website/pages/documentation/components/layout/app_layout.py +0 -23
  308. solara/website/pages/documentation/components/layout/card.py +0 -14
  309. solara/website/pages/documentation/components/layout/card_actions.py +0 -15
  310. solara/website/pages/documentation/components/layout/column.py +0 -29
  311. solara/website/pages/documentation/components/layout/columns.py +0 -26
  312. solara/website/pages/documentation/components/layout/columns_responsive.py +0 -67
  313. solara/website/pages/documentation/components/layout/griddraggable.py +0 -61
  314. solara/website/pages/documentation/components/layout/gridfixed.py +0 -21
  315. solara/website/pages/documentation/components/layout/hbox.py +0 -17
  316. solara/website/pages/documentation/components/layout/row.py +0 -29
  317. solara/website/pages/documentation/components/layout/sidebar.py +0 -23
  318. solara/website/pages/documentation/components/layout/vbox.py +0 -19
  319. solara/website/pages/documentation/components/output/__init__.py +0 -9
  320. solara/website/pages/documentation/components/output/file_download.py +0 -12
  321. solara/website/pages/documentation/components/output/html.py +0 -22
  322. solara/website/pages/documentation/components/output/image.py +0 -12
  323. solara/website/pages/documentation/components/output/markdown.py +0 -59
  324. solara/website/pages/documentation/components/output/markdown_editor.py +0 -53
  325. solara/website/pages/documentation/components/output/sql_code.py +0 -84
  326. solara/website/pages/documentation/components/output/tooltip.py +0 -12
  327. solara/website/pages/documentation/components/page/__init__.py +0 -9
  328. solara/website/pages/documentation/components/page/head.py +0 -19
  329. solara/website/pages/documentation/components/page/title.py +0 -28
  330. solara/website/pages/documentation/components/status/__init__.py +0 -9
  331. solara/website/pages/documentation/components/status/error.py +0 -40
  332. solara/website/pages/documentation/components/status/info.py +0 -40
  333. solara/website/pages/documentation/components/status/progress.py +0 -10
  334. solara/website/pages/documentation/components/status/spinner.py +0 -10
  335. solara/website/pages/documentation/components/status/success.py +0 -40
  336. solara/website/pages/documentation/components/status/warning.py +0 -47
  337. solara/website/pages/documentation/components/viz/__init__.py +0 -9
  338. solara/website/pages/documentation/components/viz/altair.py +0 -44
  339. solara/website/pages/documentation/components/viz/echarts.py +0 -78
  340. solara/website/pages/documentation/components/viz/matplotlib.py +0 -32
  341. solara/website/pages/documentation/components/viz/plotly.py +0 -63
  342. solara/website/pages/documentation/components/viz/plotly_express.py +0 -41
  343. solara/website/pages/documentation/examples/__init__.py +0 -52
  344. solara/website/pages/documentation/examples/ai/__init__.py +0 -10
  345. solara/website/pages/documentation/examples/ai/chatbot.py +0 -96
  346. solara/website/pages/documentation/examples/ai/tokenizer.py +0 -106
  347. solara/website/pages/documentation/examples/basics/__init__.py +0 -2
  348. solara/website/pages/documentation/examples/basics/sine.py +0 -28
  349. solara/website/pages/documentation/examples/fullscreen/__init__.py +0 -9
  350. solara/website/pages/documentation/examples/fullscreen/authorization.py +0 -3
  351. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +0 -3
  352. solara/website/pages/documentation/examples/fullscreen/multipage.py +0 -3
  353. solara/website/pages/documentation/examples/fullscreen/scatter.py +0 -3
  354. solara/website/pages/documentation/examples/fullscreen/scrolling.py +0 -3
  355. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +0 -3
  356. solara/website/pages/documentation/examples/general/__init__.py +0 -9
  357. solara/website/pages/documentation/examples/general/custom_storage.py +0 -69
  358. solara/website/pages/documentation/examples/general/deploy_model.py +0 -114
  359. solara/website/pages/documentation/examples/general/live_update.py +0 -38
  360. solara/website/pages/documentation/examples/general/login_oauth.py +0 -76
  361. solara/website/pages/documentation/examples/general/mycard.vue +0 -58
  362. solara/website/pages/documentation/examples/general/pokemon_search.py +0 -51
  363. solara/website/pages/documentation/examples/general/vue_component.py +0 -50
  364. solara/website/pages/documentation/examples/ipycanvas.py +0 -49
  365. solara/website/pages/documentation/examples/libraries/__init__.py +0 -9
  366. solara/website/pages/documentation/examples/libraries/altair.py +0 -63
  367. solara/website/pages/documentation/examples/libraries/bqplot.py +0 -39
  368. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +0 -32
  369. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +0 -65
  370. solara/website/pages/documentation/examples/utilities/__init__.py +0 -9
  371. solara/website/pages/documentation/examples/utilities/calculator.py +0 -157
  372. solara/website/pages/documentation/examples/utilities/countdown_timer.py +0 -64
  373. solara/website/pages/documentation/examples/utilities/todo.py +0 -195
  374. solara/website/pages/documentation/examples/visualization/__init__.py +0 -6
  375. solara/website/pages/documentation/examples/visualization/annotator.py +0 -68
  376. solara/website/pages/documentation/examples/visualization/linked_views.py +0 -84
  377. solara/website/pages/documentation/examples/visualization/plotly.py +0 -43
  378. solara/website/pages/documentation/faq/__init__.py +0 -11
  379. solara/website/pages/documentation/faq/content/99-faq.md +0 -73
  380. solara/website/pages/documentation/getting_started/__init__.py +0 -15
  381. solara/website/pages/documentation/getting_started/content/00-quickstart.md +0 -84
  382. solara/website/pages/documentation/getting_started/content/01-introduction.md +0 -121
  383. solara/website/pages/documentation/getting_started/content/02-installing.md +0 -81
  384. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +0 -9
  385. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +0 -13
  386. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +0 -84
  387. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +0 -120
  388. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +0 -141
  389. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +0 -140
  390. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +0 -64
  391. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  392. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +0 -445
  393. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +0 -1000
  394. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +0 -7
  395. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +0 -218
  396. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +0 -83
  397. solara/website/pages/documentation/getting_started/content/06-reference/00-overview.md +0 -3
  398. solara/website/pages/documentation/getting_started/content/06-reference/40-static_files.md +0 -27
  399. solara/website/pages/documentation/getting_started/content/06-reference/41-asset-files.md +0 -32
  400. solara/website/pages/documentation/getting_started/content/06-reference/60-static-site-generation.md +0 -55
  401. solara/website/pages/documentation/getting_started/content/06-reference/70-search.md +0 -30
  402. solara/website/pages/documentation/getting_started/content/06-reference/80-reloading.md +0 -30
  403. solara/website/pages/documentation/getting_started/content/06-reference/90-notebook-support.md +0 -4
  404. solara/website/pages/documentation/getting_started/content/06-reference/95-caching.md +0 -143
  405. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +0 -3
  406. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +0 -269
  407. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +0 -76
  408. solara/website/pages/documentation/getting_started/content/08-lab/00-what-is-lab.md +0 -3
  409. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +0 -22
  410. solara/website/pages/documentation/getting_started/content/__init__.py +0 -0
  411. solara/website/pages/docutils.py +0 -38
  412. solara/website/pages/showcase/__init__.py +0 -105
  413. solara/website/pages/showcase/domino_code_assist.py +0 -60
  414. solara/website/pages/showcase/planeto_tessa.py +0 -19
  415. solara/website/pages/showcase/solara_dev.py +0 -54
  416. solara/website/pages/showcase/solarathon_2023_team_2.py +0 -22
  417. solara/website/pages/showcase/solarathon_2023_team_4.py +0 -22
  418. solara/website/pages/showcase/solarathon_2023_team_5.py +0 -23
  419. solara/website/pages/showcase/solarathon_2023_team_6.py +0 -34
  420. solara/website/pages/showcase/wanderlust.py +0 -27
  421. solara/website/public/beach.jpeg +0 -0
  422. solara/website/public/logo.svg +0 -6
  423. solara/website/public/social/discord.svg +0 -1
  424. solara/website/public/social/github.svg +0 -1
  425. solara/website/public/social/twitter.svg +0 -3
  426. solara/website/public/success.html +0 -25
  427. solara/website/templates/index.html.j2 +0 -117
  428. solara/website/utils.py +0 -51
  429. solara/widgets/__init__.py +0 -1
  430. solara/widgets/vue/gridlayout.vue +0 -110
  431. solara/widgets/vue/html.vue +0 -4
  432. solara/widgets/vue/navigator.vue +0 -104
  433. solara/widgets/vue/vegalite.vue +0 -115
  434. solara/widgets/widgets.py +0 -65
  435. solara-1.30.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -7
  436. solara-1.30.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -7
  437. solara-1.30.0.dist-info/RECORD +0 -438
  438. solara-1.30.0.dist-info/entry_points.txt +0 -5
  439. /solara-1.30.0.dist-info/licenses/LICENSE → /LICENSE +0 -0
solara/tasks.py DELETED
@@ -1,847 +0,0 @@
1
- import abc
2
- import asyncio
3
- import dataclasses
4
- import inspect
5
- import logging
6
- import threading
7
- from enum import Enum
8
- from typing import (
9
- Any,
10
- Callable,
11
- Coroutine,
12
- Generic,
13
- List,
14
- Optional,
15
- TypeVar,
16
- Union,
17
- cast,
18
- overload,
19
- )
20
-
21
- import typing_extensions
22
-
23
- import solara
24
- import solara.util
25
- from solara.toestand import Singleton
26
-
27
- from .toestand import Ref as ref
28
-
29
- R = TypeVar("R")
30
- T = TypeVar("T")
31
- P = typing_extensions.ParamSpec("P")
32
-
33
- logger = logging.getLogger("solara.task")
34
-
35
- has_threads = solara.util.has_threads
36
-
37
-
38
- class TaskState(Enum):
39
- NOTCALLED = 1
40
- STARTING = 2
41
- WAITING = 3
42
- RUNNING = 4
43
- ERROR = 5
44
- FINISHED = 6
45
- CANCELLED = 7
46
-
47
-
48
- @dataclasses.dataclass(frozen=True)
49
- class TaskResult(Generic[T]):
50
- value: Optional[T] = None
51
- latest: Optional[T] = None
52
- exception: Optional[Exception] = None
53
- # only useful if you want to know details about the state like STARTING or WAITING
54
- _state: TaskState = TaskState.NOTCALLED
55
- progress: Optional[float] = None
56
-
57
- @property
58
- def not_called(self):
59
- return self._state == TaskState.NOTCALLED
60
-
61
- @property
62
- def pending(self):
63
- return self._state in (TaskState.STARTING, TaskState.WAITING, TaskState.RUNNING)
64
-
65
- @property
66
- def finished(self):
67
- return self._state == TaskState.FINISHED
68
-
69
- @property
70
- def cancelled(self):
71
- return self._state == TaskState.CANCELLED
72
-
73
- @property
74
- def error(self):
75
- return self._state == TaskState.ERROR
76
-
77
-
78
- class Task(Generic[P, R], abc.ABC):
79
- def __init__(self):
80
- self._result = solara.reactive(
81
- TaskResult[R](
82
- value=None,
83
- _state=TaskState.NOTCALLED,
84
- )
85
- )
86
- self._last_value: Optional[R] = None
87
- self._last_progress: Optional[float] = None
88
- self._latest = ref(self._result.fields.latest)
89
- self._value = ref(self._result.fields.value)
90
- self._error = ref(self._result.fields.error)
91
- self._finished = ref(self._result.fields.finished)
92
- self._cancelled = ref(self._result.fields.cancelled)
93
- self._pending = ref(self._result.fields.pending)
94
- self._not_called = ref(self._result.fields.not_called)
95
- self._progress = ref(self._result.fields.progress)
96
- self._exception = ref(self._result.fields.exception)
97
- self._state_ = ref(self._result.fields._state)
98
-
99
- @property
100
- def result(self) -> TaskResult[R]:
101
- return self._result.value
102
-
103
- @property
104
- def latest(self) -> Optional[R]:
105
- return self._latest.value
106
-
107
- @property
108
- def value(self) -> Optional[R]:
109
- return self._value.value
110
-
111
- @property
112
- def _state(self) -> TaskState:
113
- return self._state_.value
114
-
115
- @property
116
- def error(self) -> bool:
117
- return self._error.value
118
-
119
- @property
120
- def finished(self) -> bool:
121
- return self._finished.value
122
-
123
- @property
124
- def cancelled(self) -> bool:
125
- return self._cancelled.value
126
-
127
- @property
128
- def pending(self) -> bool:
129
- return self._pending.value
130
-
131
- @property
132
- def not_called(self) -> bool:
133
- return self._not_called.value
134
-
135
- @property
136
- def progress(self) -> Optional[float]:
137
- return self._progress.value
138
-
139
- @progress.setter
140
- def progress(self, value: Optional[float]) -> None:
141
- self._last_progress = value
142
- self._progress.value = value
143
-
144
- @property
145
- def exception(self) -> Optional[Exception]:
146
- return self._exception.value
147
-
148
- @abc.abstractmethod
149
- def retry(self) -> None:
150
- ...
151
-
152
- @abc.abstractmethod
153
- def cancel(self) -> None:
154
- ...
155
-
156
- @abc.abstractmethod
157
- def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None:
158
- ...
159
-
160
- @abc.abstractmethod
161
- def is_current(self) -> bool:
162
- ...
163
-
164
- def _prestart(self):
165
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.STARTING)
166
-
167
-
168
- class _CancelledErrorInOurTask(BaseException):
169
- pass
170
-
171
-
172
- class TaskAsyncio(Task[P, R]):
173
- current_task: Optional[asyncio.Task] = None
174
- current_future: Optional[asyncio.Future] = None
175
- _cancel: Optional[Callable[[], None]] = None
176
- _retry: Optional[Callable[[], None]] = None
177
-
178
- def __init__(self, run_in_thread: bool, function: Callable[P, Coroutine[Any, Any, R]]):
179
- self.run_in_thread = run_in_thread
180
- self.function = function
181
- super().__init__()
182
-
183
- def cancel(self) -> None:
184
- if self._cancel:
185
- self._cancel()
186
- else:
187
- raise RuntimeError("Cannot cancel task, never started")
188
-
189
- def retry(self):
190
- if self._retry:
191
- self._retry()
192
- else:
193
- raise RuntimeError("Cannot retry task, never started")
194
-
195
- def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None:
196
- self.current_future = future = asyncio.Future[R]()
197
- self._last_progress = None
198
- current_task: asyncio.Task[None]
199
- if self.current_task:
200
- self.current_task.cancel()
201
-
202
- def retry():
203
- self(*args, **kwargs)
204
-
205
- def cancel():
206
- event_loop = current_task.get_loop()
207
- # cancel after cancel is a no-op
208
- self._cancel = lambda: None
209
- if asyncio.current_task() == current_task:
210
- if event_loop == asyncio.get_event_loop():
211
- # we got called in our own task and event loop
212
- raise _CancelledErrorInOurTask()
213
- else:
214
- current_task.cancel()
215
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.CANCELLED)
216
- else:
217
- current_task.cancel()
218
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.CANCELLED)
219
-
220
- self._cancel = cancel
221
- self._retry = retry
222
- call_event_loop = asyncio.get_event_loop()
223
-
224
- if self.run_in_thread:
225
- thread_event_loop = asyncio.new_event_loop()
226
- self.current_task = current_task = thread_event_loop.create_task(self._async_run(call_event_loop, future, args, kwargs))
227
-
228
- def runs_in_thread():
229
- try:
230
- thread_event_loop.run_until_complete(current_task)
231
- except asyncio.CancelledError as e:
232
- call_event_loop.call_soon_threadsafe(future.set_exception, e)
233
- except Exception as e:
234
- logger.exception("error running in thread")
235
- call_event_loop.call_soon_threadsafe(future.set_exception, e)
236
- raise
237
-
238
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.STARTING)
239
- thread = threading.Thread(target=runs_in_thread)
240
- thread.start()
241
- else:
242
- self.current_task = current_task = asyncio.create_task(self._async_run(call_event_loop, future, args, kwargs))
243
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.STARTING)
244
-
245
- def is_current(self):
246
- running_task = self.current_task
247
- assert running_task is not None
248
- return (self.current_task == asyncio.current_task()) and not running_task.cancelled()
249
-
250
- async def _async_run(self, call_event_loop: asyncio.AbstractEventLoop, future: asyncio.Future, args, kwargs) -> None:
251
- task_for_this_call = asyncio.current_task()
252
- assert task_for_this_call is not None
253
-
254
- if self.is_current():
255
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.STARTING)
256
-
257
- async def runner():
258
- try:
259
- if self.is_current():
260
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.RUNNING)
261
- self._last_value = value = await self.function(*args, **kwargs)
262
- if self.is_current() and not task_for_this_call.cancelled(): # type: ignore
263
- self._result.value = TaskResult[R](value=value, latest=value, _state=TaskState.FINISHED, progress=self._last_progress)
264
- logger.info("setting result to %r", value)
265
- call_event_loop.call_soon_threadsafe(future.set_result, value)
266
- except Exception as e:
267
- if self.is_current():
268
- logger.exception(e)
269
- self._result.value = TaskResult[R](latest=self._last_value, exception=e, _state=TaskState.ERROR)
270
- call_event_loop.call_soon_threadsafe(future.set_exception, e)
271
- # Although this seems like an easy way to handle cancellation, an early cancelled task will never execute
272
- # so this code will never execute, so we need to handle this in the cancel function in __call__
273
- # except asyncio.CancelledError as e:
274
- # if self.is_current():
275
- # self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.CANCELLED)
276
- # call_event_loop.call_soon_threadsafe(future.set_exception, e)
277
- # But... if we call cancel in our own task, we still need to do it from this place
278
- except _CancelledErrorInOurTask as e:
279
- try:
280
- # maybe there is a different way to get a full stack trace?
281
- raise asyncio.CancelledError() from e
282
- except asyncio.CancelledError as e:
283
- if self.is_current():
284
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.CANCELLED)
285
- call_event_loop.call_soon_threadsafe(future.set_exception, e)
286
-
287
- await runner()
288
-
289
-
290
- class TaskThreaded(Task[P, R]):
291
- _current_cancel_event: Optional[threading.Event] = None
292
- _current_thread: Optional[threading.Thread] = None
293
- _last_finished_event: Optional[threading.Event] = None
294
- _cancel: Optional[Callable[[], None]] = None
295
- _retry: Optional[Callable[[], None]] = None
296
-
297
- def __init__(self, function: Callable[P, R]):
298
- super().__init__()
299
- self.__qualname__ = function.__qualname__
300
- self.function = function
301
- self.lock = threading.Lock()
302
-
303
- def cancel(self) -> None:
304
- if self._cancel:
305
- self._cancel()
306
- else:
307
- raise RuntimeError("Cannot cancel task, never started")
308
-
309
- def retry(self):
310
- if self._retry:
311
- self._retry()
312
- else:
313
- raise RuntimeError("Cannot retry task, never started")
314
-
315
- def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None:
316
- self._last_finished_event = _last_finished_event = threading.Event()
317
- self._current_cancel_event = cancel_event = threading.Event()
318
- self._last_progress = None
319
-
320
- def retry():
321
- self(*args, **kwargs)
322
-
323
- def cancel():
324
- cancel_event.set()
325
- if threading.current_thread() == current_thread:
326
- raise solara.util.CancelledError()
327
- self._current_cancel_event = None
328
-
329
- self._retry = retry
330
- self._cancel = cancel
331
-
332
- with self.lock:
333
- previous_thread = self._current_thread
334
- self._current_thread = current_thread = threading.Thread(
335
- target=lambda: self._run(_last_finished_event, previous_thread, cancel_event, args, kwargs), daemon=False
336
- )
337
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.STARTING)
338
- current_thread.start()
339
-
340
- def is_current(self):
341
- return self._current_thread == threading.current_thread()
342
-
343
- def _run(self, _last_finished_event, previous_thread: Optional[threading.Thread], cancel_event, args, kwargs) -> None:
344
- # use_thread has this as default, which can make code run 10x slower
345
- intrusive_cancel = False
346
- wait_on_previous = False
347
-
348
- def runner():
349
- if wait_on_previous:
350
- if previous_thread and previous_thread.is_alive():
351
- if self.is_current():
352
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.WAITING)
353
- # don't start before the previous is stopped
354
- try:
355
- previous_thread.join()
356
- except: # noqa
357
- pass
358
- if self.is_current():
359
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.RUNNING)
360
- else:
361
- # early stop
362
- return
363
-
364
- callback = self.function
365
- try:
366
- guard = solara.util.cancel_guard(cancel_event) if intrusive_cancel else solara.util.nullcontext()
367
- try:
368
- # we only use the cancel_guard context manager around
369
- # the function calls to f. We don't want to guard around
370
- # a call to react, since that might slow down rendering
371
- # during rendering
372
- with guard:
373
- if self.is_current():
374
- value = callback(*args, **kwargs)
375
- if inspect.isgenerator(value):
376
- generator = value
377
- self._last_value = None
378
- while True:
379
- try:
380
- with guard:
381
- self._last_value = value = next(generator)
382
- if self.is_current():
383
- self._result.value = TaskResult[R](latest=value, value=value, _state=TaskState.RUNNING, progress=self._last_progress)
384
- except StopIteration:
385
- break
386
- if self.is_current():
387
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.FINISHED, progress=self._last_progress)
388
- else:
389
- self._last_value = value
390
- if self.is_current():
391
- self._result.value = TaskResult[R](latest=value, value=value, _state=TaskState.FINISHED, progress=self._last_progress)
392
- except Exception as e:
393
- if self.is_current():
394
- logger.exception(e)
395
- self._last_value = None
396
- self._result.value = TaskResult[R](latest=self._last_value, exception=e, _state=TaskState.ERROR)
397
- return
398
- except solara.util.CancelledError:
399
- pass
400
- # this means this thread is cancelled not be request, but because
401
- # a new thread is running, we can ignore this
402
- finally:
403
- if self.is_current():
404
- self.running_thread = None
405
- logger.info("thread done!")
406
- if cancel_event.is_set():
407
- self._result.value = TaskResult[R](latest=self._last_value, _state=TaskState.CANCELLED)
408
- _last_finished_event.set()
409
-
410
- try:
411
- runner()
412
- except Exception:
413
- logger.exception("error running in thread")
414
- raise
415
-
416
-
417
- # TODO: Not sure if we want to use this, or have all local variables in Task subclasses be reactive vars
418
- class Proxy:
419
- def __init__(self, factory):
420
- self._instance = Singleton(factory)
421
-
422
- def __getattr__(self, name):
423
- return getattr(self._instance.value, name)
424
-
425
- def __setattr__(self, name, value):
426
- if name == "_instance":
427
- super().__setattr__(name, value)
428
- else:
429
- setattr(self._instance.value, name, value)
430
-
431
- def __call__(self, *args, **kwargs):
432
- return self._instance.value(*args, **kwargs)
433
-
434
-
435
- @overload
436
- def task(
437
- f: None = None,
438
- *,
439
- prefer_threaded: bool = ...,
440
- ) -> Callable[[Callable[P, R]], Task[P, R]]:
441
- ...
442
-
443
-
444
- @overload
445
- def task(
446
- f: Callable[P, Union[Coroutine[Any, Any, R], R]],
447
- *,
448
- prefer_threaded: bool = ...,
449
- ) -> Task[P, R]:
450
- ...
451
-
452
-
453
- def task(
454
- f: Union[None, Callable[P, Union[Coroutine[Any, Any, R], R]]] = None,
455
- *,
456
- prefer_threaded: bool = True,
457
- ) -> Union[Callable[[Callable[P, R]], Task[P, R]], Task[P, R]]:
458
- """Decorator to turn a function or coroutine function into a task.
459
-
460
- Lets you run code in the background, with the UI available to the user. This is useful for long running tasks, like downloading data or processing data.
461
-
462
- The task decorator turns a function or coroutine function (`async def foo(...)` - here foo is called a coroutine function) into a task object.
463
- A task is a callable that will run the function or coroutine function in a separate thread
464
- Note that on platforms where threads are supported, asyncio tasks will still be executed in threads (unless the
465
- `prefer_thread=False` argument is passed). Because a coroutine function might still call long running blocking code.
466
- Running the asyncio task in a thread will still result in a responsive UI when executed in a separate thread.
467
-
468
- The task object will execute the function only once per virtual kernel and will only store one result per virtual kernel.
469
- When called multiple times, the previously started thread or asyncio task result will be ignored.
470
-
471
- A running thread or asyncio task can check if it is still the current task by calling `task.is_current()`.
472
- If `task.is_current()` returns False, the task should stop running and return early.
473
-
474
- The return value of the function is available as the `.value` reactive property on the task object, meaning that if a
475
- component accesses it, the component will automatically re-run when the value changes, like a [reactive variable](/api/reactive).
476
-
477
- ## Task object
478
-
479
- The task object has the following attributes/values which are all reactive:
480
-
481
- * `.value`: Contains the return value of the function (Only valid if `.finished` is true, else None).
482
- * `.exception`: The exception raised by the function, if any (Only valid if `.error` is true, else None).
483
- * `.latest` The last return value of the function, useful for showing out-of-date data while the task is running.
484
- * `.progress` A readable and writable reactive property which can be used for communicating progress to the user.
485
-
486
- The state of the task can be queried with the following attributes, which are all reactive:
487
-
488
- * `.not_called`: True if the task has not been called yet.
489
- * `.pending`: True if the task is asked to run, but did not finish yet, did not error and did not get cancelled.
490
- When true, often a loading or busy indicator is shown to the user.
491
- * `.finished`: True if the task has finished running. The result is available in the `.value` attribute as
492
- well as the `.latest` attribute.
493
- * `.cancelled`: True if the task was cancelled (by calling `.cancel()`).
494
- * `.error`: True if the function has raised an exception.
495
-
496
- The following methods are available:
497
-
498
- * `(*args, **kwargs)` : Call the task with the given arguments and keyword arguments. The task will only run once per virtual kernel.
499
- * `.cancel()`: Cancels the task.
500
- * `is_current()`: Returns True if the task is still the current task, and should continue running.
501
- Will return False when a new call to the task is made, and this function is being called from the the
502
- previous thread or asyncio.
503
-
504
- ## State diagram
505
-
506
- The following state diagram shows the possible states of a task and how
507
- each state transitions to another state.
508
-
509
- ```mermaid
510
- stateDiagram-v2
511
- not_called --> pending: task()
512
- pending --> finished
513
- pending --> error: exception
514
- pending --> pending: task()
515
- pending --> cancelled: task.cancel()
516
- finished --> pending: task()
517
- error --> pending: task()
518
- cancelled --> pending: task()
519
- ```
520
-
521
- Note that calling the task (as indicated by `task()`) can be done from any state.
522
-
523
-
524
- ## Example
525
-
526
- ### Async task
527
-
528
-
529
- ```solara
530
- import asyncio
531
- import solara
532
- from solara.lab import task
533
-
534
- @task
535
- async def fetch_data():
536
- await asyncio.sleep(2)
537
- return "The answer is 42"
538
-
539
- @solara.component
540
- def Page():
541
- solara.Button("Fetch data", on_click=fetch_data)
542
- solara.ProgressLinear(fetch_data.pending)
543
-
544
- if fetch_data.finished:
545
- solara.Text(fetch_data.value)
546
- elif fetch_data.not_called:
547
- solara.Text("Click the button to fetch data")
548
- # Optional state check
549
- # elif fetch_data.cancelled:
550
- # solara.Text("Cancelled the fetch")
551
- # elif fetch_data.error:
552
- # solara.Error(str(fetch_data.exception))
553
-
554
- ```
555
-
556
- ### Threaded task
557
-
558
- ```solara
559
- import time
560
- import solara
561
- from solara.lab import task
562
-
563
- @task
564
- def fetch_data():
565
- time.sleep(2)
566
- return "The answer is 42"
567
-
568
-
569
- @solara.component
570
- def Page():
571
- solara.Button("Fetch data", on_click=fetch_data)
572
- solara.ProgressLinear(fetch_data.pending)
573
-
574
- if fetch_data.finished:
575
- solara.Text(fetch_data.value)
576
- elif fetch_data.not_called:
577
- solara.Text("Click the button to fetch data")
578
- # Optional state check
579
- # elif fetch_data.cancelled:
580
- # solara.Text("Cancelled the fetch")
581
- # elif fetch_data.error:
582
- # solara.Error(str(fetch_data.exception))
583
- ```
584
-
585
- Note that both examples are very similar. In the first example however, we wrap a coroutine function
586
- which can use `asyncio.sleep`. In the second example, we use a regular function, which uses `time.sleep`.
587
- If the coroutine function would use `time.sleep` in combination with `prefer_threaded=False`,
588
- the UI would be unresponsive for 2 seconds.
589
-
590
-
591
- ### Showing a progress bar
592
-
593
-
594
- Using the `.progress` attribute, you can show a progress bar to the user. This is useful for long running tasks
595
- but requires a bit more work.
596
-
597
- ```solara
598
- import time
599
- import solara
600
- from solara.lab import task
601
-
602
-
603
- @task
604
- def my_calculation():
605
- total = 0
606
- for i in range(10):
607
- my_calculation.progress = (i + 1) * 10.0
608
- time.sleep(0.4)
609
- if not my_calculation.is_current():
610
- # a new call was made before this call was finished
611
- return
612
- total += i**2
613
- return total
614
-
615
-
616
- @solara.component
617
- def Page():
618
- solara.Button("Run calculation", on_click=my_calculation)
619
- solara.ProgressLinear(my_calculation.progress if my_calculation.pending else False)
620
-
621
- if my_calculation.finished:
622
- solara.Text(f"Calculation result: {my_calculation.value}")
623
- elif my_calculation.not_called:
624
- solara.Text("Click the button to fetch data")
625
- # Optional state check
626
- # elif my_calculation.cancelled:
627
- # solara.Text("Cancelled the fetch")
628
- # elif my_calculation.error:
629
- # solara.Error(str(my_calculation.exception))
630
- ```
631
-
632
- ### Out-of-date data
633
-
634
- ```solara
635
- import time
636
- import solara
637
- from solara.lab import task
638
-
639
-
640
- @task
641
- def my_calculation():
642
- total = 0
643
- for i in range(10):
644
- time.sleep(0.1)
645
- total += i**2
646
- return total
647
-
648
-
649
- @solara.component
650
- def Page():
651
- solara.ProgressLinear(my_calculation.pending)
652
- solara.Button("Run simulation", on_click=my_calculation)
653
- print(my_calculation.pending, my_calculation.value)
654
-
655
- if my_calculation.finished:
656
- solara.Text(f"Simulation result: {my_calculation.value}")
657
- if my_calculation.pending and my_calculation.latest:
658
- solara.Text(f"Simulation previous result: {my_calculation.latest}", style={"opacity": ".3"})
659
- elif my_calculation.not_called:
660
- solara.Text("Click the button to fetch data")
661
- ```
662
-
663
- ## Arguments
664
-
665
- - `f`: Function to turn into task or None
666
- - `prefer_threaded` - bool: Will run coroutine functions as a task in a thread when threads are available.
667
- This ensures that even when a coroutine functions calls a blocking function the UI is still responsive.
668
- On platform where threads are not supported (like Pyodide / WASM / Emscripten / PyScript), a coroutine
669
- function will always run in the current event loop.
670
-
671
- ```
672
-
673
- """
674
-
675
- def wrapper(f: Union[None, Callable[P, Union[Coroutine[Any, Any, R], R]]]) -> Task[P, R]:
676
- def create_task():
677
- if inspect.iscoroutinefunction(f):
678
- return TaskAsyncio[P, R](prefer_threaded and has_threads, f)
679
- else:
680
- return TaskThreaded[P, R](cast(Callable[P, R], f))
681
-
682
- return cast(Task[P, R], Proxy(create_task))
683
-
684
- if f is None:
685
- return wrapper
686
- else:
687
- return wrapper(f)
688
-
689
-
690
- @overload
691
- def use_task(
692
- f: None = None,
693
- *,
694
- dependencies: None = ...,
695
- raise_error=...,
696
- prefer_threaded=...,
697
- ) -> Callable[[Callable[P, R]], Task[P, R]]:
698
- ...
699
-
700
-
701
- @overload
702
- def use_task(
703
- f: Callable[P, R],
704
- *,
705
- dependencies: None = ...,
706
- raise_error=...,
707
- prefer_threaded=...,
708
- ) -> Task[P, R]:
709
- ...
710
-
711
-
712
- @overload
713
- def use_task(
714
- f: None = None,
715
- *,
716
- dependencies: List = ...,
717
- raise_error=...,
718
- prefer_threaded=...,
719
- ) -> Callable[[Callable[[], R]], "Task[[], R]"]:
720
- ...
721
-
722
-
723
- @overload
724
- def use_task(
725
- f: Callable[[], R],
726
- *,
727
- dependencies: List = ...,
728
- raise_error=...,
729
- prefer_threaded=...,
730
- ) -> "Task[[], R]":
731
- ...
732
-
733
-
734
- def use_task(
735
- f: Union[None, Callable[P, R]] = None,
736
- *,
737
- dependencies: Union[None, List] = [],
738
- raise_error=True,
739
- prefer_threaded=True,
740
- ) -> Union[Callable[[Callable[P, R]], Task[P, R]], Task[P, R]]:
741
- """A hook that runs a function or coroutine function as a task and returns the result.
742
-
743
- Allows you to run code in the background, with the UI available to the user. This is useful for long running tasks,
744
- like downloading data or processing data.
745
-
746
- Unlike with the [`@task`](/api/task) decorator, the result is not globally shared, but only available to the component that called `use_task`.
747
-
748
- Note that unlike the [`@task`](/api/task) decorator, the task is invoked immediately when dependencies are passed.
749
-
750
-
751
- ## Example
752
-
753
- ### Running in a thread
754
-
755
- ```solara
756
- import time
757
- import solara
758
- from solara.lab import use_task, Task
759
-
760
-
761
- @solara.component
762
- def Page():
763
- number = solara.use_reactive(4)
764
-
765
- def square():
766
- time.sleep(1)
767
- return number.value**2
768
-
769
- result: Task[int] = use_task(square, dependencies=[number.value])
770
-
771
- solara.InputInt("Square", value=number, continuous_update=True)
772
- if result.finished:
773
- solara.Success(f"Square of {number} == {result.value}")
774
- solara.ProgressLinear(result.pending)
775
- ```
776
-
777
- ### Running in an asyncio task
778
-
779
- Note that the only difference is our function is now a coroutine function,
780
- and we use `asyncio.sleep` instead of `time.sleep`.
781
-
782
- ```solara
783
- import asyncio
784
- import solara
785
- from solara.lab import use_task, Task
786
-
787
-
788
- @solara.component
789
- def Page():
790
- number = solara.use_reactive(4)
791
-
792
- async def square():
793
- await asyncio.sleep(1)
794
- return number.value**2
795
-
796
- result: Task[int] = use_task(square, dependencies=[number.value])
797
-
798
- solara.InputInt("Square", value=number, continuous_update=True)
799
- if result.finished:
800
- solara.Success(f"Square of {number} == {result.value}")
801
- solara.ProgressLinear(result.pending)
802
- ```
803
-
804
- ## Arguments
805
-
806
- - `f`: The function or coroutine to run as a task.
807
- - `dependencies`: A list of dependencies that will trigger a rerun of the task when changed.
808
- - `raise_error`: If true, an error in the task will be raised. If false, the error should be handled by the
809
- user and is available in the `.exception` attribute of the task result object.
810
- - `prefer_threaded` - bool: Will run coroutine functions as a task in a thread when threads are available.
811
- This ensures that even when a coroutine functions calls a blocking function the UI is still responsive.
812
- On platform where threads are not supported (like Pyodide / WASM / Emscripten / PyScript), a coroutine
813
- function will always run in the current event loop.
814
-
815
-
816
- """
817
-
818
- def wrapper(f):
819
- task_instance = solara.use_memo(lambda: task(f, prefer_threaded=prefer_threaded), dependencies=[])
820
- # we always update the function so we do not have stale data in the function
821
- task_instance.function = f # type: ignore
822
-
823
- def _prestart():
824
- if dependencies is not None:
825
- # we do not want to be in a state of .finished when the dependencies change
826
- # otherwise user code might render a stale value with the new dependencies
827
- task_instance._prestart()
828
-
829
- solara.use_memo(_prestart, dependencies=dependencies)
830
-
831
- def run():
832
- if dependencies is not None:
833
- # but we only want to execute it as an effect, which makes
834
- # sure that if the user assigns to a task object, the function f
835
- # starts after the assignment is executed
836
- task_instance()
837
-
838
- solara.use_effect(run, dependencies=dependencies)
839
- if raise_error:
840
- if task_instance.error:
841
- raise task_instance.exception
842
- return task_instance
843
-
844
- if f is None:
845
- return wrapper
846
- else:
847
- return wrapper(f)