solara-ui 1.31.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. 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 +734 -0
  5. solara/alias.py +6 -0
  6. solara/autorouting.py +546 -0
  7. solara/cache.py +303 -0
  8. solara/checks.html +71 -0
  9. solara/checks.py +224 -0
  10. solara/comm.py +28 -0
  11. solara/components/__init__.py +59 -0
  12. solara/components/alert.py +155 -0
  13. solara/components/applayout.py +393 -0
  14. solara/components/button.py +85 -0
  15. solara/components/card.py +87 -0
  16. solara/components/checkbox.py +50 -0
  17. solara/components/code_highlight_css.py +11 -0
  18. solara/components/code_highlight_css.vue +63 -0
  19. solara/components/columns.py +159 -0
  20. solara/components/component_vue.py +110 -0
  21. solara/components/cross_filter.py +335 -0
  22. solara/components/dataframe.py +546 -0
  23. solara/components/datatable.py +221 -0
  24. solara/components/datatable.vue +175 -0
  25. solara/components/details.py +21 -0
  26. solara/components/download.vue +35 -0
  27. solara/components/echarts.py +75 -0
  28. solara/components/echarts.vue +128 -0
  29. solara/components/figure_altair.py +39 -0
  30. solara/components/file_browser.py +182 -0
  31. solara/components/file_download.py +199 -0
  32. solara/components/file_drop.py +139 -0
  33. solara/components/file_drop.vue +83 -0
  34. solara/components/file_list_widget.vue +78 -0
  35. solara/components/head.py +27 -0
  36. solara/components/head_tag.py +49 -0
  37. solara/components/head_tag.vue +60 -0
  38. solara/components/image.py +173 -0
  39. solara/components/input.py +436 -0
  40. solara/components/link.py +55 -0
  41. solara/components/markdown.py +378 -0
  42. solara/components/markdown_editor.py +25 -0
  43. solara/components/markdown_editor.vue +362 -0
  44. solara/components/matplotlib.py +74 -0
  45. solara/components/meta.py +47 -0
  46. solara/components/misc.py +333 -0
  47. solara/components/pivot_table.py +258 -0
  48. solara/components/pivot_table.vue +158 -0
  49. solara/components/progress.py +47 -0
  50. solara/components/select.py +182 -0
  51. solara/components/select.vue +27 -0
  52. solara/components/slider.py +442 -0
  53. solara/components/slider_date.vue +56 -0
  54. solara/components/spinner-solara.vue +105 -0
  55. solara/components/spinner.py +30 -0
  56. solara/components/sql_code.py +33 -0
  57. solara/components/sql_code.vue +128 -0
  58. solara/components/style.py +105 -0
  59. solara/components/switch.py +68 -0
  60. solara/components/tab_navigation.py +37 -0
  61. solara/components/title.py +90 -0
  62. solara/components/title.vue +38 -0
  63. solara/components/togglebuttons.py +200 -0
  64. solara/components/tooltip.py +61 -0
  65. solara/datatypes.py +143 -0
  66. solara/express.py +241 -0
  67. solara/hooks/__init__.py +4 -0
  68. solara/hooks/dataframe.py +99 -0
  69. solara/hooks/misc.py +263 -0
  70. solara/hooks/use_reactive.py +129 -0
  71. solara/hooks/use_thread.py +129 -0
  72. solara/kitchensink.py +8 -0
  73. solara/lab/__init__.py +34 -0
  74. solara/lab/components/__init__.py +6 -0
  75. solara/lab/components/chat.py +203 -0
  76. solara/lab/components/confirmation_dialog.py +163 -0
  77. solara/lab/components/cross_filter.py +7 -0
  78. solara/lab/components/input_date.py +298 -0
  79. solara/lab/components/menu.py +181 -0
  80. solara/lab/components/menu.vue +38 -0
  81. solara/lab/components/tabs.py +274 -0
  82. solara/lab/components/theming.py +98 -0
  83. solara/lab/components/theming.vue +72 -0
  84. solara/lab/hooks/__init__.py +0 -0
  85. solara/lab/hooks/dataframe.py +12 -0
  86. solara/lab/toestand.py +3 -0
  87. solara/lab/utils/__init__.py +2 -0
  88. solara/lab/utils/cookies.py +5 -0
  89. solara/lab/utils/dataframe.py +115 -0
  90. solara/lab/utils/headers.py +5 -0
  91. solara/layout.py +44 -0
  92. solara/lifecycle.py +46 -0
  93. solara/minisettings.py +133 -0
  94. solara/py.typed +0 -0
  95. solara/reactive.py +93 -0
  96. solara/routing.py +268 -0
  97. solara/scope/__init__.py +88 -0
  98. solara/scope/types.py +55 -0
  99. solara/server/__init__.py +0 -0
  100. solara/server/app.py +491 -0
  101. solara/server/assets/custom.css +1 -0
  102. solara/server/assets/custom.js +1 -0
  103. solara/server/assets/favicon.png +0 -0
  104. solara/server/assets/favicon.svg +5 -0
  105. solara/server/assets/style.css +1665 -0
  106. solara/server/assets/theme-dark.css +437 -0
  107. solara/server/assets/theme-light.css +420 -0
  108. solara/server/assets/theme.js +3 -0
  109. solara/server/cdn_helper.py +77 -0
  110. solara/server/esm.py +69 -0
  111. solara/server/fastapi.py +5 -0
  112. solara/server/flask.py +286 -0
  113. solara/server/jupyter/__init__.py +2 -0
  114. solara/server/jupyter/cdn_handler.py +28 -0
  115. solara/server/jupyter/server_extension.py +29 -0
  116. solara/server/jupytertools.py +46 -0
  117. solara/server/kernel.py +338 -0
  118. solara/server/kernel_context.py +357 -0
  119. solara/server/patch.py +552 -0
  120. solara/server/reload.py +242 -0
  121. solara/server/server.py +456 -0
  122. solara/server/settings.py +215 -0
  123. solara/server/shell.py +251 -0
  124. solara/server/starlette.py +601 -0
  125. solara/server/static/ansi.js +270 -0
  126. solara/server/static/highlight-dark.css +82 -0
  127. solara/server/static/highlight.css +43 -0
  128. solara/server/static/main-vuetify.js +260 -0
  129. solara/server/static/main.js +163 -0
  130. solara/server/static/solara_bootstrap.py +129 -0
  131. solara/server/static/sun.svg +23 -0
  132. solara/server/static/webworker.js +42 -0
  133. solara/server/telemetry.py +212 -0
  134. solara/server/templates/index.html.j2 +1 -0
  135. solara/server/templates/loader-plain.css +11 -0
  136. solara/server/templates/loader-plain.html +20 -0
  137. solara/server/templates/loader-solara.css +111 -0
  138. solara/server/templates/loader-solara.html +40 -0
  139. solara/server/templates/plain.html +82 -0
  140. solara/server/templates/solara.html.j2 +446 -0
  141. solara/server/threaded.py +75 -0
  142. solara/server/utils.py +30 -0
  143. solara/server/websocket.py +45 -0
  144. solara/settings.py +56 -0
  145. solara/tasks.py +837 -0
  146. solara/template/button.py +16 -0
  147. solara/template/markdown.py +42 -0
  148. solara/template/portal/.flake8 +6 -0
  149. solara/template/portal/.pre-commit-config.yaml +28 -0
  150. solara/template/portal/LICENSE +21 -0
  151. solara/template/portal/Procfile +7 -0
  152. solara/template/portal/mypy.ini +3 -0
  153. solara/template/portal/pyproject.toml +26 -0
  154. solara/template/portal/solara_portal/__init__.py +4 -0
  155. solara/template/portal/solara_portal/components/__init__.py +2 -0
  156. solara/template/portal/solara_portal/components/article.py +28 -0
  157. solara/template/portal/solara_portal/components/data.py +28 -0
  158. solara/template/portal/solara_portal/components/header.py +6 -0
  159. solara/template/portal/solara_portal/components/layout.py +6 -0
  160. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
  161. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
  162. solara/template/portal/solara_portal/data.py +60 -0
  163. solara/template/portal/solara_portal/pages/__init__.py +67 -0
  164. solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
  165. solara/template/portal/solara_portal/pages/tabular.py +29 -0
  166. solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
  167. solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
  168. solara/test/__init__.py +0 -0
  169. solara/test/pytest_plugin.py +697 -0
  170. solara/toestand.py +772 -0
  171. solara/util.py +308 -0
  172. solara/website/__init__.py +0 -0
  173. solara/website/assets/custom.css +468 -0
  174. solara/website/assets/images/logo-small.png +0 -0
  175. solara/website/assets/images/logo.svg +17 -0
  176. solara/website/assets/images/logo_white.svg +50 -0
  177. solara/website/assets/theme.js +8 -0
  178. solara/website/components/__init__.py +5 -0
  179. solara/website/components/algolia.vue +24 -0
  180. solara/website/components/algolia_api.vue +187 -0
  181. solara/website/components/docs.py +118 -0
  182. solara/website/components/header.py +72 -0
  183. solara/website/components/hero.py +15 -0
  184. solara/website/components/mailchimp.py +12 -0
  185. solara/website/components/mailchimp.vue +47 -0
  186. solara/website/components/markdown.py +30 -0
  187. solara/website/components/notebook.py +171 -0
  188. solara/website/pages/__init__.py +575 -0
  189. solara/website/pages/apps/__init__.py +16 -0
  190. solara/website/pages/apps/authorization/__init__.py +119 -0
  191. solara/website/pages/apps/authorization/admin.py +12 -0
  192. solara/website/pages/apps/authorization/users.py +12 -0
  193. solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
  194. solara/website/pages/apps/layout-demo.py +40 -0
  195. solara/website/pages/apps/multipage/__init__.py +38 -0
  196. solara/website/pages/apps/multipage/page1.py +26 -0
  197. solara/website/pages/apps/multipage/page2.py +34 -0
  198. solara/website/pages/apps/scatter.py +136 -0
  199. solara/website/pages/apps/scrolling.py +63 -0
  200. solara/website/pages/apps/tutorial-streamlit.py +18 -0
  201. solara/website/pages/changelog/__init__.py +8 -0
  202. solara/website/pages/changelog/changelog.md +204 -0
  203. solara/website/pages/contact/__init__.py +8 -0
  204. solara/website/pages/contact/contact.md +17 -0
  205. solara/website/pages/doc_use_download.py +85 -0
  206. solara/website/pages/documentation/__init__.py +184 -0
  207. solara/website/pages/documentation/advanced/__init__.py +9 -0
  208. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  209. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
  210. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
  211. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
  212. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +162 -0
  213. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
  214. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +49 -0
  215. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
  216. solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
  217. solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
  218. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +36 -0
  219. solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
  220. solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
  221. solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
  222. solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
  223. solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
  224. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
  225. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
  226. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
  227. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
  228. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
  229. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
  230. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +7 -0
  231. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
  232. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
  233. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +240 -0
  234. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +97 -0
  235. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
  236. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -0
  237. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +171 -0
  238. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  239. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
  240. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
  241. solara/website/pages/documentation/api/__init__.py +19 -0
  242. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  243. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +23 -0
  244. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +22 -0
  245. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +22 -0
  246. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +22 -0
  247. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  248. solara/website/pages/documentation/api/hooks/use_cross_filter.py +25 -0
  249. solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
  250. solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
  251. solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
  252. solara/website/pages/documentation/api/hooks/use_exception.py +33 -0
  253. solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
  254. solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
  255. solara/website/pages/documentation/api/hooks/use_previous.py +33 -0
  256. solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
  257. solara/website/pages/documentation/api/hooks/use_state.py +10 -0
  258. solara/website/pages/documentation/api/hooks/use_state_or_update.py +69 -0
  259. solara/website/pages/documentation/api/hooks/use_thread.md +58 -0
  260. solara/website/pages/documentation/api/hooks/use_thread.py +44 -0
  261. solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
  262. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  263. solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
  264. solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
  265. solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
  266. solara/website/pages/documentation/api/routing/route.py +31 -0
  267. solara/website/pages/documentation/api/routing/use_route.py +80 -0
  268. solara/website/pages/documentation/api/routing/use_router.py +16 -0
  269. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  270. solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
  271. solara/website/pages/documentation/api/utilities/computed.py +16 -0
  272. solara/website/pages/documentation/api/utilities/display.py +16 -0
  273. solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
  274. solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
  275. solara/website/pages/documentation/api/utilities/memoize.py +35 -0
  276. solara/website/pages/documentation/api/utilities/on_kernel_start.py +27 -0
  277. solara/website/pages/documentation/api/utilities/reactive.py +16 -0
  278. solara/website/pages/documentation/api/utilities/widget.py +104 -0
  279. solara/website/pages/documentation/components/__init__.py +12 -0
  280. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  281. solara/website/pages/documentation/components/advanced/link.py +27 -0
  282. solara/website/pages/documentation/components/advanced/meta.py +20 -0
  283. solara/website/pages/documentation/components/advanced/style.py +45 -0
  284. solara/website/pages/documentation/components/common.py +9 -0
  285. solara/website/pages/documentation/components/data/__init__.py +9 -0
  286. solara/website/pages/documentation/components/data/dataframe.py +44 -0
  287. solara/website/pages/documentation/components/data/pivot_table.py +81 -0
  288. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  289. solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
  290. solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
  291. solara/website/pages/documentation/components/input/__init__.py +9 -0
  292. solara/website/pages/documentation/components/input/button.py +23 -0
  293. solara/website/pages/documentation/components/input/checkbox.py +10 -0
  294. solara/website/pages/documentation/components/input/file_browser.py +32 -0
  295. solara/website/pages/documentation/components/input/file_drop.py +76 -0
  296. solara/website/pages/documentation/components/input/input.py +19 -0
  297. solara/website/pages/documentation/components/input/select.py +22 -0
  298. solara/website/pages/documentation/components/input/slider.py +29 -0
  299. solara/website/pages/documentation/components/input/switch.py +10 -0
  300. solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
  301. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  302. solara/website/pages/documentation/components/lab/chat.py +109 -0
  303. solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
  304. solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
  305. solara/website/pages/documentation/components/lab/input_date.py +20 -0
  306. solara/website/pages/documentation/components/lab/menu.py +22 -0
  307. solara/website/pages/documentation/components/lab/tab.py +25 -0
  308. solara/website/pages/documentation/components/lab/tabs.py +45 -0
  309. solara/website/pages/documentation/components/lab/task.py +11 -0
  310. solara/website/pages/documentation/components/lab/theming.py +72 -0
  311. solara/website/pages/documentation/components/lab/use_task.py +11 -0
  312. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  313. solara/website/pages/documentation/components/layout/app_bar.py +16 -0
  314. solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
  315. solara/website/pages/documentation/components/layout/app_layout.py +24 -0
  316. solara/website/pages/documentation/components/layout/card.py +15 -0
  317. solara/website/pages/documentation/components/layout/card_actions.py +16 -0
  318. solara/website/pages/documentation/components/layout/column.py +30 -0
  319. solara/website/pages/documentation/components/layout/columns.py +27 -0
  320. solara/website/pages/documentation/components/layout/columns_responsive.py +68 -0
  321. solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
  322. solara/website/pages/documentation/components/layout/gridfixed.py +21 -0
  323. solara/website/pages/documentation/components/layout/hbox.py +18 -0
  324. solara/website/pages/documentation/components/layout/row.py +30 -0
  325. solara/website/pages/documentation/components/layout/sidebar.py +24 -0
  326. solara/website/pages/documentation/components/layout/vbox.py +19 -0
  327. solara/website/pages/documentation/components/output/__init__.py +9 -0
  328. solara/website/pages/documentation/components/output/file_download.py +11 -0
  329. solara/website/pages/documentation/components/output/html.py +21 -0
  330. solara/website/pages/documentation/components/output/image.py +11 -0
  331. solara/website/pages/documentation/components/output/markdown.py +57 -0
  332. solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
  333. solara/website/pages/documentation/components/output/sql_code.py +85 -0
  334. solara/website/pages/documentation/components/output/tooltip.py +11 -0
  335. solara/website/pages/documentation/components/page/__init__.py +9 -0
  336. solara/website/pages/documentation/components/page/head.py +18 -0
  337. solara/website/pages/documentation/components/page/title.py +27 -0
  338. solara/website/pages/documentation/components/status/__init__.py +9 -0
  339. solara/website/pages/documentation/components/status/error.py +40 -0
  340. solara/website/pages/documentation/components/status/info.py +40 -0
  341. solara/website/pages/documentation/components/status/progress.py +10 -0
  342. solara/website/pages/documentation/components/status/spinner.py +11 -0
  343. solara/website/pages/documentation/components/status/success.py +40 -0
  344. solara/website/pages/documentation/components/status/warning.py +47 -0
  345. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  346. solara/website/pages/documentation/components/viz/altair.py +42 -0
  347. solara/website/pages/documentation/components/viz/echarts.py +75 -0
  348. solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
  349. solara/website/pages/documentation/components/viz/plotly.py +63 -0
  350. solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
  351. solara/website/pages/documentation/examples/__init__.py +52 -0
  352. solara/website/pages/documentation/examples/ai/__init__.py +11 -0
  353. solara/website/pages/documentation/examples/ai/chatbot.py +95 -0
  354. solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
  355. solara/website/pages/documentation/examples/basics/__init__.py +10 -0
  356. solara/website/pages/documentation/examples/basics/sine.py +28 -0
  357. solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
  358. solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
  359. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
  360. solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
  361. solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
  362. solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
  363. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
  364. solara/website/pages/documentation/examples/general/__init__.py +10 -0
  365. solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
  366. solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
  367. solara/website/pages/documentation/examples/general/live_update.py +38 -0
  368. solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
  369. solara/website/pages/documentation/examples/general/mycard.vue +58 -0
  370. solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
  371. solara/website/pages/documentation/examples/general/vue_component.py +50 -0
  372. solara/website/pages/documentation/examples/ipycanvas.py +49 -0
  373. solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
  374. solara/website/pages/documentation/examples/libraries/altair.py +64 -0
  375. solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
  376. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
  377. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
  378. solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
  379. solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
  380. solara/website/pages/documentation/examples/utilities/countdown_timer.py +64 -0
  381. solara/website/pages/documentation/examples/utilities/todo.py +196 -0
  382. solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
  383. solara/website/pages/documentation/examples/visualization/annotator.py +69 -0
  384. solara/website/pages/documentation/examples/visualization/linked_views.py +84 -0
  385. solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
  386. solara/website/pages/documentation/faq/__init__.py +12 -0
  387. solara/website/pages/documentation/faq/content/99-faq.md +76 -0
  388. solara/website/pages/documentation/getting_started/__init__.py +9 -0
  389. solara/website/pages/documentation/getting_started/content/00-quickstart.md +89 -0
  390. solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
  391. solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
  392. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
  393. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
  394. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
  395. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
  396. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
  397. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
  398. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +64 -0
  399. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  400. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
  401. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1000 -0
  402. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
  403. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +223 -0
  404. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +88 -0
  405. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
  406. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +273 -0
  407. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
  408. solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
  409. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
  410. solara/website/pages/docutils.py +38 -0
  411. solara/website/pages/showcase/__init__.py +105 -0
  412. solara/website/pages/showcase/domino_code_assist.py +60 -0
  413. solara/website/pages/showcase/planeto_tessa.py +19 -0
  414. solara/website/pages/showcase/solara_dev.py +54 -0
  415. solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
  416. solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
  417. solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
  418. solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
  419. solara/website/pages/showcase/wanderlust.py +27 -0
  420. solara/website/public/beach.jpeg +0 -0
  421. solara/website/public/logo.svg +6 -0
  422. solara/website/public/social/discord.svg +1 -0
  423. solara/website/public/social/github.svg +1 -0
  424. solara/website/public/social/twitter.svg +3 -0
  425. solara/website/public/success.html +25 -0
  426. solara/website/templates/index.html.j2 +117 -0
  427. solara/website/utils.py +51 -0
  428. solara/widgets/__init__.py +1 -0
  429. solara/widgets/vue/gridlayout.vue +110 -0
  430. solara/widgets/vue/html.vue +4 -0
  431. solara/widgets/vue/navigator.vue +104 -0
  432. solara/widgets/vue/vegalite.vue +115 -0
  433. solara/widgets/widgets.py +66 -0
  434. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  435. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  436. solara_ui-1.31.0.dist-info/METADATA +158 -0
  437. solara_ui-1.31.0.dist-info/RECORD +439 -0
  438. solara_ui-1.31.0.dist-info/WHEEL +5 -0
  439. solara_ui-1.31.0.dist-info/licenses/LICENSE +21 -0
solara/server/patch.py ADDED
@@ -0,0 +1,552 @@
1
+ import functools
2
+ import logging
3
+ import os
4
+ import pdb
5
+ import sys
6
+ import threading
7
+ import traceback
8
+ import warnings
9
+ from typing import Any, Dict, MutableMapping
10
+ from unittest import mock
11
+
12
+ import ipykernel.kernelbase
13
+ import IPython.display
14
+ import ipywidgets
15
+ import ipywidgets.widgets.widget_output
16
+ from IPython.core.interactiveshell import InteractiveShell
17
+
18
+ from . import app, kernel_context, reload, settings
19
+ from .utils import pdb_guard
20
+
21
+ logger = logging.getLogger("solara.server.patch")
22
+ try:
23
+ from reacton.patch_display import patch as patch_display
24
+ except: # noqa
25
+ patch_display = None # type: ignore
26
+
27
+ if patch_display is not None and sys.platform != "emscripten":
28
+ patch_display()
29
+ ipywidget_version_major = int(ipywidgets.__version__.split(".")[0])
30
+ ipykernel_version_major = int(ipykernel.__version__.split(".")[0])
31
+
32
+
33
+ class FakeIPython:
34
+ def __init__(self, context: kernel_context.VirtualKernelContext):
35
+ self.context = context
36
+ self.kernel = context.kernel
37
+ self.display_pub = self.kernel.shell.display_pub
38
+ # needed for the pyplot interface of matplotlib
39
+ # (although we don't really support it)
40
+ self.events = mock.MagicMock()
41
+
42
+ def enable_gui(self, gui):
43
+ logger.error("ignoring call to enable_gui(%s)", gui)
44
+
45
+ def register_post_execute(self, callback):
46
+ # mpl requires this
47
+ pass
48
+
49
+ def set_parent(self, *args):
50
+ pass
51
+
52
+ def showtraceback(self):
53
+ if settings.main.use_pdb:
54
+ logger.exception("Exception, will be handled by debugger")
55
+ pdb.post_mortem()
56
+ etype, value, tb = sys.exc_info()
57
+ traceback_string = "".join(traceback.format_exception(etype, value, tb))
58
+ logger.error("Uncaught exception: %s", traceback_string)
59
+ msg = {
60
+ "type": "exception",
61
+ "traceback": traceback_string,
62
+ }
63
+
64
+ for socket in self.context.control_sockets:
65
+ try:
66
+ socket.send_json(msg)
67
+ except: # noqa
68
+ # TODO: should we remove it from the list?
69
+ pass
70
+
71
+ def magic(self, *args):
72
+ # proplot requires this
73
+ pass
74
+
75
+ def set_custom_exc(self, exc_tuple, handler):
76
+ # make dask work
77
+ pass
78
+
79
+
80
+ Kernel_instance_original = ipykernel.kernelbase.Kernel.instance.__func__ # type: ignore
81
+
82
+
83
+ def kernel_instance_dispatch(cls, *args, **kwargs):
84
+ if kernel_context.has_current_context():
85
+ context = kernel_context.get_current_context()
86
+ return context.kernel
87
+ else:
88
+ return Kernel_instance_original(cls, *args, **kwargs)
89
+
90
+
91
+ Kernel_initialized_initial = ipykernel.kernelbase.Kernel.initialized.__func__ # type: ignore
92
+
93
+
94
+ def kernel_initialized_dispatch(cls):
95
+ if app is None: # python is shutting down, and the comm dtor wants to send a close message
96
+ return False
97
+ if kernel_context.has_current_context():
98
+ return True
99
+ else:
100
+ return Kernel_initialized_initial(cls)
101
+
102
+
103
+ InteractiveShell_instance_initial = InteractiveShell.instance.__func__ # type: ignore
104
+
105
+
106
+ def interactive_shell_instance_dispatch(cls, *args, **kwargs):
107
+ if kernel_context.has_current_context():
108
+ context = kernel_context.get_current_context()
109
+ return context.kernel.shell
110
+ else:
111
+ return InteractiveShell_instance_initial(cls, *args, **kwargs)
112
+
113
+
114
+ def display_solara(
115
+ *objs,
116
+ include=None,
117
+ exclude=None,
118
+ metadata=None,
119
+ transient=None,
120
+ display_id=None,
121
+ raw=False,
122
+ clear=False,
123
+ **kwargs,
124
+ ):
125
+ print(*objs) # noqa
126
+
127
+
128
+ # from IPython.core.interactiveshell import InteractiveShell
129
+
130
+ # if transient is None:
131
+ # transient = {}
132
+ # if metadata is None:
133
+ # metadata = {}
134
+ # from IPython.core.display_functions import _new_id
135
+
136
+ # if display_id:
137
+ # if display_id is True:
138
+ # display_id = _new_id()
139
+ # transient["display_id"] = display_id
140
+ # if kwargs.get("update") and "display_id" not in transient:
141
+ # raise TypeError("display_id required for update_display")
142
+ # if transient:
143
+ # kwargs["transient"] = transient
144
+
145
+ # if not objs and display_id:
146
+ # # if given no objects, but still a request for a display_id,
147
+ # # we assume the user wants to insert an empty output that
148
+ # # can be updated later
149
+ # objs = [{}]
150
+ # raw = True
151
+
152
+ # if not raw:
153
+ # format = InteractiveShell.instance().display_formatter.format
154
+
155
+ # if clear:
156
+ # clear_output(wait=True)
157
+
158
+ # for obj in objs:
159
+ # if raw:
160
+ # publish_display_data(data=obj, metadata=metadata, **kwargs)
161
+ # else:
162
+ # format_dict, md_dict = format(obj, include=include, exclude=exclude)
163
+ # if not format_dict:
164
+ # # nothing to display (e.g. _ipython_display_ took over)
165
+ # continue
166
+ # if metadata:
167
+ # # kwarg-specified metadata gets precedence
168
+ # _merge(md_dict, metadata)
169
+ # publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
170
+ # if display_id:
171
+ # return DisplayHandle(display_id)
172
+
173
+
174
+ def get_ipython():
175
+ if kernel_context.has_current_context():
176
+ context = kernel_context.get_current_context()
177
+ our_fake_ipython = FakeIPython(context)
178
+ return our_fake_ipython
179
+ else:
180
+ return None
181
+
182
+
183
+ class context_dict(MutableMapping):
184
+ def _get_context_dict(self) -> dict:
185
+ raise NotImplementedError
186
+
187
+ def __delitem__(self, key) -> None:
188
+ self._get_context_dict().__delitem__(key)
189
+
190
+ def __getitem__(self, key):
191
+ return self._get_context_dict().__getitem__(key)
192
+
193
+ def __iter__(self):
194
+ return self._get_context_dict().__iter__()
195
+
196
+ def __len__(self):
197
+ return self._get_context_dict().__len__()
198
+
199
+ def __setitem__(self, key, value):
200
+ self._get_context_dict().__setitem__(key, value)
201
+
202
+ # support OrderedDict API for matplotlib
203
+ def move_to_end(self, key, last=True):
204
+ assert last, "only last=True is supported"
205
+ item = self.pop(key)
206
+ self[key] = item
207
+
208
+ # matplotlib assumes .values() returns a list
209
+ def values(self):
210
+ return list(self._get_context_dict().values())
211
+
212
+
213
+ class context_dict_widgets(context_dict):
214
+ def _get_context_dict(self) -> dict:
215
+ if kernel_context.has_current_context():
216
+ context = kernel_context.get_current_context()
217
+ return context.widgets
218
+ else:
219
+ return global_widgets_dict
220
+
221
+
222
+ class context_dict_templates(context_dict):
223
+ def _get_context_dict(self) -> dict:
224
+ if kernel_context.has_current_context():
225
+ context = kernel_context.get_current_context()
226
+ return context.templates
227
+ else:
228
+ return global_templates_dict
229
+
230
+
231
+ class context_dict_user(context_dict):
232
+ def __init__(self, name, default_dict):
233
+ self.name = name
234
+ self.default_dict = default_dict
235
+
236
+ def _get_context_dict(self) -> dict:
237
+ if kernel_context.has_current_context():
238
+ context = kernel_context.get_current_context()
239
+ if self.name not in context.user_dicts:
240
+ context.user_dicts[self.name] = {}
241
+ return context.user_dicts[self.name]
242
+ else:
243
+ return self.default_dict
244
+
245
+
246
+ def auto_watch_get_template(get_template):
247
+ """Wraps get_template and adds a file listener for automatic .vue file reloading"""
248
+
249
+ def wrapper(abs_path):
250
+ template = get_template(abs_path)
251
+ reload.reloader.watcher.add_file(abs_path)
252
+ return template
253
+
254
+ return wrapper
255
+
256
+
257
+ class ThreadDebugInfo:
258
+ lock = threading.Lock()
259
+ created = 0
260
+ running = 0
261
+ stopped = 0
262
+
263
+
264
+ Thread__init__ = threading.Thread.__init__
265
+ Thread__bootstrap = threading.Thread._bootstrap # type: ignore
266
+
267
+
268
+ def WidgetContextAwareThread__init__(self, *args, **kwargs):
269
+ Thread__init__(self, *args, **kwargs)
270
+ with ThreadDebugInfo.lock:
271
+ ThreadDebugInfo.created += 1
272
+
273
+ self.current_context = None
274
+ try:
275
+ self.current_context = kernel_context.get_current_context()
276
+ except RuntimeError:
277
+ logger.debug(f"No context for thread {self}")
278
+
279
+
280
+ def WidgetContextAwareThread__bootstrap(self):
281
+ with ThreadDebugInfo.lock:
282
+ ThreadDebugInfo.running += 1
283
+ try:
284
+ _WidgetContextAwareThread__bootstrap(self)
285
+ finally:
286
+ with ThreadDebugInfo.lock:
287
+ ThreadDebugInfo.running -= 1
288
+ ThreadDebugInfo.stopped += 1
289
+
290
+
291
+ def _WidgetContextAwareThread__bootstrap(self):
292
+ if not hasattr(self, "current_context"):
293
+ return Thread__bootstrap(self)
294
+ if self.current_context:
295
+ # we need to call this manually, because set_context_for_thread
296
+ # uses this, and the original _bootstrap calls it too late for us
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)
300
+ kernel_context.set_context_for_thread(self.current_context, self)
301
+
302
+ shell = self.current_context.kernel.shell
303
+ shell.display_pub.register_hook(shell.display_in_reacton_hook)
304
+ try:
305
+ with pdb_guard():
306
+ Thread__bootstrap(self)
307
+ finally:
308
+ if self.current_context:
309
+ shell.display_pub.unregister_hook(shell.display_in_reacton_hook)
310
+
311
+
312
+ _patched = False
313
+ global_widgets_dict = {}
314
+ global_templates_dict: Dict[Any, Any] = {}
315
+ widgets = context_dict_widgets()
316
+
317
+
318
+ def Output_enter(self):
319
+ self._flush()
320
+
321
+ def hook(msg):
322
+ if msg["msg_type"] == "display_data":
323
+ self.outputs += ({"output_type": "display_data", "data": msg["content"]["data"], "metadata": msg["content"]["metadata"]},)
324
+ return None
325
+ if msg["msg_type"] == "clear_output":
326
+ self.outputs = ()
327
+ return None
328
+ return msg
329
+
330
+ ip = get_ipython()
331
+ if ip:
332
+ ip.display_pub.register_hook(hook)
333
+
334
+
335
+ def Output_exit(self, exc_type, exc_value, traceback):
336
+ ip = get_ipython()
337
+ if ip:
338
+ ip.display_pub._hooks.pop()
339
+
340
+
341
+ def patch_ipyreact():
342
+ import ipyreact
343
+ import ipyreact.module
344
+
345
+ from . import esm
346
+
347
+ ipyreact.module.define_module = esm.define_module
348
+ ipyreact.module.get_module_names = esm.get_module_names
349
+ # define_module is also exported top level
350
+ ipyreact.define_module = esm.define_module
351
+
352
+ # make this a no-op, we'll create the widget when needed
353
+ ipyreact.importmap._update_import_map = lambda: None
354
+
355
+
356
+ def once(f):
357
+ called = False
358
+ return_value = None
359
+
360
+ @functools.wraps(f)
361
+ def wrapper():
362
+ nonlocal called
363
+ nonlocal return_value
364
+ if called:
365
+ return return_value
366
+ called = True
367
+ return_value = f()
368
+ return return_value
369
+
370
+ return wrapper
371
+
372
+
373
+ @once
374
+ def patch_matplotlib():
375
+ import matplotlib
376
+ import matplotlib._pylab_helpers
377
+
378
+ prev = matplotlib._pylab_helpers.Gcf.figs
379
+ matplotlib._pylab_helpers.Gcf.figs = context_dict_user("matplotlib.pylab.figure_managers", prev) # type: ignore
380
+
381
+ RcParamsOriginal = matplotlib.RcParams
382
+ counter = 0
383
+ lock = threading.Lock()
384
+
385
+ class RcParamsScoped(context_dict, matplotlib.RcParams):
386
+ _was_initialized = False
387
+ _without_kernel_dict: Dict[Any, Any]
388
+
389
+ def __init__(self, *args, **kwargs) -> None:
390
+ self._init()
391
+ RcParamsOriginal.__init__(self, *args, **kwargs)
392
+
393
+ def _init(self):
394
+ nonlocal counter
395
+ with lock:
396
+ counter += 1
397
+ self._user_dict_name = f"matplotlib.rcParams:{counter}"
398
+ # this creates a copy of the CPython side of the dict
399
+ self._without_kernel_dict = dict(zip(dict.keys(self), dict.values(self)))
400
+ self._was_initialized = True
401
+
402
+ def _set(self, key, val):
403
+ # in matplotlib this directly calls dict.__setitem__
404
+ # which would not call context_dict.__setitem__
405
+ self[key] = val
406
+
407
+ def _get(self, key):
408
+ # same as _get
409
+ return self[key]
410
+
411
+ def _get_context_dict(self) -> dict:
412
+ if not self._was_initialized:
413
+ # since we monkey patch the class after __init__ was called
414
+ # we may have to do that later on
415
+ self._init()
416
+ if kernel_context.has_current_context():
417
+ context = kernel_context.get_current_context()
418
+ if self._user_dict_name not in context.user_dicts:
419
+ # copy over the global settings when needed
420
+ context.user_dicts[self._user_dict_name] = self._without_kernel_dict.copy()
421
+ return context.user_dicts[self._user_dict_name]
422
+ else:
423
+ return self._without_kernel_dict
424
+
425
+ matplotlib.RcParams = RcParamsScoped
426
+ matplotlib.rcParams.__class__ = RcParamsScoped
427
+ # we chose to monkeypatch the class, instead of re-assiging to reParams for 2 reasons:
428
+ # 1. the RcParams object could be imported in different namespaces
429
+ # 2. the rcParams has extra methods, which means we have to otherwise monkeypatch the context_dict
430
+
431
+ def cleanup():
432
+ matplotlib._pylab_helpers.Gcf.figs = prev
433
+ matplotlib.RcParams = RcParamsOriginal
434
+ matplotlib.rcParams.__class__ = RcParamsOriginal
435
+
436
+ return cleanup
437
+
438
+
439
+ def patch_heavy_imports():
440
+ # patches that we only want to do if a package is imported, because they may slow down startup
441
+ if "matplotlib" in sys.modules:
442
+ patch_matplotlib()
443
+
444
+
445
+ def patch():
446
+ global _patched
447
+ global global_widgets_dict
448
+ if _patched:
449
+ warnings.warn("patch() called twice")
450
+ return
451
+ _patched = True
452
+ __builtins__["display"] = IPython.display.display
453
+
454
+ try:
455
+ import ipyreact
456
+
457
+ del ipyreact
458
+ except ModuleNotFoundError:
459
+ pass
460
+ else:
461
+ patch_ipyreact()
462
+
463
+ if "MPLBACKEND" not in os.environ:
464
+ if ipykernel_version_major < 6:
465
+ # changed in https://github.com/ipython/ipykernel/pull/591
466
+ os.environ["MPLBACKEND"] = "module://ipykernel.pylab.backend_inline"
467
+ else:
468
+ os.environ["MPLBACKEND"] = "module://matplotlib_inline.backend_inline"
469
+
470
+ # the ipyvue.Template module cannot be accessed like ipyvue.Template
471
+ # because the import in ipvue overrides it
472
+ template_mod = sys.modules["ipyvue.Template"]
473
+ template_mod.template_registry = context_dict_templates() # type: ignore
474
+ template_mod.get_template = auto_watch_get_template(template_mod.get_template) # type: ignore
475
+
476
+ # this module also imports get_template
477
+ template_mod_vue = sys.modules["ipyvue.VueTemplateWidget"]
478
+ template_mod_vue.get_template = template_mod.get_template # type: ignore
479
+
480
+ component_mod_vue = sys.modules["ipyvue.VueComponentRegistry"]
481
+ component_mod_vue.vue_component_registry = context_dict_user("vue_component_registry", component_mod_vue.vue_component_registry) # type: ignore
482
+ component_mod_vue.vue_component_files = context_dict_user("vue_component_files", component_mod_vue.vue_component_files) # type: ignore
483
+
484
+ if ipywidget_version_major < 8:
485
+ global_widgets_dict = ipywidgets.widget.Widget.widgets
486
+ ipywidgets.widget.Widget.widgets = widgets # type: ignore
487
+ else:
488
+ if hasattr(ipywidgets.widgets.widget, "_instances"): # since 8.0.3
489
+ global_widgets_dict = ipywidgets.widgets.widget._instances
490
+ ipywidgets.widgets.widget._instances = widgets # type: ignore
491
+ elif hasattr(ipywidgets.widget.Widget, "_instances"):
492
+ global_widgets_dict = ipywidgets.widget.Widget._instances
493
+ ipywidgets.widget.Widget._instances = widgets # type: ignore
494
+ else:
495
+ raise RuntimeError("Could not find _instances on ipywidgets version %r" % ipywidgets.__version__)
496
+ threading.Thread.__init__ = WidgetContextAwareThread__init__ # type: ignore
497
+ threading.Thread._bootstrap = WidgetContextAwareThread__bootstrap # type: ignore
498
+ # on CI we get a mypy error:
499
+ # solara/server/patch.py:210: error: Cannot assign to a method
500
+ # solara/server/patch.py:210: error: Incompatible types in assignment (expression has type "classmethod[Any]",\
501
+ # variable has type "Callable[[VarArg(Any), KwArg(Any)], Any]")
502
+ # not sure why we cannot reproduce that locally
503
+ ipykernel.kernelbase.Kernel.instance = classmethod(kernel_instance_dispatch) # type: ignore
504
+ InteractiveShell.instance = classmethod(interactive_shell_instance_dispatch) # type: ignore
505
+ # on CI we get a mypy error:
506
+ # solara/server/patch.py:211: error: Cannot assign to a method
507
+ # solara/server/patch.py:211: error: Incompatible types in assignment (expression has type "classmethod[Any]", variable has type "Callable[[], Any]")
508
+ # not sure why we cannot reproduce that locally
509
+ ipykernel.kernelbase.Kernel.initialized = classmethod(kernel_initialized_dispatch) # type: ignore
510
+ ipywidgets.widgets.widget.get_ipython = get_ipython
511
+ # TODO: find a way to actually monkeypatch get_ipython
512
+ IPython.get_ipython = get_ipython
513
+
514
+ ipywidgets.widgets.widget_output.Output.__enter__ = Output_enter
515
+ ipywidgets.widgets.widget_output.Output.__exit__ = Output_exit
516
+
517
+ original_close = ipywidgets.widget.Widget.close
518
+ closed_ids = set()
519
+ closed_stack: Dict[int, str] = {}
520
+
521
+ def model_id_debug(self: ipywidgets.widgets.widget.Widget):
522
+ from ipyvue.ForceLoad import force_load_instance
523
+
524
+ import solara.comm
525
+
526
+ if self.comm is None and id(self) in closed_ids and id(self) in closed_stack:
527
+ raise RuntimeError(f"Widget {type(self)} has been closed, the stacktrace when the widget was closed is:\n{closed_stack[id(self)]}")
528
+
529
+ if self.comm is None or isinstance(self.comm, solara.comm.DummyComm) and force_load_instance.comm is not self.comm:
530
+ stack = solara.comm.orphan_comm_stacks.get(self.comm)
531
+ if stack:
532
+ raise RuntimeError(
533
+ "Widget has no comm, you are probably using a widget that was created at app startup, the stacktrace when the widget was created is:\n"
534
+ + stack
535
+ )
536
+ else:
537
+ raise RuntimeError("Widget has no comm, you are probably using a widget that was closed. The widget is:\n" + repr(self))
538
+
539
+ return self.comm.comm_id
540
+
541
+ ipywidgets.widget.Widget.model_id = property(model_id_debug)
542
+
543
+ def close_widget_debug(self: ipywidgets.widgets.widget.Widget):
544
+ # only in development mode, since this leaks memory
545
+ # can be called during shutdown/gc, so we need to check if the module is still there
546
+ if settings and settings.main.mode == "development":
547
+ stacktrace = "".join(traceback.format_stack())
548
+ closed_stack[id(self)] = stacktrace
549
+ closed_ids.add(id(self))
550
+ original_close(self)
551
+
552
+ ipywidgets.widget.Widget.close = close_widget_debug