solara 1.29.1__py2.py3-none-any.whl → 1.30.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. solara/__init__.py +5 -5
  2. solara/__main__.py +6 -2
  3. solara/autorouting.py +79 -38
  4. solara/cache.py +2 -2
  5. solara/checks.html +1 -1
  6. solara/components/__init__.py +1 -1
  7. solara/components/applayout.py +5 -5
  8. solara/components/button.py +4 -4
  9. solara/components/card.py +1 -2
  10. solara/components/component_vue.py +1 -1
  11. solara/components/cross_filter.py +6 -7
  12. solara/components/datatable.py +2 -3
  13. solara/components/figure_altair.py +1 -1
  14. solara/components/file_download.py +2 -2
  15. solara/components/file_drop.py +76 -33
  16. solara/components/file_drop.vue +24 -10
  17. solara/components/head.py +1 -2
  18. solara/components/head_tag.py +2 -3
  19. solara/components/link.py +3 -4
  20. solara/components/meta.py +1 -1
  21. solara/components/misc.py +5 -9
  22. solara/datatypes.py +2 -2
  23. solara/hooks/use_reactive.py +2 -2
  24. solara/lab/components/confirmation_dialog.py +1 -1
  25. solara/lab/components/tabs.py +6 -6
  26. solara/reactive.py +1 -1
  27. solara/routing.py +9 -8
  28. solara/server/app.py +44 -1
  29. solara/server/assets/style.css +6 -0
  30. solara/server/esm.py +28 -4
  31. solara/server/kernel_context.py +75 -7
  32. solara/server/patch.py +3 -0
  33. solara/server/reload.py +2 -2
  34. solara/server/server.py +3 -3
  35. solara/server/settings.py +1 -0
  36. solara/server/starlette.py +66 -33
  37. solara/server/static/solara_bootstrap.py +1 -1
  38. solara/server/templates/solara.html.j2 +62 -42
  39. solara/tasks.py +1 -6
  40. solara/util.py +23 -1
  41. solara/website/assets/custom.css +56 -0
  42. solara/website/components/__init__.py +1 -0
  43. solara/website/components/algolia_api.vue +157 -0
  44. solara/website/components/docs.py +118 -0
  45. solara/website/components/header.py +20 -10
  46. solara/website/components/hero.py +1 -1
  47. solara/website/pages/__init__.py +223 -20
  48. solara/website/pages/apps/jupyter-dashboard-1.py +1 -1
  49. solara/website/pages/apps/multipage/__init__.py +1 -1
  50. solara/website/pages/apps/multipage/page2.py +1 -1
  51. solara/website/pages/apps/scatter.py +21 -7
  52. solara/website/pages/changelog/__init__.py +8 -0
  53. solara/website/pages/{docs/content/95-changelog.md → changelog/changelog.md} +28 -2
  54. solara/website/pages/contact/__init__.py +8 -0
  55. solara/website/pages/documentation/__init__.py +184 -0
  56. solara/website/pages/documentation/advanced/__init__.py +36 -0
  57. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  58. solara/website/pages/{docs/content/10-howto/20-multipage.md → documentation/advanced/content/10-howto/10-multipage.md} +4 -5
  59. solara/website/pages/{docs/content/10-howto/30-layout.md → documentation/advanced/content/10-howto/20-layout.md} +21 -21
  60. solara/website/pages/{docs/content/10-howto/80-embed.md → documentation/advanced/content/10-howto/40-embed.md} +1 -1
  61. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/06-ipyvuetify.md +1 -1
  62. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/12-reacton-basics.md +1 -1
  63. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/15-anatomy.md +2 -2
  64. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/18-containers.md +3 -3
  65. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/40-routing.md +9 -9
  66. solara/website/pages/{docs → documentation/advanced}/content/20-understanding/50-solara-server.md +1 -1
  67. solara/website/pages/{docs/content/50-enterprise → documentation/advanced/content/30-enterprise}/10-oauth.md +3 -3
  68. solara/website/pages/{docs/content/10-howto → documentation/advanced/content/40-development}/01-contribute.md +5 -5
  69. solara/website/pages/{docs/content/90-development → documentation/advanced/content/40-development}/10-setup.md +2 -2
  70. solara/website/pages/documentation/advanced/content/__init__.py +0 -0
  71. solara/website/pages/documentation/api/__init__.py +19 -0
  72. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  73. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  74. solara/website/pages/{api → documentation/api/hooks}/use_effect.md +3 -3
  75. solara/website/pages/{api → documentation/api/hooks}/use_effect.py +2 -1
  76. solara/website/pages/{api → documentation/api/hooks}/use_memo.md +2 -2
  77. solara/website/pages/{api → documentation/api/hooks}/use_memo.py +2 -1
  78. solara/website/pages/{api → documentation/api/hooks}/use_reactive.py +1 -2
  79. solara/website/pages/{api → documentation/api/hooks}/use_state.py +1 -2
  80. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  81. solara/website/pages/{api → documentation/api/routing}/generate_routes.py +1 -2
  82. solara/website/pages/{api → documentation/api/routing}/generate_routes_directory.py +1 -2
  83. solara/website/pages/{api → documentation/api/routing}/use_route.py +2 -2
  84. solara/website/pages/{api → documentation/api/routing}/use_router.py +1 -2
  85. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  86. solara/website/pages/{api → documentation/api/utilities}/component_vue.py +1 -2
  87. solara/website/pages/{api → documentation/api/utilities}/computed.py +2 -2
  88. solara/website/pages/{api → documentation/api/utilities}/display.py +1 -2
  89. solara/website/pages/{api → documentation/api/utilities}/get_kernel_id.py +2 -2
  90. solara/website/pages/{api → documentation/api/utilities}/get_session_id.py +2 -2
  91. solara/website/pages/{api → documentation/api/utilities}/on_kernel_start.py +9 -3
  92. solara/website/pages/{api → documentation/api/utilities}/reactive.py +1 -2
  93. solara/website/pages/{api → documentation/api/utilities}/widget.py +2 -2
  94. solara/website/pages/documentation/components/__init__.py +12 -0
  95. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  96. solara/website/pages/documentation/components/data/__init__.py +9 -0
  97. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  98. solara/website/pages/{api → documentation/components/enterprise}/avatar.py +1 -2
  99. solara/website/pages/{api → documentation/components/enterprise}/avatar_menu.py +1 -2
  100. solara/website/pages/documentation/components/input/__init__.py +9 -0
  101. solara/website/pages/{api → documentation/components/input}/checkbox.py +1 -2
  102. solara/website/pages/documentation/components/input/file_drop.py +75 -0
  103. solara/website/pages/{api → documentation/components/input}/input.py +1 -2
  104. solara/website/pages/{api → documentation/components/input}/select.py +1 -2
  105. solara/website/pages/{api → documentation/components/input}/slider.py +1 -2
  106. solara/website/pages/{api → documentation/components/input}/switch.py +1 -2
  107. solara/website/pages/{api → documentation/components/input}/togglebuttons.py +1 -2
  108. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  109. solara/website/pages/{api → documentation/components/lab}/chat.py +2 -3
  110. solara/website/pages/{api → documentation/components/lab}/cookies_headers.py +1 -1
  111. solara/website/pages/{api → documentation/components/lab}/input_date.py +1 -2
  112. solara/website/pages/{api → documentation/components/lab}/menu.py +1 -2
  113. solara/website/pages/{api → documentation/components/lab}/task.py +1 -2
  114. solara/website/pages/{api → documentation/components/lab}/theming.py +1 -2
  115. solara/website/pages/{api → documentation/components/lab}/use_task.py +1 -2
  116. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  117. solara/website/pages/{api → documentation/components/layout}/app_bar.py +1 -2
  118. solara/website/pages/{api → documentation/components/layout}/app_bar_title.py +1 -2
  119. solara/website/pages/{api → documentation/components/layout}/card.py +1 -2
  120. solara/website/pages/{api → documentation/components/layout}/card_actions.py +1 -2
  121. solara/website/pages/{api → documentation/components/layout}/griddraggable.py +1 -1
  122. solara/website/pages/{api → documentation/components/layout}/gridfixed.py +1 -1
  123. solara/website/pages/{api → documentation/components/layout}/hbox.py +1 -1
  124. solara/website/pages/{api → documentation/components/layout}/vbox.py +1 -1
  125. solara/website/pages/documentation/components/output/__init__.py +9 -0
  126. solara/website/pages/{api → documentation/components/output}/file_download.py +1 -2
  127. solara/website/pages/{api → documentation/components/output}/image.py +1 -2
  128. solara/website/pages/{api → documentation/components/output}/tooltip.py +1 -2
  129. solara/website/pages/documentation/components/page/__init__.py +9 -0
  130. solara/website/pages/documentation/components/status/__init__.py +9 -0
  131. solara/website/pages/{api → documentation/components/status}/error.py +3 -3
  132. solara/website/pages/{api → documentation/components/status}/info.py +3 -3
  133. solara/website/pages/{api → documentation/components/status}/progress.py +1 -2
  134. solara/website/pages/{api → documentation/components/status}/spinner.py +1 -2
  135. solara/website/pages/{api → documentation/components/status}/success.py +3 -3
  136. solara/website/pages/{api → documentation/components/status}/warning.py +3 -3
  137. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  138. solara/website/pages/{api → documentation/components/viz}/plotly.py +1 -0
  139. solara/website/pages/{examples → documentation/examples}/__init__.py +3 -43
  140. solara/website/pages/{examples → documentation/examples}/general/deploy_model.py +3 -3
  141. solara/website/pages/{examples → documentation/examples}/general/login_oauth.py +1 -1
  142. solara/website/pages/{examples → documentation/examples}/general/vue_component.py +1 -2
  143. solara/website/pages/{examples → documentation/examples}/libraries/altair.py +2 -3
  144. solara/website/pages/{examples → documentation/examples}/libraries/ipyleaflet_advanced.py +1 -1
  145. solara/website/pages/{examples → documentation/examples}/utilities/countdown_timer.py +1 -1
  146. solara/website/pages/{examples → documentation/examples}/visualization/plotly.py +1 -2
  147. solara/website/pages/documentation/faq/__init__.py +11 -0
  148. solara/website/pages/{docs → documentation/getting_started}/__init__.py +7 -1
  149. solara/website/pages/{docs/content/03-quickstart.md → documentation/getting_started/content/00-quickstart.md} +2 -2
  150. solara/website/pages/{docs/content/00-introduction.md → documentation/getting_started/content/01-introduction.md} +16 -16
  151. solara/website/pages/{docs → documentation/getting_started}/content/02-installing.md +1 -1
  152. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +9 -0
  153. solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/20-web-app.md +4 -4
  154. solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/30-ipywidgets.md +9 -9
  155. solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/40-streamlit.md +13 -13
  156. solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/50-dash.md +3 -3
  157. solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/_data_science.ipynb +5 -5
  158. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +7 -0
  159. solara/website/pages/{docs/content/07-fundamentals → documentation/getting_started/content/05-fundamentals}/10-components.md +2 -2
  160. solara/website/pages/{docs/content/07-fundamentals → documentation/getting_started/content/05-fundamentals}/50-state-management.md +3 -3
  161. solara/website/pages/documentation/getting_started/content/06-reference/00-overview.md +3 -0
  162. solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/41-asset-files.md +1 -1
  163. solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/60-static-site-generation.md +1 -1
  164. solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/70-search.md +1 -1
  165. solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/80-reloading.md +3 -3
  166. solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/95-caching.md +1 -1
  167. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +3 -0
  168. solara/website/pages/{docs/content/30-deploying → documentation/getting_started/content/07-deploying}/10-self-hosted.md +3 -3
  169. solara/website/pages/{docs/content/30-deploying → documentation/getting_started/content/07-deploying}/20-cloud-hosted.md +1 -1
  170. solara/website/pages/documentation/getting_started/content/__init__.py +0 -0
  171. solara/website/pages/showcase/__init__.py +1 -1
  172. solara/website/pages/showcase/domino_code_assist.py +1 -1
  173. solara/website/pages/showcase/solara_dev.py +1 -1
  174. solara/website/public/social/discord.svg +1 -0
  175. solara/website/public/social/github.svg +1 -0
  176. solara/website/public/social/twitter.svg +3 -0
  177. {solara-1.29.1.dist-info → solara-1.30.0.dist-info}/METADATA +8 -7
  178. solara-1.30.0.dist-info/RECORD +438 -0
  179. {solara-1.29.1.dist-info → solara-1.30.0.dist-info}/WHEEL +1 -1
  180. solara/website/pages/api/__init__.py +0 -292
  181. solara/website/pages/api/default_layout.py +0 -16
  182. solara/website/pages/api/file_drop.py +0 -36
  183. solara/website/pages/docs/content/04-tutorial/00-overview.md +0 -9
  184. solara/website/pages/docs/content/07-fundamentals/00-overview.md +0 -7
  185. solara/website/pages/docs/content/15-reference/00-overview.md +0 -6
  186. solara/website/pages/docs/content/30-deploying/00-overview.md +0 -3
  187. solara-1.29.1.dist-info/RECORD +0 -411
  188. /solara/website/pages/{docs/content/99-contact.md → contact/contact.md} +0 -0
  189. /solara/website/pages/{docs → documentation/advanced}/content/10-howto/00-overview.md +0 -0
  190. /solara/website/pages/{docs/content/10-howto/50-testing.md → documentation/advanced/content/10-howto/30-testing.md} +0 -0
  191. /solara/website/pages/{docs/content/10-howto/51-debugging.md → documentation/advanced/content/10-howto/31-debugging.md} +0 -0
  192. /solara/website/pages/{docs/content/10-howto/ipywidget_libraries.md → documentation/advanced/content/10-howto/50-ipywidget_libraries.md} +0 -0
  193. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/00-introduction.md +0 -0
  194. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/05-ipywidgets.md +0 -0
  195. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/10-reacton.md +0 -0
  196. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/17-rules-of-hooks.md +0 -0
  197. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/20-solara.md +0 -0
  198. /solara/website/pages/{docs → documentation/advanced}/content/20-understanding/60-voila.md +0 -0
  199. /solara/website/pages/{docs/content/50-enterprise → documentation/advanced/content/30-enterprise}/00-overview.md +0 -0
  200. /solara/website/pages/{docs/content/__init__.py → documentation/advanced/content/40-development/00-overview.md} +0 -0
  201. /solara/website/pages/{api → documentation/api/cross_filter}/cross_filter_dataframe.py +0 -0
  202. /solara/website/pages/{api → documentation/api/cross_filter}/cross_filter_report.py +0 -0
  203. /solara/website/pages/{api → documentation/api/cross_filter}/cross_filter_select.py +0 -0
  204. /solara/website/pages/{api → documentation/api/cross_filter}/cross_filter_slider.py +0 -0
  205. /solara/website/pages/{api → documentation/api/hooks}/use_cross_filter.py +0 -0
  206. /solara/website/pages/{api → documentation/api/hooks}/use_dark_effective.py +0 -0
  207. /solara/website/pages/{api → documentation/api/hooks}/use_exception.py +0 -0
  208. /solara/website/pages/{api → documentation/api/hooks}/use_previous.py +0 -0
  209. /solara/website/pages/{api → documentation/api/hooks}/use_state_or_update.py +0 -0
  210. /solara/website/pages/{api → documentation/api/hooks}/use_thread.md +0 -0
  211. /solara/website/pages/{api → documentation/api/hooks}/use_thread.py +0 -0
  212. /solara/website/pages/{api → documentation/api/hooks}/use_trait_observe.py +0 -0
  213. /solara/website/pages/{api → documentation/api/routing}/resolve_path.py +0 -0
  214. /solara/website/pages/{api → documentation/api/routing}/route.py +0 -0
  215. /solara/website/pages/{api → documentation/api/utilities}/memoize.py +0 -0
  216. /solara/website/pages/{api → documentation/components/advanced}/link.py +0 -0
  217. /solara/website/pages/{api → documentation/components/advanced}/meta.py +0 -0
  218. /solara/website/pages/{api → documentation/components/advanced}/style.py +0 -0
  219. /solara/website/pages/{api → documentation/components}/common.py +0 -0
  220. /solara/website/pages/{api → documentation/components/data}/dataframe.py +0 -0
  221. /solara/website/pages/{api → documentation/components/data}/pivot_table.py +0 -0
  222. /solara/website/pages/{api → documentation/components/input}/button.py +0 -0
  223. /solara/website/pages/{api → documentation/components/input}/file_browser.py +0 -0
  224. /solara/website/pages/{api → documentation/components/lab}/confirmation_dialog.py +0 -0
  225. /solara/website/pages/{api → documentation/components/lab}/tab.py +0 -0
  226. /solara/website/pages/{api → documentation/components/lab}/tabs.py +0 -0
  227. /solara/website/pages/{api → documentation/components/layout}/app_layout.py +0 -0
  228. /solara/website/pages/{api → documentation/components/layout}/column.py +0 -0
  229. /solara/website/pages/{api → documentation/components/layout}/columns.py +0 -0
  230. /solara/website/pages/{api → documentation/components/layout}/columns_responsive.py +0 -0
  231. /solara/website/pages/{api → documentation/components/layout}/row.py +0 -0
  232. /solara/website/pages/{api → documentation/components/layout}/sidebar.py +0 -0
  233. /solara/website/pages/{api → documentation/components/output}/html.py +0 -0
  234. /solara/website/pages/{api → documentation/components/output}/markdown.py +0 -0
  235. /solara/website/pages/{api → documentation/components/output}/markdown_editor.py +0 -0
  236. /solara/website/pages/{api → documentation/components/output}/sql_code.py +0 -0
  237. /solara/website/pages/{api → documentation/components/page}/head.py +0 -0
  238. /solara/website/pages/{api → documentation/components/page}/title.py +0 -0
  239. /solara/website/pages/{api → documentation/components/viz}/altair.py +0 -0
  240. /solara/website/pages/{api → documentation/components/viz}/echarts.py +0 -0
  241. /solara/website/pages/{api → documentation/components/viz}/matplotlib.py +0 -0
  242. /solara/website/pages/{api → documentation/components/viz}/plotly_express.py +0 -0
  243. /solara/website/pages/{examples → documentation/examples}/ai/__init__.py +0 -0
  244. /solara/website/pages/{examples → documentation/examples}/ai/chatbot.py +0 -0
  245. /solara/website/pages/{examples → documentation/examples}/ai/tokenizer.py +0 -0
  246. /solara/website/pages/{examples → documentation/examples}/basics/__init__.py +0 -0
  247. /solara/website/pages/{examples → documentation/examples}/basics/sine.py +0 -0
  248. /solara/website/pages/{examples → documentation/examples}/fullscreen/__init__.py +0 -0
  249. /solara/website/pages/{examples → documentation/examples}/fullscreen/authorization.py +0 -0
  250. /solara/website/pages/{examples → documentation/examples}/fullscreen/layout_demo.py +0 -0
  251. /solara/website/pages/{examples → documentation/examples}/fullscreen/multipage.py +0 -0
  252. /solara/website/pages/{examples → documentation/examples}/fullscreen/scatter.py +0 -0
  253. /solara/website/pages/{examples → documentation/examples}/fullscreen/scrolling.py +0 -0
  254. /solara/website/pages/{examples → documentation/examples}/fullscreen/tutorial_streamlit.py +0 -0
  255. /solara/website/pages/{examples → documentation/examples}/general/__init__.py +0 -0
  256. /solara/website/pages/{examples → documentation/examples}/general/custom_storage.py +0 -0
  257. /solara/website/pages/{examples → documentation/examples}/general/live_update.py +0 -0
  258. /solara/website/pages/{examples → documentation/examples}/general/mycard.vue +0 -0
  259. /solara/website/pages/{examples → documentation/examples}/general/pokemon_search.py +0 -0
  260. /solara/website/pages/{examples → documentation/examples}/ipycanvas.py +0 -0
  261. /solara/website/pages/{examples → documentation/examples}/libraries/__init__.py +0 -0
  262. /solara/website/pages/{examples → documentation/examples}/libraries/bqplot.py +0 -0
  263. /solara/website/pages/{examples → documentation/examples}/libraries/ipyleaflet.py +0 -0
  264. /solara/website/pages/{examples → documentation/examples}/utilities/__init__.py +0 -0
  265. /solara/website/pages/{examples → documentation/examples}/utilities/calculator.py +0 -0
  266. /solara/website/pages/{examples → documentation/examples}/utilities/todo.py +0 -0
  267. /solara/website/pages/{examples → documentation/examples}/visualization/__init__.py +0 -0
  268. /solara/website/pages/{examples → documentation/examples}/visualization/annotator.py +0 -0
  269. /solara/website/pages/{examples → documentation/examples}/visualization/linked_views.py +0 -0
  270. /solara/website/pages/{docs → documentation/faq}/content/99-faq.md +0 -0
  271. /solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/10_data_science.py +0 -0
  272. /solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/60-jupyter-dashboard-part1.py +0 -0
  273. /solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/SF_crime_sample.csv.gz +0 -0
  274. /solara/website/pages/{docs/content/04-tutorial → documentation/getting_started/content/04-tutorials}/_jupyter_dashboard_1.ipynb +0 -0
  275. /solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/40-static_files.md +0 -0
  276. /solara/website/pages/{docs/content/15-reference → documentation/getting_started/content/06-reference}/90-notebook-support.md +0 -0
  277. /solara/website/pages/{docs/content/lab → documentation/getting_started/content/08-lab}/00-what-is-lab.md +0 -0
  278. /solara/website/pages/{docs → documentation/getting_started}/content/90-troubleshoot.md +0 -0
  279. {solara-1.29.1.data → solara-1.30.0.data}/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -0
  280. {solara-1.29.1.data → solara-1.30.0.data}/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -0
  281. {solara-1.29.1.dist-info → solara-1.30.0.dist-info}/entry_points.txt +0 -0
  282. {solara-1.29.1.dist-info → solara-1.30.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,18 @@
1
1
  <template>
2
2
  <div ref="dropzone" class="solara-file-drop" effectAllowed="move">
3
- {{ (file_info && file_info.length === 1) ? file_info[0].name : label }}
3
+ <template v-if="file_info && file_info.length > 0">
4
+ <template v-if="multiple">
5
+ <div v-for="file in file_info">
6
+ {{ file.name }}
7
+ </div>
8
+ </template>
9
+ <template v-else>
10
+ {{ file_info[0].name }}
11
+ </template>
12
+ </template>
13
+ <template v-else>
14
+ {{ label }}
15
+ </template>
4
16
  </div>
5
17
  </template>
6
18
 
@@ -16,16 +28,17 @@ module.exports = {
16
28
  event.preventDefault();
17
29
  const items = await Promise.all([...event.dataTransfer.items]);
18
30
  const files = items.map(i => i.webkitGetAsEntry())
19
- const fileHolder = files.filter(f => f.isFile)[0]
20
- const file = await new Promise((rs, rj) => fileHolder.file(rs, rj))
31
+ const fileHolders = files.filter(f => f.isFile)
32
+ const nativeFilesPromises = fileHolders.map(fileHolder => new Promise((rs, rj) => fileHolder.file(rs, rj)))
33
+ const nativeFiles = await Promise.all(nativeFilesPromises)
21
34
 
22
- this.native_file_info = [file]
35
+ this.native_file_info = nativeFiles
23
36
  this.file_info = this.native_file_info.map(
24
- ({name, isFile, size}) => ({
25
- name,
26
- isFile,
27
- size,
28
- }));
37
+ ({name, size}) => ({
38
+ name,
39
+ isFile: true,
40
+ size,
41
+ }));
29
42
  });
30
43
  },
31
44
  methods: {
@@ -64,6 +77,7 @@ module.exports = {
64
77
  height: 100px;
65
78
  border: 1px dashed gray;
66
79
  margin: 8px 0;
67
- padding: 8px
80
+ padding: 8px;
81
+ overflow: auto;
68
82
  }
69
83
  </style>
solara/components/head.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from typing import List
2
2
 
3
3
  import reacton
4
-
5
4
  import solara
6
5
 
7
6
 
@@ -9,7 +8,7 @@ import solara
9
8
  def Head(children: List[reacton.core.Element] = []):
10
9
  """A component that manager the "head" tag of the page to avoid duplicate tags, such as titles.
11
10
 
12
- Currently only supports the [title](/api/title) tag as child, e.g.:
11
+ Currently only supports the [title](/documentation/components/page/title) tag as child, e.g.:
13
12
 
14
13
  ```python
15
14
  import solara
@@ -2,9 +2,8 @@ from typing import Optional
2
2
 
3
3
  import ipyvuetify as vy
4
4
  import reacton.core
5
- import traitlets
6
-
7
5
  import solara
6
+ import traitlets
8
7
 
9
8
 
10
9
  class HeadTagWidget(vy.VuetifyTemplate):
@@ -19,7 +18,7 @@ class HeadTagWidget(vy.VuetifyTemplate):
19
18
  def HeadTag(tagname: str, key=None, attributes: Optional[dict] = None):
20
19
  """Add a child element to head element, or replace a meta tag with the same tagname and key.
21
20
 
22
- This component should be used inside a [Head](/api/head) component, e.g.:
21
+ This component should be used inside a [Head](/documentation/components/page/head) component, e.g.:
23
22
 
24
23
  ```python
25
24
  import solara
solara/components/link.py CHANGED
@@ -2,7 +2,6 @@ from typing import Dict, List, Union
2
2
 
3
3
  import ipyvue as vue
4
4
  import reacton.ipyvue as vuer
5
-
6
5
  import solara
7
6
 
8
7
 
@@ -18,8 +17,8 @@ def Link(
18
17
 
19
18
  See also:
20
19
 
21
- * [Multipage](/docs/howto/multipage).
22
- * [Understanding Routing](/docs/understanding/routing).
20
+ * [Multipage](/documentation/advanced/howto/multipage).
21
+ * [Understanding Routing](/documentation/advanced/understanding/routing).
23
22
 
24
23
  Most common usage is in combination with a button, e.g.:
25
24
 
@@ -32,7 +31,7 @@ def Link(
32
31
  ## Arguments
33
32
 
34
33
  * path_or_route: the path or route to navigate to. Paths should be absolute, e.g. '/fruit/banana'.
35
- If a route is given, [`resolve_path`](/api/resolve_path)] will be used to resolve to the absolute path.
34
+ If a route is given, [`resolve_path`](/documentation/api/routing/resolve_path)] will be used to resolve to the absolute path.
36
35
  * children: the children of the link. If a child is clicked, the link will be followed.
37
36
  * nofollow: If True, the link will not be followed by web crawlers (such as google).
38
37
  * style: CSS styles to apply to the HTML link element. Either a string or a dictionary.
solara/components/meta.py CHANGED
@@ -9,7 +9,7 @@ from .head_tag import HeadTag
9
9
  def Meta(name: Optional[str] = None, property: Optional[str] = None, content: Optional[str] = None):
10
10
  """Add a meta tag to the head element, or replace a meta tag with the same name and or property.
11
11
 
12
- This component should be used inside a [Head](/api/head) component, e.g.:
12
+ This component should be used inside a [Head](/documentation/components/page/head) component, e.g.:
13
13
 
14
14
  ```python
15
15
  import solara
solara/components/misc.py CHANGED
@@ -3,7 +3,6 @@ from typing import Any, Callable, Dict, List, Union
3
3
 
4
4
  import reacton
5
5
  import reacton.ipyvuetify as v
6
-
7
6
  import solara
8
7
  import solara.widgets
9
8
  from solara.util import _combine_classes
@@ -159,7 +158,7 @@ def HBox(children=[], grow=True, align_items="stretch", classes: List[str] = [])
159
158
  def Row(children=[], gap="12px", justify="start", margin: int = 0, classes: List[str] = [], style: Union[str, Dict[str, str], None] = None):
160
159
  """Lays out children in a row, side by side, with the given gap between them.
161
160
 
162
- See also [Column](/api/column).
161
+ See also [Column](/documentation/components/layout/column).
163
162
 
164
163
  Example with three children side by side:
165
164
 
@@ -200,7 +199,7 @@ def Row(children=[], gap="12px", justify="start", margin: int = 0, classes: List
200
199
  def Column(children=[], gap="12px", align="stretch", margin: int = 0, classes: List[str] = [], style: Union[str, Dict[str, str], None] = None):
201
200
  """Lays out children in a column on top of each other, with the given gap between them.
202
201
 
203
- See also [Row](/api/row).
202
+ See also [Row](/documentation/components/layout/row).
204
203
 
205
204
  Example with three children on top of each other:
206
205
 
@@ -287,17 +286,14 @@ def FigurePlotly(
287
286
  "plotly_hover": on_hover,
288
287
  "plotly_unhover": on_unhover,
289
288
  "plotly_selected": on_selection,
290
- "plotly_deselect": on_deselect
289
+ "plotly_deselect": on_deselect,
291
290
  }
292
-
291
+
293
292
  callback = event_mapping.get(event_type)
294
293
  if callback:
295
294
  callback(data)
296
295
 
297
- fig_element = FigureWidget.element(
298
- on__js2py_pointsCallback=on_points_callback,
299
- on__js2py_relayout=on_relayout
300
- )
296
+ fig_element = FigureWidget.element(on__js2py_pointsCallback=on_points_callback, on__js2py_relayout=on_relayout)
301
297
 
302
298
  def update_data():
303
299
  fig_widget: FigureWidget = solara.get_widget(fig_element)
solara/datatypes.py CHANGED
@@ -114,8 +114,8 @@ class Route:
114
114
 
115
115
  ## See also
116
116
 
117
- * [Multipage](/docs/howto/multipage).
118
- * [Understanding Routing](/docs/understanding/routing).
117
+ * [Multipage](/documentation/advanced/howto/multipage).
118
+ * [Understanding Routing](/documentation/advanced/understanding/routing).
119
119
 
120
120
  """
121
121
 
@@ -13,7 +13,7 @@ def use_reactive(
13
13
 
14
14
  It is a useful alternative to `use_state` when you want to use a
15
15
  reactive variable for the component state.
16
- See also [our documentation on state management](/docs/fundamentals/state-management).
16
+ See also [our documentation on state management](/documentation/getting_started/fundamentals/state-management).
17
17
 
18
18
  If the variable passed is a reactive variable, it will be returned instead and no
19
19
  new reactive variable will be created. This is useful for implementing component
@@ -92,7 +92,7 @@ def use_reactive(
92
92
  except RuntimeError as e:
93
93
  raise RuntimeError(
94
94
  "use_reactive must be called from a component function, inside the render function.\n"
95
- "Do not call it top level, use [solara.reactive()](https://solara.dev/api/reactive) instead."
95
+ "Do not call it top level, use [solara.reactive()](https://solara.dev/documentation/api/utilities/reactive) instead."
96
96
  ) from e
97
97
  on_change_ref.current = on_change
98
98
 
@@ -60,7 +60,7 @@ def ConfirmationDialog(
60
60
  ):
61
61
  """A dialog used to confirm a user action.
62
62
 
63
- (*Note: [This component is experimental and its API may change in the future](/docs/lab).*)
63
+ (*Note: [This component is experimental and its API may change in the future](/documentation/getting_started/lab).*)
64
64
 
65
65
  By default, has a title, a text explaining the
66
66
  decision to be made, and two buttons "OK" and "Cancel".
@@ -17,9 +17,9 @@ def Tab(
17
17
  ):
18
18
  """An item in a Tabs component.
19
19
 
20
- (*Note: [This component is experimental and its API may change in the future](/docs/lab).*)
20
+ (*Note: [This component is experimental and its API may change in the future](/documentation/getting_started/lab).*)
21
21
 
22
- Should be a direct child of a [Tabs](/api/tabs).
22
+ Should be a direct child of a [Tabs](/documentation/components/lab/tabs).
23
23
 
24
24
  ## Arguments
25
25
  * `label`: The label of the tab.
@@ -62,12 +62,12 @@ def Tabs(
62
62
  ):
63
63
  """A tabbed container showing one tab at a time.
64
64
 
65
- (*Note: [This component is experimental and its API may change in the future](/docs/lab).*)
65
+ (*Note: [This component is experimental and its API may change in the future](/documentation/getting_started/lab).*)
66
66
 
67
- Note that if Tabs are used as a child of the [AppBar](/api/appbar) component, the tabs
67
+ Note that if Tabs are used as a child of the [AppBar](/documentation/components/layout/app_bar) component, the tabs
68
68
  will be placed under the app bar. See our [authorization app](/apps/authorization) for an example.
69
69
 
70
- If the children [Tab](/api/tab) elements are passed a `path_or_route` argument, the active tab
70
+ If the children [Tab](/documentation/components/lab/tab) elements are passed a `path_or_route` argument, the active tab
71
71
  will be based on the path of the current page.
72
72
 
73
73
 
@@ -89,7 +89,7 @@ def Tabs(
89
89
 
90
90
  ### Tabs with content
91
91
 
92
- This is usually only used when the tabs are placed in the [AppBar](/api/appbar) component.
92
+ This is usually only used when the tabs are placed in the [AppBar](/documentation/components/layout/app_bar) component.
93
93
 
94
94
  ```solara
95
95
  import solara
solara/reactive.py CHANGED
@@ -14,7 +14,7 @@ def reactive(value: T) -> Reactive[T]:
14
14
  Solara web applications. They provide an easy-to-use mechanism for keeping
15
15
  track of the changing state of data and for propagating those changes to
16
16
  the appropriate UI components. For managing local or component-specific
17
- state, consider using the [`solara.use_state()`](/api/use_state) function.
17
+ state, consider using the [`solara.use_state()`](/documentation/api/hooks/use_state) function.
18
18
 
19
19
 
20
20
  Reactive variables can be accessed using the `.value` attribute. To modify
solara/routing.py CHANGED
@@ -101,7 +101,7 @@ def use_route_level():
101
101
  def use_router() -> Router:
102
102
  """Returns the current router object.
103
103
 
104
- See also [Understanding Routing](/docs/understanding/routing).
104
+ See also [Understanding Routing](/documentation/advanced/understanding/routing).
105
105
 
106
106
  `use_router` returns the current router object. This is useful to build custom routing.
107
107
 
@@ -123,7 +123,7 @@ def use_router() -> Router:
123
123
  router = solara.use_router()
124
124
 
125
125
  def redirect():
126
- router.push(f"/api/use_route")
126
+ router.push(f"/documentation/api/routing/use_route")
127
127
 
128
128
  solara.Button("Navigate using an event", on_click=redirect)
129
129
  ```
@@ -138,7 +138,7 @@ def use_route(
138
138
  ) -> Tuple[Optional[solara.Route], List[solara.Route]]:
139
139
  """Returns (if found) the current route that matches the pathname, or None
140
140
 
141
- See also [Understanding Routing](/docs/understanding/routing).
141
+ See also [Understanding Routing](/documentation/advanced/understanding/routing).
142
142
 
143
143
  `use_route` returns (if found) the current route that matches the pathname, or None. It also returns all resolved routes of that level
144
144
  (i.e. all siblings and itself). This return tuple is useful to build custom navigation (e.g. using tabs or buttons).
@@ -166,9 +166,10 @@ def use_route(
166
166
 
167
167
  Note that all routes are relative, since a component does not know if it is embedded into a larger application, which may also do routing.
168
168
  Therefore you should never use the `route.path` for navigation since the route object has no knowledge of the full url
169
- (e.g. `/api/use_route/fruit/banana`) but only knows its small piece of the pathname (e.g. `banana`)
169
+ (e.g. `/documentation/api/routing/use_route/fruit/banana`) but only knows its small piece of the pathname (e.g. `banana`)
170
170
 
171
- Use [`resolve_path`](/api/resolve_path) to request the full url for navigation, or simply use the `Link` component that can do this for us.
171
+ Use [`resolve_path`](/documentation/api/routing/resolve_path) to request the full url for navigation,
172
+ or simply use the `Link` component that can do this for us.
172
173
 
173
174
  If the current route has children, any child component that calls `use_route` will return the matched route and its siblings of our children.
174
175
 
@@ -229,12 +230,12 @@ def resolve_path(path_or_route: Union[str, solara.Route], level=0) -> str:
229
230
 
230
231
  ## Arguments
231
232
 
232
- * path_or_route: a path string or a [`solara.Route`](/api/route) object to resolve.
233
+ * path_or_route: a path string or a [`solara.Route`](/documentation/api/routing/route) object to resolve.
233
234
 
234
235
  ## See also
235
236
 
236
- * [Multipage](/docs/howto/multipage).
237
- * [Understanding Routing](/docs/understanding/routing).
237
+ * [Multipage](/documentation/advanced/howto/multipage).
238
+ * [Understanding Routing](/documentation/advanced/understanding/routing).
238
239
 
239
240
 
240
241
  """
solara/server/app.py CHANGED
@@ -1,3 +1,4 @@
1
+ import dataclasses
1
2
  import importlib.util
2
3
  import logging
3
4
  import os
@@ -5,6 +6,7 @@ import pickle
5
6
  import sys
6
7
  import threading
7
8
  import traceback
9
+ import warnings
8
10
  from enum import Enum
9
11
  from pathlib import Path
10
12
  from typing import Any, Dict, List, Optional, cast
@@ -14,6 +16,7 @@ import reacton
14
16
  from reacton.core import Element, render
15
17
 
16
18
  import solara
19
+ from solara.util import nested_get
17
20
 
18
21
  from . import kernel_context, patch, reload, settings
19
22
  from .kernel import Kernel
@@ -149,9 +152,24 @@ class AppScript:
149
152
  routes = solara.generate_routes(mod)
150
153
 
151
154
  app = solara.autorouting.RenderPage(self.app_name)
152
- if not hasattr(routes[0].module, self.app_name) and routes[0].children:
155
+
156
+ # when the root moduled defined routes, skip the enclosing route object
157
+ if len(routes) == 1 and routes[0].module and hasattr(routes[0].module, "routes"):
158
+ if routes[0].component:
159
+ warnings.warn(
160
+ f"{self.name} has a component defined, but you are also defining routes."
161
+ " To avoid confusing, consider renaming the {self.app_name} component."
162
+ )
153
163
  routes = routes[0].children
154
164
 
165
+ if self.app_name != "Page":
166
+ # if we specified the app name, we replace the component
167
+ if len(routes) > 1:
168
+ raise ValueError(f"App {self.name} has multiple routes, but a default app name was given: {self.app_name}")
169
+ assert len(routes) == 1
170
+ component = nested_get(routes[0].module.__dict__, self.app_name, None)
171
+ routes = [dataclasses.replace(routes[0], component=component)]
172
+
155
173
  if settings.ssg.build_path is None:
156
174
  settings.ssg.build_path = self.directory.parent.resolve() / "build"
157
175
 
@@ -231,6 +249,31 @@ class AppScript:
231
249
 
232
250
  solara.lab.toestand.ConnectionStore._type_counter.clear()
233
251
 
252
+ # we need to remove callbacks that are added in the app code
253
+ # which will be re-executed after the reload and we do not
254
+ # want to keep executing the old ones.
255
+ for kc in kernel_context._on_kernel_start_callbacks.copy():
256
+ callback, path, module, cleanup = kc
257
+ will_reload = False
258
+ if module is not None:
259
+ module_name = module.__name__
260
+ if module_name in reload.reloader.get_reload_module_names():
261
+ will_reload = True
262
+ elif path is not None:
263
+ if str(path.resolve()).startswith(str(self.directory)):
264
+ will_reload = True
265
+ else:
266
+ logger.warning(
267
+ "script %s is not in the same directory as the app %s but is using on_kernel_start, "
268
+ "this might lead to multiple entries, and might indicate a bug.",
269
+ path,
270
+ self.directory,
271
+ )
272
+
273
+ if will_reload:
274
+ logger.info("reload: Removing on_kernel_start callback: %s (since it will be added when reloaded)", callback)
275
+ cleanup()
276
+
234
277
  context_values = list(kernel_context.contexts.values())
235
278
  # save states into the context so the hot reload will
236
279
  # keep the same state
@@ -23,6 +23,12 @@ code::before {
23
23
  box-shadow: unset !important;
24
24
  }
25
25
 
26
+ .v-application--wrap .v-application--wrap {
27
+ /* disable min-height: 100vh set by vuetify for nested apps */
28
+ min-height: unset;
29
+ }
30
+
31
+
26
32
  div.highlight pre code {
27
33
  /* box-shadow: 0 2px 1px -1px rgb(0 0 0 / 20%), 0 1px 1px 0 rgb(0 0 0 / 14%), 0 1px 3px 0 rgb(0 0 0 / 12%); */
28
34
  /* border: 1px #333 solid; */
solara/server/esm.py CHANGED
@@ -2,15 +2,22 @@
2
2
  # in the future, we may want to move the esm features of ipyreact
3
3
  # into a separate package, and then we can import it unconditionally
4
4
  import logging
5
+ import threading
6
+ from collections import defaultdict
5
7
  from pathlib import Path
6
8
  from typing import Dict, List, Tuple, Union
7
9
 
8
10
  import ipyreact.importmap
9
11
  import ipyreact.module
10
12
 
13
+ from solara.server import kernel_context
14
+
11
15
  logger = logging.getLogger("solara.server.esm")
16
+ lock = threading.Lock()
12
17
 
13
18
  _modules: Dict[str, Tuple[Union[str, Path], List[str]]] = {}
19
+ _modules_added_per_kernel: Dict[str, Dict[str, ipyreact.module.Module]] = defaultdict(dict)
20
+ _import_map_per_kernel: Dict[str, ipyreact.importmap.ImportMap] = {}
14
21
 
15
22
 
16
23
  # in solara server, we'll monkey patch ipyreact.module with this
@@ -29,10 +36,20 @@ def get_module_names():
29
36
 
30
37
 
31
38
  def create_modules():
39
+ kernel_id = kernel_context.get_current_context().id
40
+ _modules_added = _modules_added_per_kernel[kernel_id]
32
41
  logger.info("define modules %s", _modules)
33
42
  widgets = {}
34
- for name, (module, dependencies) in _modules.items():
35
- widgets[name] = create_module(name, module, dependencies=dependencies)
43
+ with lock:
44
+ for name, (module, dependencies) in _modules.items():
45
+ if name not in _modules_added:
46
+ _modules_added[name] = create_module(name, module, dependencies=dependencies)
47
+ logger.info("create module %s %s %s", name, module, dependencies)
48
+ else:
49
+ _modules_added[name].code = module if not isinstance(module, Path) else module.read_text(encoding="utf8")
50
+ _modules_added[name].dependencies = dependencies
51
+ logger.info("update module %s %s %s", name, module, dependencies)
52
+ widgets[name] = _modules_added[name]
36
53
  return widgets
37
54
 
38
55
 
@@ -41,5 +58,12 @@ def create_module(name, module: Union[str, Path], dependencies: List[str]):
41
58
 
42
59
 
43
60
  def create_import_map():
44
- logger.info("create import map %s", ipyreact.importmap._effective_import_map)
45
- return ipyreact.importmap.ImportMap(import_map=ipyreact.importmap._effective_import_map)
61
+ kernel_id = kernel_context.get_current_context().id
62
+ with lock:
63
+ if kernel_id not in _import_map_per_kernel:
64
+ _import_map_per_kernel[kernel_id] = ipyreact.importmap.ImportMap(import_map=ipyreact.importmap._effective_import_map)
65
+ logger.info("create import map %s", ipyreact.importmap._effective_import_map)
66
+ else:
67
+ _import_map_per_kernel[kernel_id].import_map = ipyreact.importmap._effective_import_map
68
+ logger.info("update import map %s", ipyreact.importmap._effective_import_map)
69
+ return
@@ -1,13 +1,22 @@
1
1
  import asyncio
2
+
3
+ try:
4
+ import contextvars
5
+ except ModuleNotFoundError:
6
+ contextvars = None # type: ignore
7
+
2
8
  import dataclasses
3
9
  import enum
10
+ import inspect
4
11
  import logging
5
12
  import os
6
13
  import pickle
7
14
  import threading
8
15
  import time
16
+ import typing
9
17
  from pathlib import Path
10
- from typing import Any, Callable, Dict, List, Optional, cast
18
+ from types import FrameType, ModuleType
19
+ from typing import Any, Callable, Dict, List, NamedTuple, Optional, cast
11
20
 
12
21
  import ipywidgets as widgets
13
22
  import reacton
@@ -36,11 +45,46 @@ class PageStatus(enum.Enum):
36
45
  CLOSED = "closed"
37
46
 
38
47
 
39
- _on_kernel_start_callbacks: List[Callable[[], Optional[Callable[[], None]]]] = []
48
+ class _on_kernel_callback_entry(NamedTuple):
49
+ callback: Callable[[], Optional[Callable[[], None]]]
50
+ callpoint: Optional[Path]
51
+ module: Optional[ModuleType]
52
+ cleanup: Callable[[], None]
53
+
54
+
55
+ _on_kernel_start_callbacks: List[_on_kernel_callback_entry] = []
56
+
57
+
58
+ def _find_root_module_frame() -> Optional[FrameType]:
59
+ # basically the module where the call stack origined from
60
+ current_frame = inspect.currentframe()
61
+ root_module_frame = None
62
+
63
+ while current_frame is not None:
64
+ if current_frame.f_code.co_name == "<module>":
65
+ root_module_frame = current_frame
66
+ break
67
+ current_frame = current_frame.f_back
68
+
69
+ return root_module_frame
40
70
 
41
71
 
42
- def on_kernel_start(f: Callable[[], Optional[Callable[[], None]]]):
43
- _on_kernel_start_callbacks.append(f)
72
+ def on_kernel_start(f: Callable[[], Optional[Callable[[], None]]]) -> Callable[[], None]:
73
+ root = _find_root_module_frame()
74
+ path: Optional[Path] = None
75
+ module: Optional[ModuleType] = None
76
+ if root is not None:
77
+ path_str = inspect.getsourcefile(root)
78
+ module = inspect.getmodule(root)
79
+ if path_str is not None:
80
+ path = Path(path_str)
81
+
82
+ def cleanup():
83
+ return _on_kernel_start_callbacks.remove(kce)
84
+
85
+ kce = _on_kernel_callback_entry(f, path, module, cleanup)
86
+ _on_kernel_start_callbacks.append(kce)
87
+ return cleanup
44
88
 
45
89
 
46
90
  @dataclasses.dataclass
@@ -74,7 +118,7 @@ class VirtualKernelContext:
74
118
 
75
119
  def __post_init__(self):
76
120
  with self:
77
- for f in _on_kernel_start_callbacks:
121
+ for (f, *_) in _on_kernel_start_callbacks:
78
122
  cleanup = f()
79
123
  if cleanup:
80
124
  self.on_close(cleanup)
@@ -255,12 +299,35 @@ def create_dummy_context():
255
299
  return kernel_context
256
300
 
257
301
 
302
+ if contextvars is not None:
303
+ if typing.TYPE_CHECKING:
304
+ async_context_id = contextvars.ContextVar[str]("async_context_id")
305
+ else:
306
+ async_context_id = contextvars.ContextVar("async_context_id")
307
+ async_context_id.set("default")
308
+ else:
309
+ async_context_id = None
310
+
311
+
258
312
  def get_current_thread_key() -> str:
259
- thread = threading.current_thread()
260
- return get_thread_key(thread)
313
+ if not solara.server.settings.kernel.threaded:
314
+ if async_context_id is not None:
315
+ try:
316
+ key = async_context_id.get()
317
+ except LookupError:
318
+ raise RuntimeError("no kernel context set")
319
+ else:
320
+ raise RuntimeError("No threading support, and no contextvars support (Python 3.6 is not supported for this)")
321
+ else:
322
+ thread = threading.current_thread()
323
+ key = get_thread_key(thread)
324
+ return key
261
325
 
262
326
 
263
327
  def get_thread_key(thread: threading.Thread) -> str:
328
+ if not solara.server.settings.kernel.threaded:
329
+ if async_context_id is not None:
330
+ return async_context_id.get()
264
331
  thread_key = thread._name + str(thread._ident) # type: ignore
265
332
  return thread_key
266
333
 
@@ -318,6 +385,7 @@ def initialize_virtual_kernel(session_id: str, kernel_id: str, websocket: websoc
318
385
  widgets.register_comm_target(kernel)
319
386
  appmodule.register_solara_comm_target(kernel)
320
387
  with context:
388
+ assert has_current_context()
321
389
  assert kernel is Kernel.instance()
322
390
  kernel.shell_stream = WebsocketStreamWrapper(websocket, "shell")
323
391
  kernel.control_stream = WebsocketStreamWrapper(websocket, "control")
solara/server/patch.py CHANGED
@@ -295,7 +295,10 @@ def _WidgetContextAwareThread__bootstrap(self):
295
295
  # we need to call this manually, because set_context_for_thread
296
296
  # uses this, and the original _bootstrap calls it too late for us
297
297
  self._set_ident()
298
+ if kernel_context.async_context_id is not None:
299
+ kernel_context.async_context_id.set(self.current_context.id)
298
300
  kernel_context.set_context_for_thread(self.current_context, self)
301
+
299
302
  shell = self.current_context.kernel.shell
300
303
  shell.display_pub.register_hook(shell.display_in_reacton_hook)
301
304
  try:
solara/server/reload.py CHANGED
@@ -152,13 +152,13 @@ class Reloader:
152
152
  self._first = False
153
153
 
154
154
  def _on_change(self, name):
155
- # used for testing
156
- self.reload_event_next.set()
157
155
  # flag that we need to reload all modules next time
158
156
  self.requires_reload = True
159
157
  # and forward callback
160
158
  if self.on_change:
161
159
  self.on_change(name)
160
+ # used for testing
161
+ self.reload_event_next.set()
162
162
 
163
163
  def close(self):
164
164
  self.watcher.close()
solara/server/server.py CHANGED
@@ -13,7 +13,6 @@ import ipyvue
13
13
  import ipywidgets
14
14
  import jinja2
15
15
  import requests
16
-
17
16
  import solara
18
17
  import solara.routing
19
18
  import solara.settings
@@ -35,6 +34,7 @@ ipykernel_major = int(ipykernel.__version__.split(".")[0])
35
34
  ipywidgets_major = int(ipywidgets.__version__.split(".")[0])
36
35
  cache_memory = solara.cache.Memory(max_items=128)
37
36
  vue3 = ipyvue.__version__.startswith("3")
37
+ _redirects: Dict[str, str] = {}
38
38
 
39
39
  # first look at the project directory, then the builtin solara directory
40
40
 
@@ -302,9 +302,9 @@ def read_root(path: str, root_path: str = "", render_kwargs={}, use_nbextensions
302
302
  code = content_utf8
303
303
  elif embed:
304
304
  content_utf8 = content.decode("utf-8")
305
- code = f"<style>/*\npath={path}\n*/\n{content_utf8}</style>"
305
+ code = f'<style class="solara-template-css">/*\npath={path}\n*/\n{content_utf8}</style>'
306
306
  else:
307
- code = f'<link rel="stylesheet" type="text/css" href="{url}">'
307
+ code = f'<link rel="stylesheet" type="text/css" href="{url}" class="solara-template-css">'
308
308
  return Markup(code)
309
309
 
310
310
  def include_js(path: str, module=False) -> Markup: