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,61 @@
1
+ from typing import Optional, Union
2
+
3
+ import reacton.ipyvuetify as v
4
+
5
+ import solara
6
+
7
+
8
+ @solara.component
9
+ def Tooltip(
10
+ tooltip: Union[str, solara.Element],
11
+ children=[],
12
+ color: Optional[str] = None,
13
+ ):
14
+ """A tooltip that is shown when you hover above an element.
15
+
16
+ Not all components support tooltips, in case it does not work,
17
+ try wrapping the element in a `Column` or `Row`.
18
+
19
+ ```solara
20
+ import solara
21
+
22
+ @solara.component
23
+ def Page():
24
+ with solara.Tooltip("This is a tooltip over a button"):
25
+ solara.Button("Hover me")
26
+ with solara.Tooltip("This is a tooltip over a text"):
27
+ solara.Text("Hover me")
28
+ info = solara.Info("Any component is supported as tooltip.")
29
+ with solara.Tooltip(info, color="white"):
30
+ with solara.Column():
31
+ solara.Markdown("# Lorem ipsum\\n\\nDolor sit amet")
32
+ ```
33
+
34
+ ## Arguments
35
+
36
+ * `tooltip`: the text, or element to display on hover.
37
+ * `children`: the element to display the tooltip over.
38
+ * `color`: the color of the tooltip (if None, the default color).
39
+
40
+ """
41
+
42
+ def set_v_on():
43
+ for child in children:
44
+ widget = solara.get_widget(child)
45
+ # this only works on vue/vuetify components
46
+ widget.v_on = "tooltip.on" # type: ignore
47
+
48
+ solara.use_effect(set_v_on, children)
49
+
50
+ return v.Tooltip(
51
+ bottom=True,
52
+ v_slots=[
53
+ {
54
+ "name": "activator",
55
+ "variable": "tooltip",
56
+ "children": children,
57
+ }
58
+ ],
59
+ color=color,
60
+ children=[tooltip],
61
+ )
solara/core.py ADDED
@@ -0,0 +1,42 @@
1
+ import warnings
2
+ from typing import Any, Callable, Dict, Union, overload, TypeVar
3
+ import typing_extensions
4
+ import reacton
5
+ from . import validate_hooks
6
+
7
+
8
+ P = typing_extensions.ParamSpec("P")
9
+ FuncT = TypeVar("FuncT", bound=Callable[..., reacton.core.Element])
10
+
11
+
12
+ @overload
13
+ def component(obj: None = None, mime_bundle: Dict[str, Any] = ...) -> Callable[[FuncT], FuncT]: ...
14
+
15
+
16
+ @overload
17
+ def component(obj: FuncT, mime_bundle: Dict[str, Any] = ...) -> FuncT: ...
18
+
19
+
20
+ @overload
21
+ def component(obj: Callable[P, None], mime_bundle: Dict[str, Any] = ...) -> Callable[P, reacton.core.Element]: ...
22
+
23
+
24
+ def component(
25
+ obj: Union[Callable[P, None], FuncT, None] = None, mime_bundle: Dict[str, Any] = reacton.core.mime_bundle_default
26
+ ) -> Union[Callable[[FuncT], FuncT], FuncT, Callable[P, reacton.core.Element]]:
27
+ def wrapper(obj: Union[Callable[P, None], FuncT]) -> FuncT:
28
+ try:
29
+ validate_hooks.HookValidator(obj).run()
30
+ except Exception as e:
31
+ if not isinstance(e, validate_hooks.HookValidationError):
32
+ # we probably failed because of an unknown reason, but we do not want to break the user's code
33
+ warnings.warn(f"Failed to validate hooks for component {obj.__qualname__}: {e}")
34
+ else:
35
+ raise
36
+
37
+ return reacton.component(obj, mime_bundle) # type: ignore
38
+
39
+ if obj is not None:
40
+ return wrapper(obj)
41
+ else:
42
+ return wrapper
solara/datatypes.py ADDED
@@ -0,0 +1,143 @@
1
+ import dataclasses
2
+ from enum import Enum
3
+ from pathlib import Path
4
+ from types import ModuleType
5
+ from typing import Any, Callable, Dict, Generic, List, Optional, TypeVar, Union
6
+
7
+ import reacton
8
+ from typing_extensions import Literal, TypedDict
9
+
10
+ T = TypeVar("T")
11
+ U = TypeVar("U")
12
+
13
+
14
+ @dataclasses.dataclass(frozen=True)
15
+ class Action:
16
+ name: str
17
+ icon: Optional[str] = None
18
+ on_click: Optional[Callable] = None
19
+
20
+
21
+ @dataclasses.dataclass(frozen=True)
22
+ class ColumnAction(Action):
23
+ on_click: Optional[Callable[[str], None]] = None
24
+
25
+
26
+ @dataclasses.dataclass(frozen=True)
27
+ class CellAction(Action):
28
+ on_click: Optional[Callable[[str, int], None]] = None
29
+
30
+
31
+ def _fallback_retry():
32
+ raise RuntimeError("Should not happen")
33
+
34
+
35
+ class ResultState(Enum):
36
+ INITIAL = 1
37
+ STARTING = 2
38
+ WAITING = 3
39
+ RUNNING = 4
40
+ ERROR = 5
41
+ FINISHED = 6
42
+ CANCELLED = 7
43
+
44
+
45
+ @dataclasses.dataclass(frozen=True)
46
+ class Result(Generic[T]):
47
+ value: Optional[T] = None
48
+ error: Optional[Exception] = None
49
+ state: ResultState = ResultState.INITIAL
50
+ progress: Optional[float] = None
51
+
52
+ def retry(self):
53
+ # mypy does not like members that are callable
54
+ # gets confused about self argument.
55
+ # we wrap it to avoid hitting this error in user
56
+ # code
57
+ self._retry() # type: ignore
58
+
59
+ # can we avoid storing these into the dataclass?
60
+ _retry: Callable[[], Any] = dataclasses.field(compare=False, default=lambda: None)
61
+ cancel: Callable[[], Any] = dataclasses.field(compare=False, default=lambda: None)
62
+
63
+ def __or__(self, next: Callable[["Result[T]"], "Result[U]"]):
64
+ return next(self)
65
+
66
+
67
+ @dataclasses.dataclass(frozen=True)
68
+ class FileContentResult(Result[T]):
69
+ @property
70
+ def exists(self):
71
+ return not isinstance(self.error, FileNotFoundError)
72
+
73
+
74
+ class AggregationCount(TypedDict):
75
+ type: Literal["count"]
76
+
77
+
78
+ class AggregationSum(TypedDict):
79
+ type: Literal["sum"]
80
+
81
+
82
+ JsonType = Union[None, int, str, bool, List[Any], Dict[str, Any]]
83
+
84
+ Aggregation = Union[AggregationCount, AggregationSum]
85
+
86
+
87
+ class PivotTableData(TypedDict):
88
+ x: List[str]
89
+ y: List[str]
90
+ agg: str
91
+ values: List[List[JsonType]]
92
+ values_x: List[str]
93
+ values_y: List[str]
94
+ headers_x: List[List[str]]
95
+ headers_y: List[List[str]]
96
+ counts_x: int
97
+ counts_y: int
98
+ total: str
99
+
100
+
101
+ @dataclasses.dataclass(frozen=True)
102
+ class Route:
103
+ """A route tells Solara which component to render for a given URL. (Not a Solara component!)
104
+
105
+ ## Arguments
106
+
107
+ * `path` - The path of the route. This is the part of the URL that you see in the browser.
108
+ * `children` - (Optional) A list of child routes. These are routes that are nested under this route.
109
+ * `module` - (Optional) The module that contains the component to render for this route, used for autorouting.
110
+ * `component` - (Optional) The component to render for this route.
111
+ * `layout` - (Optional) The layout to use for this route. If not specified, the default layout will be used.
112
+ * `data` - (Optional) The data to pass to the component for this route, usage is up to the user.
113
+ * `label` - (Optional) The label to use for this route, can be used for labeling tabs or links.
114
+
115
+ ## See also
116
+
117
+ * [Multipage](/documentation/advanced/howto/multipage).
118
+ * [Understanding Routing](/documentation/advanced/understanding/routing).
119
+
120
+ """
121
+
122
+ path: str
123
+ children: List["Route"] = dataclasses.field(default_factory=list)
124
+
125
+ # these are free to use, depending on the implementation
126
+ # see autorouting.py for how Solara uses them
127
+ module: Optional[ModuleType] = None
128
+
129
+ # in the autorouting implementation, this is the
130
+ # the same as module.Page (unless we are rendering a markdown)
131
+ component: Union[None, Callable, reacton.core.Component] = None
132
+ layout: Union[None, Callable, reacton.core.Component] = None
133
+
134
+ # in the autorouting implementation, this is the
135
+ # path of the markdown file
136
+ data: Any = None
137
+
138
+ # Can be used for a title and/or a tab label
139
+ label: Optional[str] = None
140
+
141
+ # file corresponding to this route, can be used for
142
+ # checking of content has changed (using mtime)
143
+ file: Optional[Path] = None
solara/express.py ADDED
@@ -0,0 +1,241 @@
1
+ import functools
2
+ import typing
3
+ from typing import Callable
4
+
5
+ import numpy as np
6
+ import plotly.express as px
7
+ import plotly.graph_objs as go
8
+ import typing_extensions
9
+
10
+ # behave as the px module
11
+ from plotly.express import * # noqa: F401, F403
12
+ from plotly.express._core import make_figure
13
+
14
+ import solara
15
+
16
+ P = typing_extensions.ParamSpec("P")
17
+ T = typing.TypeVar("T")
18
+ T2 = typing.TypeVar("T2")
19
+
20
+
21
+ # patch histogram until issue 3859 in plotly is resolved
22
+
23
+
24
+ def histogram(
25
+ data_frame=None,
26
+ x=None,
27
+ y=None,
28
+ custom_data=None,
29
+ color=None,
30
+ pattern_shape=None,
31
+ facet_row=None,
32
+ facet_col=None,
33
+ facet_col_wrap=0,
34
+ facet_row_spacing=None,
35
+ facet_col_spacing=None,
36
+ hover_name=None,
37
+ hover_data=None,
38
+ animation_frame=None,
39
+ animation_group=None,
40
+ category_orders=None,
41
+ labels=None,
42
+ color_discrete_sequence=None,
43
+ color_discrete_map=None,
44
+ pattern_shape_sequence=None,
45
+ pattern_shape_map=None,
46
+ marginal=None,
47
+ opacity=None,
48
+ orientation=None,
49
+ barmode="relative",
50
+ barnorm=None,
51
+ histnorm=None,
52
+ log_x=False,
53
+ log_y=False,
54
+ range_x=None,
55
+ range_y=None,
56
+ histfunc=None,
57
+ cumulative=None,
58
+ nbins=None,
59
+ text_auto=False,
60
+ title=None,
61
+ template=None,
62
+ width=None,
63
+ height=None,
64
+ ) -> go.Figure:
65
+ """
66
+ In a histogram, rows of `data_frame` are grouped together into a
67
+ rectangular mark to visualize the 1D distribution of an aggregate
68
+ function `histfunc` (e.g. the count or sum) of the value `y` (or `x` if
69
+ `orientation` is `'h'`).
70
+ """
71
+ return make_figure(
72
+ args=locals(),
73
+ constructor=go.Histogram,
74
+ trace_patch=dict(
75
+ histnorm=histnorm,
76
+ histfunc=histfunc,
77
+ cumulative=dict(enabled=cumulative),
78
+ ),
79
+ layout_patch=dict(barmode=barmode, barnorm=barnorm),
80
+ )
81
+
82
+
83
+ px.histogram = histogram
84
+
85
+
86
+ def _make_self_describing(f: Callable[P, T]):
87
+ # put the arguments on the function and the function into the return value
88
+ if hasattr(f, "__wrapped__"):
89
+ # on hot reload, we need to unwrap the function to not wrap it twice
90
+ f = f.__wrapped__
91
+
92
+ @functools.wraps(f)
93
+ def wrapper(*args: P.args, **kwargs: P.kwargs):
94
+ fig = f(*args, **kwargs)
95
+ fig._func = f # type: ignore
96
+ fig._args = args # type: ignore
97
+ fig._kwargs = kwargs # type: ignore
98
+ return fig
99
+
100
+ return wrapper
101
+
102
+
103
+ def _patch():
104
+ for name in dir(px):
105
+ f = getattr(px, name)
106
+ if callable(f):
107
+ f = _make_self_describing(f)
108
+ setattr(px, name, f)
109
+
110
+
111
+ _patch()
112
+
113
+
114
+ @solara.component
115
+ def CrossFilteredFigurePlotly(fig):
116
+ first_arg_name = fig._func.__code__.co_varnames[0]
117
+ kwargs = fig._kwargs.copy()
118
+ kwargs.update(zip(fig._func.__code__.co_varnames, fig._args))
119
+
120
+ df = kwargs[first_arg_name]
121
+ name = fig._func.__name__
122
+ filter, set_filter = solara.use_cross_filter(id(df), name)
123
+ dff = df
124
+ if filter is not None:
125
+ dff = df[filter]
126
+ for key, value in kwargs.items():
127
+ if not isinstance(value, str):
128
+ try:
129
+ n = len(value)
130
+ except TypeError:
131
+ pass # int or bool, or anything without a length
132
+ except Exception:
133
+ raise
134
+ else:
135
+ if n == len(df):
136
+ kwargs[key] = np.array(value)[filter]
137
+ original_indices = np.arange(len(df), dtype="int64")
138
+ else:
139
+ original_indices = None
140
+
141
+ kwargs[first_arg_name] = dff
142
+
143
+ index = np.arange(len(dff))
144
+ custom_data = [index]
145
+ has_custom_data = "custom_data" in kwargs
146
+
147
+ if has_custom_data:
148
+ kwargs["custom_data"] = custom_data + list(kwargs["custom_data"])
149
+ else:
150
+ kwargs["custom_data"] = custom_data
151
+ new_fig = fig._func(**kwargs)
152
+ new_fig.layout = fig.layout
153
+
154
+ # the df is split into multiple traces, generate the data such that we can transform back from trace+point indices to df.index
155
+ indices = []
156
+ offset = 0
157
+ index_offsets_list = []
158
+ for data in new_fig.data:
159
+ indices.append(data.customdata.T[0])
160
+ index_offsets_list.append(offset)
161
+ offset += len(data.customdata.T[0])
162
+ index_offsets = np.array(index_offsets_list)
163
+ # strip of the custom data we added
164
+ for data in new_fig.data:
165
+ if has_custom_data:
166
+ data.customdata = data.customdata.T[len(custom_data) :].T
167
+ else:
168
+ data.customdata = None
169
+
170
+ def on_selection(data):
171
+ if data is not None:
172
+ trace_indexes = np.array(data["points"]["trace_indexes"])
173
+ point_indexes = np.array(data["points"]["point_indexes"])
174
+ if len(trace_indexes):
175
+ indices_selected = index_offsets[trace_indexes] + point_indexes
176
+
177
+ if filter is not None:
178
+ assert original_indices is not None
179
+ # these are references to the filtered dataframe
180
+ indices_selected = original_indices[filter][indices_selected]
181
+ mask = np.zeros(len(df), dtype=bool)
182
+ mask[indices_selected] = True
183
+ set_filter(mask)
184
+ else:
185
+ set_filter(None)
186
+
187
+ def on_deselect(data):
188
+ set_filter(None)
189
+
190
+ return solara.FigurePlotly(new_fig, on_selection=on_selection, on_deselect=on_deselect)
191
+
192
+
193
+ # for backwards compatibility
194
+ FigurePlotlyCrossFiltered = CrossFilteredFigurePlotly
195
+
196
+
197
+ def _wraps(f: Callable[P, T]):
198
+ @functools.wraps(f)
199
+ def wrapper(*args: P.args, **kwargs: P.kwargs):
200
+ fig = f(*args, **kwargs)
201
+ return CrossFilteredFigurePlotly(fig)
202
+
203
+ return wrapper
204
+
205
+
206
+ scatter = _wraps(px.scatter)
207
+ scatter_3d = _wraps(px.scatter_3d)
208
+ scatter_polar = _wraps(px.scatter_polar)
209
+ scatter_ternary = _wraps(px.scatter_ternary)
210
+ scatter_mapbox = _wraps(px.scatter_mapbox)
211
+ scatter_geo = _wraps(px.scatter_geo)
212
+ scatter_matrix = _wraps(px.scatter_matrix)
213
+ density_contour = _wraps(px.density_contour)
214
+ density_heatmap = _wraps(px.density_heatmap)
215
+ density_mapbox = _wraps(px.density_mapbox)
216
+ line = _wraps(px.line)
217
+ line_3d = _wraps(px.line_3d)
218
+ line_polar = _wraps(px.line_polar)
219
+ line_ternary = _wraps(px.line_ternary)
220
+ line_mapbox = _wraps(px.line_mapbox)
221
+ line_geo = _wraps(px.line_geo)
222
+ parallel_coordinates = _wraps(px.parallel_coordinates)
223
+ parallel_categories = _wraps(px.parallel_categories)
224
+ area = _wraps(px.area)
225
+ bar = _wraps(px.bar)
226
+ timeline = _wraps(px.timeline)
227
+ bar_polar = _wraps(px.bar_polar)
228
+ violin = _wraps(px.violin)
229
+ box = _wraps(px.box)
230
+ strip = _wraps(px.strip)
231
+ histogram = _wraps(px.histogram)
232
+ ecdf = _wraps(px.ecdf)
233
+ choropleth = _wraps(px.choropleth)
234
+ choropleth_mapbox = _wraps(px.choropleth_mapbox)
235
+ pie = _wraps(px.pie)
236
+ sunburst = _wraps(px.sunburst)
237
+ treemap = _wraps(px.treemap)
238
+ icicle = _wraps(px.icicle)
239
+ funnel = _wraps(px.funnel)
240
+ funnel_area = _wraps(px.funnel_area)
241
+ imshow = _wraps(px.imshow)
@@ -0,0 +1,4 @@
1
+ from .dataframe import * # noqa: F401 F403
2
+ from .misc import * # noqa: F401 F403
3
+ from .use_reactive import use_reactive # noqa: F401 F403
4
+ from .use_thread import use_thread # noqa: F401 F403
@@ -0,0 +1,99 @@
1
+ import operator
2
+ from functools import reduce
3
+ from typing import Any, Callable, Dict, List, TypeVar
4
+
5
+ import solara.util
6
+ from solara.hooks.misc import use_force_update, use_unique_key
7
+
8
+ T = TypeVar("T")
9
+
10
+ __all__ = [
11
+ "provide_cross_filter",
12
+ "use_cross_filter",
13
+ ]
14
+
15
+
16
+ class CrossFilterStore:
17
+ def __init__(self) -> None:
18
+ self.listeners: List[Callable] = []
19
+ self.filters: Dict[Any, Dict[str, Any]] = {}
20
+
21
+ def add(self, data_key, key, filter):
22
+ data_filters = self.filters.setdefault(data_key, {})
23
+ data_filters[key] = filter
24
+
25
+ def use(self, data_key, key, eq=None):
26
+ # we use this state to trigger update, we could do without
27
+ updater = use_force_update()
28
+
29
+ data_filters = self.filters.setdefault(data_key, {})
30
+ filter, set_filter = solara.use_state(data_filters.get(key), eq=eq)
31
+
32
+ def on_change():
33
+ set_filter(data_filters.get(key))
34
+ # even if we don't change our own filter, the other may change
35
+ updater()
36
+
37
+ def connect():
38
+ self.listeners.append(on_change)
39
+ # we need to force an extra render after the first render
40
+ # to make sure we have the correct filter, since others components
41
+ # may set a filter after we have rendered, *or* mounted
42
+ on_change()
43
+
44
+ def cleanup():
45
+ self.listeners.remove(on_change)
46
+ # also remove our filter, and notify the rest
47
+ data_filters.pop(key, None) # remove, ignoring key error
48
+ for listener in self.listeners:
49
+ listener()
50
+
51
+ return cleanup
52
+
53
+ solara.use_effect(connect, [key])
54
+
55
+ def setter(filter):
56
+ data_filters[key] = filter
57
+ for listener in self.listeners:
58
+ listener()
59
+
60
+ otherfilters = [filter for key_other, filter in data_filters.items() if key != key_other and filter is not None]
61
+ return filter, otherfilters, setter
62
+
63
+
64
+ cross_filter_context = solara.create_context(CrossFilterStore())
65
+
66
+
67
+ def provide_cross_filter():
68
+ # create it once
69
+ cross_filter_object = solara.use_memo(CrossFilterStore, [])
70
+ cross_filter_context.provide(cross_filter_object)
71
+ return cross_filter_object
72
+
73
+
74
+ def use_cross_filter(data_key, name: str = "no-name", reducer: Callable[[T, T], T] = operator.and_, eq=solara.util.numpy_equals):
75
+ """Provides cross filtering, all other filters are combined using the reducer.
76
+
77
+ Cross filtering will collect a set of filters (from other components), and combine
78
+ them into a single filter, that excludes the filter we set for the current component.
79
+ This is often used in dashboards where a filter is defined in a visualization component,
80
+ but only applied to all other components.
81
+
82
+ The graph below shows what happens when component A and B set a filter, and C does not.
83
+
84
+ ```mermaid
85
+ graph TD;
86
+ A--"filter A"-->B;
87
+ B--"filter B"-->C;
88
+ A--"filter A"-->C;
89
+ B--"filter B"-->A;
90
+ ```
91
+ """
92
+ key = use_unique_key(prefix=f"cross-filter-{name}-")
93
+ cross_filter_store = solara.use_context(cross_filter_context)
94
+ _own_filter, otherfilters, set_filter = cross_filter_store.use(data_key, key, eq=eq)
95
+ if otherfilters:
96
+ cross_filter = reduce(reducer, otherfilters[1:], otherfilters[0])
97
+ else:
98
+ cross_filter = None
99
+ return cross_filter, set_filter