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
solara/server/app.py ADDED
@@ -0,0 +1,527 @@
1
+ import dataclasses
2
+ import importlib.util
3
+ import logging
4
+ import os
5
+ import pickle
6
+ import sys
7
+ import threading
8
+ import traceback
9
+ import warnings
10
+ import weakref
11
+ from enum import Enum
12
+ from pathlib import Path
13
+ from typing import Any, Dict, List, Optional, cast
14
+
15
+ import ipywidgets as widgets
16
+ import reacton
17
+ from reacton.core import Element, render
18
+
19
+ import solara
20
+ import solara.lifecycle
21
+ from solara.util import nested_get
22
+
23
+ from . import kernel_context, patch, reload, settings
24
+ from .kernel import Kernel
25
+ from .utils import pdb_guard
26
+
27
+ WebSocket = Any
28
+ apps: Dict[str, "AppScript"] = {}
29
+ thread_lock = threading.Lock()
30
+
31
+ logger = logging.getLogger("solara.server.app")
32
+
33
+ reload.reloader.start()
34
+
35
+
36
+ class AppType(str, Enum):
37
+ SCRIPT = "script"
38
+ NOTEBOOK = "notebook"
39
+ MODULE = "module"
40
+ DIRECTORY = "directory"
41
+
42
+
43
+ def display(*args, **kwargs):
44
+ print("display not implemented", args, kwargs) # noqa
45
+
46
+
47
+ class AppScript:
48
+ directory: Path
49
+ routes: List[solara.Route]
50
+
51
+ def __init__(self, name, default_app_name="Page"):
52
+ self.fullname = name
53
+ if reload.reloader.on_change:
54
+ raise RuntimeError("Previous reloader still had a on_change attached, no cleanup?")
55
+ reload.reloader.on_change = self.on_file_change
56
+
57
+ self.app_name = default_app_name
58
+ if ":" in self.fullname:
59
+ self.name, self.app_name = self.fullname.rsplit(":", 1)
60
+ if len(self.name) == 1: # a windows drive letter, restore
61
+ self.name = self.fullname
62
+ self.app_name = default_app_name
63
+ else:
64
+ self.name = name
65
+ self.path: Path = Path(self.name).resolve()
66
+ if self.path.is_dir():
67
+ self.type = AppType.DIRECTORY
68
+ # resolve the directory, because Path("file").parent.parent == "." != ".."
69
+ self.directory = self.path.resolve()
70
+ elif self.name.endswith(".py"):
71
+ self.type = AppType.SCRIPT
72
+ self.directory = self.path.parent.resolve()
73
+ elif self.name.endswith(".ipynb"):
74
+ self.type = AppType.NOTEBOOK
75
+ self.directory = self.path.parent.resolve()
76
+ else:
77
+ self.type = AppType.MODULE
78
+ try:
79
+ spec = importlib.util.find_spec(self.name)
80
+ except ValueError:
81
+ if self.name not in sys.modules:
82
+ raise ImportError(f"Module {self.name} not found")
83
+ spec = importlib.util.spec_from_file_location(self.name, sys.modules[self.name].__file__)
84
+ if spec is None:
85
+ raise ImportError(f"Module {self.name} cannot be found")
86
+ assert spec is not None
87
+ if spec.origin is None:
88
+ raise ImportError(f"Module {self.name} cannot be found, or is a namespace package")
89
+ assert spec.origin is not None
90
+ self.path = Path(spec.origin)
91
+ self.directory = self.path.parent
92
+ self._initialized = False
93
+ self._lock = threading.Lock()
94
+
95
+ def init(self):
96
+ try:
97
+ context = kernel_context.get_current_context()
98
+ except RuntimeError:
99
+ context = None
100
+ if context is not None:
101
+ raise RuntimeError(f"We should not have an existing Solara app context when running an app for the first time: {context}")
102
+ dummy_kernel_context = kernel_context.create_dummy_context()
103
+ with dummy_kernel_context:
104
+ app = self._execute()
105
+
106
+ # We now ran the app, now we can check for patches that require heavy imports
107
+ patch.patch_heavy_imports()
108
+
109
+ self._first_execute_app = app
110
+ reload.reloader.root_path = self.directory
111
+ if self.type == AppType.MODULE:
112
+ package_name = self.name.split(".")[0]
113
+ mod = importlib.import_module(package_name)
114
+ if mod.__file__ is not None:
115
+ package_root_path = Path(mod.__file__).parent
116
+ reload.reloader.root_path = package_root_path
117
+ dummy_kernel_context.close()
118
+ self._initialized = True
119
+
120
+ def _execute(self):
121
+ logger.info("Executing %s", self.name)
122
+ app = None
123
+ routes: Optional[List[solara.Route]] = None
124
+
125
+ def add_path():
126
+ # this is not expected for modules, similar to `python script.py and python -m package.mymodule`
127
+ if self.type in [AppType.SCRIPT, AppType.NOTEBOOK]:
128
+ working_directory = str(self.path.parent)
129
+ if working_directory not in sys.path:
130
+ sys.path.insert(0, working_directory)
131
+
132
+ if self.type == AppType.DIRECTORY:
133
+ # resolve the directory, because Path("file").parent.parent == "." != ".."
134
+ routes = solara.generate_routes_directory(self.path)
135
+
136
+ if any(name for name in sys.modules.keys() if name.startswith(self.name)):
137
+ logger.warn(
138
+ f"Directory {self.name} is also used as a package. This can cause modules to be loaded twice, and might "
139
+ "cause unexpected behavior. If you run solara from a different directory (e.g. the parent directory) you "
140
+ "can avoid this ambiguity."
141
+ )
142
+
143
+ elif self.type == AppType.SCRIPT:
144
+ add_path()
145
+ # manually add the script to the watcher
146
+ reload.reloader.watcher.add_file(self.path)
147
+ initial_namespace = {
148
+ "__name__": "__main__",
149
+ }
150
+ with reload.reloader.watch():
151
+ routes = [solara.autorouting._generate_route_path(self.path, first=True, initial_namespace=initial_namespace)]
152
+ elif self.type == AppType.NOTEBOOK:
153
+ add_path()
154
+ # manually add the notebook to the watcher
155
+ reload.reloader.watcher.add_file(self.path)
156
+ with reload.reloader.watch():
157
+ routes = [solara.autorouting._generate_route_path(self.path, first=True)]
158
+ else:
159
+ # the module itself will be added by reloader
160
+ # automatically
161
+ with kernel_context.without_context(), reload.reloader.watch():
162
+ self.type = AppType.MODULE
163
+ mod = importlib.import_module(self.name)
164
+ routes = solara.generate_routes(mod)
165
+
166
+ app = solara.autorouting.RenderPage(self.app_name)
167
+
168
+ # when the root moduled defined routes, skip the enclosing route object
169
+ if len(routes) == 1 and routes[0].module and hasattr(routes[0].module, "routes"):
170
+ if routes[0].component:
171
+ warnings.warn(
172
+ f"{self.name} has a component defined, but you are also defining routes."
173
+ " To avoid confusing, consider renaming the {self.app_name} component."
174
+ )
175
+ routes = routes[0].children
176
+
177
+ if self.app_name != "Page":
178
+ # if we specified the app name, we replace the component
179
+ if len(routes) > 1:
180
+ raise ValueError(f"App {self.name} has multiple routes, but a default app name was given: {self.app_name}")
181
+ assert len(routes) == 1
182
+ component = nested_get(routes[0].module.__dict__, self.app_name, None)
183
+ routes = [dataclasses.replace(routes[0], component=component)]
184
+
185
+ if settings.ssg.build_path is None:
186
+ settings.ssg.build_path = self.directory.parent.resolve() / "build"
187
+
188
+ # auto enable search if search.json exists
189
+ search_index_file = self.directory.parent / "assets" / "search.json"
190
+ if search_index_file.exists():
191
+ settings.search.enabled = True
192
+
193
+ # this might be useful for development
194
+ # but requires reloading of react in solara itself
195
+ # for name, module in sys.modules.items():
196
+ # if name.startswith("reacton"):
197
+ # file = inspect.getfile(module)
198
+ # self.watcher.add_file(file)
199
+
200
+ # cgi vars: https://datatracker.ietf.org/doc/html/rfc3875
201
+ # we cannot set script name, because gunicorn uses it (and will crash)
202
+ # os.environ["SCRIPT_NAME"] = self.name
203
+ os.environ["PATH_TRANSLATED"] = str(self.path.resolve())
204
+
205
+ self.routes = routes
206
+
207
+ # this might be useful for development
208
+ # but requires reloading of react in solara itself
209
+ # for name, module in sys.modules.items():
210
+ # if name.startswith("reacton"):
211
+ # file = inspect.getfile(module)
212
+ # self.watcher.add_file(file)
213
+
214
+ # cgi vars: https://datatracker.ietf.org/doc/html/rfc3875
215
+ # we cannot set script name, because gunicorn uses it (and will crash)
216
+ # os.environ["SCRIPT_NAME"] = self.name
217
+ os.environ["PATH_TRANSLATED"] = str(self.path.resolve())
218
+ return app
219
+
220
+ def close(self):
221
+ reload.reloader.on_change = None
222
+ context_values = list(kernel_context.contexts.values())
223
+ kernel_context.contexts.clear()
224
+ for context in context_values:
225
+ context.close()
226
+
227
+ def check(self):
228
+ if not self._initialized:
229
+ with self._lock:
230
+ if not self._initialized:
231
+ self.init()
232
+
233
+ def run(self):
234
+ self.check()
235
+ if reload.reloader.requires_reload or self._first_execute_app is None:
236
+ with thread_lock:
237
+ if reload.reloader.requires_reload or self._first_execute_app is None:
238
+ self._first_execute_app = None
239
+ self._first_execute_app = self._execute()
240
+ print("Re-executed app", self.name) # noqa
241
+ # We now ran the app again, might contain new imports
242
+ patch.patch_heavy_imports()
243
+
244
+ return self._first_execute_app
245
+
246
+ def on_file_change(self, name):
247
+ path = Path(name)
248
+ if path.suffix == ".vue":
249
+ logger.info("Vue file changed: %s", name)
250
+ template_content = path.read_text(encoding="utf-8")
251
+ for context in list(kernel_context.contexts.values()):
252
+ with context:
253
+ for filepath, widget in context.templates.items():
254
+ if filepath == str(path):
255
+ widget.template = template_content
256
+ else:
257
+ logger.info("Reload requires due to change in module: %s", name)
258
+ self.reload()
259
+
260
+ def reload(self):
261
+ # if multiple files change in a short time, we want to do this
262
+ # not concurrently. Even better would be to do a debounce?
263
+ with thread_lock:
264
+ # TODO: clearing the type_counter is a bit of a hack
265
+ # and we should introduce reload 'hooks', so there is
266
+ # less interdependency between modules
267
+ import solara.lab.toestand
268
+
269
+ solara.lab.toestand.ConnectionStore._type_counter.clear()
270
+
271
+ # we need to remove callbacks that are added in the app code
272
+ # which will be re-executed after the reload and we do not
273
+ # want to keep executing the old ones.
274
+ for kc in solara.lifecycle._on_kernel_start_callbacks.copy():
275
+ callback, path, module, cleanup = kc
276
+ will_reload = False
277
+ if module is not None:
278
+ module_name = module.__name__
279
+ if module_name in reload.reloader.get_reload_module_names():
280
+ will_reload = True
281
+ elif path is not None:
282
+ if str(path.resolve()).startswith(str(self.directory)):
283
+ will_reload = True
284
+ else:
285
+ logger.warning(
286
+ "script %s is not in the same directory as the app %s but is using on_kernel_start, "
287
+ "this might lead to multiple entries, and might indicate a bug.",
288
+ path,
289
+ self.directory,
290
+ )
291
+
292
+ if will_reload:
293
+ logger.info("reload: Removing on_kernel_start callback: %s (since it will be added when reloaded)", callback)
294
+ cleanup()
295
+
296
+ context_values = list(kernel_context.contexts.values())
297
+ # save states into the context so the hot reload will
298
+ # keep the same state
299
+ for context in context_values:
300
+ render_context = cast(reacton.core._RenderContext, context.app_object)
301
+ if render_context:
302
+ with context:
303
+ # we save the state for when the app reruns, so we stay in the same state.
304
+ # (e.g. button clicks, chosen options etc)
305
+ # for instance a dataframe, needs to be pickled, because after the pandas
306
+ # module is reloaded, it's a different class type
307
+ logger.info("pickling state: %s", render_context.state_get())
308
+ try:
309
+ context.state = pickle.dumps(render_context.state_get())
310
+ except Exception as e:
311
+ logger.warning("Could not pickle state, next render the state will be lost: %s", e)
312
+ # clear/cleanup the render_context, so during reload we start
313
+ # from scratch
314
+ context.app_object = None
315
+ # we want to reuse the container
316
+ render_context.container = None
317
+ try:
318
+ render_context.close()
319
+ except Exception as e:
320
+ logger.exception("Could not close render context: %s", e)
321
+
322
+ # ask all contexts/users to reload
323
+ for context in context_values:
324
+ with context:
325
+ context.reload()
326
+
327
+
328
+ def _run_app(
329
+ app_state,
330
+ app_script: AppScript,
331
+ pathname: str,
332
+ render_context: reacton.core._RenderContext = None,
333
+ ):
334
+ # app.signal_hook_install()
335
+ main_object = app_script.run()
336
+ app_state = pickle.loads(app_state) if app_state is not None else None
337
+ if app_state:
338
+ logger.info("Restoring state: %r", app_state)
339
+
340
+ context = kernel_context.get_current_context()
341
+ container = context.container
342
+ if isinstance(main_object, widgets.Widget):
343
+ return main_object, render_context
344
+ elif isinstance(main_object, Element) or isinstance(main_object, reacton.core.Component):
345
+ if isinstance(main_object, Element):
346
+ children = [main_object]
347
+ else:
348
+ children = [main_object()]
349
+ solara_context = solara.RoutingProvider(children=children, routes=app_script.routes, pathname=pathname)
350
+ if render_context is None:
351
+ result = render(solara_context, container, handle_error=True, initial_state=app_state)
352
+ # support older versions of react
353
+ if isinstance(result, tuple):
354
+ container, render_context = result
355
+ else:
356
+ render_context = result
357
+ else:
358
+ if app_state:
359
+ render_context.state_set(render_context.context_root, app_state)
360
+ result = render_context.render(solara_context)
361
+ container = render_context.container
362
+ # return container, render_context
363
+ else:
364
+ extra = ""
365
+ dotted = []
366
+ for key, value in vars(main_object).items():
367
+ if isinstance(value, (Element, widgets.Widget)):
368
+ dotted.append(f"{app_script.app_name}.{key}")
369
+ if dotted:
370
+ extra = " We did find that sub objects that might work: " + ", ".join(dotted)
371
+ raise ValueError(
372
+ f"Main object (with name {app_script.app_name} in {app_script.path}) is not a Widget, Element or Component, but {type(main_object)}." + extra
373
+ )
374
+ return container, render_context
375
+
376
+
377
+ def load_app_widget(app_state, app_script: AppScript, pathname: str):
378
+ # load the app, and set it at the child of the context's container
379
+ app_state_initial = app_state
380
+ context = kernel_context.get_current_context()
381
+ container = context.container
382
+ assert container is not None
383
+ try:
384
+ import ipyreact
385
+
386
+ del ipyreact
387
+ except ModuleNotFoundError:
388
+ pass
389
+ else:
390
+ import solara.server.esm
391
+
392
+ # will create widgets, but will clean itself up when the kernel closes
393
+ solara.server.esm.create_modules()
394
+ solara.server.esm.create_import_map()
395
+
396
+ try:
397
+ render_context = context.app_object
398
+ app_state = app_state_initial
399
+ with pdb_guard():
400
+ widget, render_context = _run_app(
401
+ app_state,
402
+ app_script,
403
+ pathname,
404
+ render_context=render_context,
405
+ )
406
+ if render_context is None:
407
+ assert context.container is not None
408
+ context.container.children = [widget]
409
+
410
+ if render_context:
411
+ context.app_object = render_context
412
+
413
+ except BaseException as e:
414
+ error = ""
415
+ error = "".join(traceback.format_exception(None, e, e.__traceback__))
416
+ print(error, file=sys.stdout, flush=True) # noqa
417
+ # widget = widgets.Label(value="Error, see server logs")
418
+ import html
419
+
420
+ error = html.escape(error)
421
+ with context:
422
+ widget = widgets.HTML(f"<pre>{error}</pre>", layout=widgets.Layout(overflow="auto"))
423
+ container.children = [widget]
424
+
425
+
426
+ def load_themes(themes: Dict[str, Dict[str, str]], dark: bool):
427
+ # While these usually gets set from the frontend, in solara (server) we want to know theme information directly at the first
428
+ # render. Also, using the same trait allows us to write code which works on all widgets platforms, instead
429
+ # or using something different when running under solara server
430
+ from solara.lab.components.theming import _set_theme, theme
431
+
432
+ _set_theme(themes)
433
+ theme.dark_effective = dark
434
+
435
+
436
+ def solara_comm_target(comm, msg_first):
437
+ app: Optional[AppScript] = None
438
+
439
+ def on_msg(msg):
440
+ nonlocal app
441
+ comm = comm_ref()
442
+ assert comm is not None
443
+ context = kernel_context.get_current_context()
444
+ data = msg["content"]["data"]
445
+ method = data["method"]
446
+ if method == "run":
447
+ args = data["args"]
448
+ path = args.get("path", "")
449
+ app_name = args.get("appName") or "__default__"
450
+ app = apps[app_name]
451
+ context = kernel_context.get_current_context()
452
+ import ipyvuetify
453
+
454
+ container = ipyvuetify.Html(tag="div")
455
+ context.container = container
456
+ themes = args.get("themes")
457
+ dark = args.get("dark")
458
+ load_themes(themes, dark)
459
+ try:
460
+ load_app_widget(None, app, path)
461
+ except Exception as e:
462
+ msg = f"Error loading app: from path {path} and app {app_name}"
463
+ logger.exception(msg)
464
+ raise RuntimeError(msg) from e
465
+ comm.send({"method": "finished", "widget_id": context.container._model_id})
466
+ elif method == "app-status":
467
+ context = kernel_context.get_current_context()
468
+ # if there is no container, we never ran the app
469
+ if context.container is not None:
470
+ logger.info("app-status check: %s app started", context.id)
471
+ comm.send({"method": "app-status", "started": True})
472
+ else:
473
+ logger.info("app-status check: %s app not started", context.id)
474
+ comm.send({"method": "app-status", "started": False})
475
+
476
+ elif method == "reload":
477
+ from solara.lab.components.theming import _get_theme, theme
478
+
479
+ assert app is not None
480
+ context = kernel_context.get_current_context()
481
+ path = data.get("path", "")
482
+ current_theme = theme._instance.value
483
+ theme_dict = _get_theme(current_theme)
484
+
485
+ with context:
486
+ context.restart()
487
+ load_themes(theme_dict, current_theme.dark_effective)
488
+ load_app_widget(context.state, app, path)
489
+ comm.send({"method": "finished"})
490
+ else:
491
+ logger.error("Unknown comm method called on solara.control comm: %s", method)
492
+
493
+ def reload():
494
+ comm = comm_ref()
495
+ assert comm is not None
496
+ context = kernel_context.get_current_context()
497
+ # we don't reload the app ourself, we send a message to the client
498
+ # this ensures that we don't run code of any client that for some reason is connected
499
+ # but not working anymore. And it indirectly passes a message from the current thread
500
+ # (which is that of the Reloader/watchdog), to the thread of the client
501
+ logger.debug(f"Send reload to client: {context.id}")
502
+ comm.send({"method": "reload"})
503
+
504
+ comm.on_msg(on_msg)
505
+ comm_ref = weakref.ref(comm)
506
+ del comm
507
+
508
+ kernel_context.get_current_context().reload = reload
509
+
510
+
511
+ def register_solara_comm_target(kernel: Kernel):
512
+ kernel.comm_manager.register_target("solara.control", solara_comm_target)
513
+
514
+
515
+ from . import patch # noqa
516
+
517
+ patch.patch()
518
+ # the default app (used in solara-server)
519
+ if "SOLARA_APP" in os.environ:
520
+ with pdb_guard():
521
+ apps["__default__"] = AppScript(os.environ.get("SOLARA_APP", "solara.website.pages:Page"))
522
+
523
+
524
+ @solara.util.once
525
+ def ensure_apps_initialized():
526
+ for app in apps.values():
527
+ app.init()
@@ -0,0 +1 @@
1
+ /* not empty *
@@ -0,0 +1 @@
1
+ /* not empty */
Binary file
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="65" height="65"><svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M57.11 30.64L61.47 17.87L48.7 13.51L42.76 1.39999L30.65 7.34999L17.87 2.97999L13.51 15.75L1.40002 21.7L7.35002 33.81L2.99002 46.58L15.76 50.94L21.71 63.06L33.82 57.11L46.59 61.47L50.95 48.7L63.06 42.75L57.11 30.64ZM54.26 34.39L34.39 54.26C33.19 55.46 31.25 55.46 30.05 54.26L10.2 34.4C9.00002 33.2 9.00002 31.26 10.2 30.07L30.06 10.2C31.26 8.99999 33.2 8.99999 34.4 10.2L54.27 30.07C55.47 31.27 55.47 33.21 54.27 34.4L54.26 34.39Z" fill="#FFCF64"></path>
3
+ <path d="M53.62 19.42L51.65 6.07L38.3 8.04L27.46 0L19.42 10.84L6.07 12.82L8.04 26.17L0 37L10.84 45.04L12.81 58.39L26.16 56.42L37 64.46L45.04 53.62L58.39 51.64L56.42 38.29L64.46 27.45L53.62 19.4V19.42ZM52.8 24.06L44.24 50.82C43.72 52.43 42 53.32 40.39 52.81L13.63 44.25C12.02 43.74 11.13 42.01 11.64 40.4L20.21 13.64C20.72 12.03 22.45 11.14 24.06 11.65L50.82 20.21C52.43 20.72 53.32 22.45 52.81 24.06H52.8Z" fill="#FF8C3E"></path>
4
+ </svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
5
+ </style></svg>