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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/METADATA +7 -42
  2. solara-1.31.0.dist-info/RECORD +5 -0
  3. {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/WHEEL +1 -1
  4. {solara/template/portal → solara-1.31.0.dist-info/licenses}/LICENSE +1 -1
  5. solara/__init__.py +0 -123
  6. solara/__main__.py +0 -734
  7. solara/alias.py +0 -6
  8. solara/autorouting.py +0 -554
  9. solara/cache.py +0 -294
  10. solara/checks.html +0 -71
  11. solara/checks.py +0 -224
  12. solara/comm.py +0 -28
  13. solara/components/__init__.py +0 -59
  14. solara/components/alert.py +0 -155
  15. solara/components/applayout.py +0 -393
  16. solara/components/button.py +0 -85
  17. solara/components/card.py +0 -87
  18. solara/components/checkbox.py +0 -50
  19. solara/components/code_highlight_css.py +0 -11
  20. solara/components/code_highlight_css.vue +0 -63
  21. solara/components/columns.py +0 -159
  22. solara/components/component_vue.py +0 -109
  23. solara/components/cross_filter.py +0 -335
  24. solara/components/dataframe.py +0 -546
  25. solara/components/datatable.py +0 -221
  26. solara/components/datatable.vue +0 -175
  27. solara/components/details.py +0 -21
  28. solara/components/download.vue +0 -35
  29. solara/components/echarts.py +0 -75
  30. solara/components/echarts.vue +0 -128
  31. solara/components/figure_altair.py +0 -39
  32. solara/components/file_browser.py +0 -182
  33. solara/components/file_download.py +0 -199
  34. solara/components/file_drop.py +0 -139
  35. solara/components/file_drop.vue +0 -83
  36. solara/components/file_list_widget.vue +0 -78
  37. solara/components/head.py +0 -27
  38. solara/components/head_tag.py +0 -49
  39. solara/components/head_tag.vue +0 -60
  40. solara/components/image.py +0 -173
  41. solara/components/input.py +0 -440
  42. solara/components/link.py +0 -55
  43. solara/components/markdown.py +0 -371
  44. solara/components/markdown_editor.py +0 -25
  45. solara/components/markdown_editor.vue +0 -362
  46. solara/components/matplotlib.py +0 -74
  47. solara/components/meta.py +0 -47
  48. solara/components/misc.py +0 -333
  49. solara/components/pivot_table.py +0 -258
  50. solara/components/pivot_table.vue +0 -158
  51. solara/components/progress.py +0 -47
  52. solara/components/select.py +0 -186
  53. solara/components/select.vue +0 -27
  54. solara/components/slider.py +0 -442
  55. solara/components/slider_date.vue +0 -56
  56. solara/components/spinner-solara.vue +0 -105
  57. solara/components/spinner.py +0 -30
  58. solara/components/sql_code.py +0 -33
  59. solara/components/sql_code.vue +0 -128
  60. solara/components/style.py +0 -105
  61. solara/components/switch.py +0 -68
  62. solara/components/tab_navigation.py +0 -37
  63. solara/components/title.py +0 -90
  64. solara/components/title.vue +0 -38
  65. solara/components/togglebuttons.py +0 -202
  66. solara/components/tooltip.py +0 -61
  67. solara/datatypes.py +0 -143
  68. solara/express.py +0 -241
  69. solara/hooks/__init__.py +0 -4
  70. solara/hooks/dataframe.py +0 -99
  71. solara/hooks/misc.py +0 -263
  72. solara/hooks/use_reactive.py +0 -129
  73. solara/hooks/use_thread.py +0 -129
  74. solara/kitchensink.py +0 -8
  75. solara/lab/__init__.py +0 -34
  76. solara/lab/components/__init__.py +0 -6
  77. solara/lab/components/chat.py +0 -203
  78. solara/lab/components/confirmation_dialog.py +0 -165
  79. solara/lab/components/cross_filter.py +0 -7
  80. solara/lab/components/input_date.py +0 -298
  81. solara/lab/components/menu.py +0 -181
  82. solara/lab/components/menu.vue +0 -38
  83. solara/lab/components/tabs.py +0 -274
  84. solara/lab/components/theming.py +0 -98
  85. solara/lab/components/theming.vue +0 -72
  86. solara/lab/hooks/__init__.py +0 -0
  87. solara/lab/hooks/dataframe.py +0 -12
  88. solara/lab/toestand.py +0 -3
  89. solara/lab/utils/__init__.py +0 -2
  90. solara/lab/utils/cookies.py +0 -5
  91. solara/lab/utils/dataframe.py +0 -115
  92. solara/lab/utils/headers.py +0 -5
  93. solara/layout.py +0 -44
  94. solara/minisettings.py +0 -133
  95. solara/py.typed +0 -0
  96. solara/reactive.py +0 -93
  97. solara/routing.py +0 -268
  98. solara/scope/__init__.py +0 -87
  99. solara/scope/types.py +0 -55
  100. solara/server/__init__.py +0 -0
  101. solara/server/app.py +0 -490
  102. solara/server/assets/custom.css +0 -1
  103. solara/server/assets/custom.js +0 -1
  104. solara/server/assets/favicon.png +0 -0
  105. solara/server/assets/favicon.svg +0 -5
  106. solara/server/assets/style.css +0 -1665
  107. solara/server/assets/theme-dark.css +0 -437
  108. solara/server/assets/theme-light.css +0 -420
  109. solara/server/assets/theme.js +0 -3
  110. solara/server/cdn_helper.py +0 -77
  111. solara/server/esm.py +0 -69
  112. solara/server/fastapi.py +0 -5
  113. solara/server/flask.py +0 -286
  114. solara/server/jupyter/__init__.py +0 -2
  115. solara/server/jupyter/cdn_handler.py +0 -28
  116. solara/server/jupyter/server_extension.py +0 -29
  117. solara/server/jupytertools.py +0 -46
  118. solara/server/kernel.py +0 -319
  119. solara/server/kernel_context.py +0 -393
  120. solara/server/patch.py +0 -552
  121. solara/server/reload.py +0 -242
  122. solara/server/server.py +0 -437
  123. solara/server/settings.py +0 -212
  124. solara/server/shell.py +0 -240
  125. solara/server/starlette.py +0 -597
  126. solara/server/static/ansi.js +0 -270
  127. solara/server/static/highlight-dark.css +0 -82
  128. solara/server/static/highlight.css +0 -43
  129. solara/server/static/main-vuetify.js +0 -260
  130. solara/server/static/main.js +0 -163
  131. solara/server/static/solara_bootstrap.py +0 -129
  132. solara/server/static/sun.svg +0 -23
  133. solara/server/static/webworker.js +0 -42
  134. solara/server/telemetry.py +0 -212
  135. solara/server/templates/index.html.j2 +0 -1
  136. solara/server/templates/loader-plain.css +0 -11
  137. solara/server/templates/loader-plain.html +0 -20
  138. solara/server/templates/loader-solara.css +0 -111
  139. solara/server/templates/loader-solara.html +0 -40
  140. solara/server/templates/plain.html +0 -82
  141. solara/server/templates/solara.html.j2 +0 -446
  142. solara/server/threaded.py +0 -75
  143. solara/server/utils.py +0 -30
  144. solara/server/websocket.py +0 -44
  145. solara/settings.py +0 -56
  146. solara/tasks.py +0 -847
  147. solara/template/button.py +0 -16
  148. solara/template/markdown.py +0 -42
  149. solara/template/portal/.flake8 +0 -6
  150. solara/template/portal/.pre-commit-config.yaml +0 -28
  151. solara/template/portal/Procfile +0 -7
  152. solara/template/portal/mypy.ini +0 -3
  153. solara/template/portal/pyproject.toml +0 -26
  154. solara/template/portal/solara_portal/__init__.py +0 -3
  155. solara/template/portal/solara_portal/components/__init__.py +0 -2
  156. solara/template/portal/solara_portal/components/article.py +0 -28
  157. solara/template/portal/solara_portal/components/data.py +0 -28
  158. solara/template/portal/solara_portal/components/header.py +0 -6
  159. solara/template/portal/solara_portal/components/layout.py +0 -6
  160. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +0 -85
  161. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +0 -70
  162. solara/template/portal/solara_portal/data.py +0 -60
  163. solara/template/portal/solara_portal/pages/__init__.py +0 -67
  164. solara/template/portal/solara_portal/pages/article/__init__.py +0 -26
  165. solara/template/portal/solara_portal/pages/tabular.py +0 -29
  166. solara/template/portal/solara_portal/pages/viz/__init__.py +0 -69
  167. solara/template/portal/solara_portal/pages/viz/overview.py +0 -14
  168. solara/test/__init__.py +0 -0
  169. solara/test/pytest_plugin.py +0 -698
  170. solara/toestand.py +0 -772
  171. solara/util.py +0 -308
  172. solara/website/__init__.py +0 -0
  173. solara/website/assets/custom.css +0 -462
  174. solara/website/assets/images/logo-small.png +0 -0
  175. solara/website/assets/images/logo.svg +0 -17
  176. solara/website/assets/images/logo_white.svg +0 -50
  177. solara/website/assets/theme.js +0 -8
  178. solara/website/components/__init__.py +0 -5
  179. solara/website/components/algolia.vue +0 -24
  180. solara/website/components/algolia_api.vue +0 -157
  181. solara/website/components/docs.py +0 -118
  182. solara/website/components/header.py +0 -72
  183. solara/website/components/hero.py +0 -15
  184. solara/website/components/mailchimp.py +0 -12
  185. solara/website/components/mailchimp.vue +0 -47
  186. solara/website/components/notebook.py +0 -172
  187. solara/website/pages/__init__.py +0 -564
  188. solara/website/pages/apps/__init__.py +0 -16
  189. solara/website/pages/apps/authorization/__init__.py +0 -118
  190. solara/website/pages/apps/authorization/admin.py +0 -12
  191. solara/website/pages/apps/authorization/users.py +0 -12
  192. solara/website/pages/apps/jupyter-dashboard-1.py +0 -116
  193. solara/website/pages/apps/layout-demo.py +0 -40
  194. solara/website/pages/apps/multipage/__init__.py +0 -38
  195. solara/website/pages/apps/multipage/page1.py +0 -26
  196. solara/website/pages/apps/multipage/page2.py +0 -34
  197. solara/website/pages/apps/scatter.py +0 -136
  198. solara/website/pages/apps/scrolling.py +0 -63
  199. solara/website/pages/apps/tutorial-streamlit.py +0 -18
  200. solara/website/pages/changelog/__init__.py +0 -8
  201. solara/website/pages/changelog/changelog.md +0 -180
  202. solara/website/pages/contact/__init__.py +0 -8
  203. solara/website/pages/contact/contact.md +0 -17
  204. solara/website/pages/doc_use_download.py +0 -85
  205. solara/website/pages/documentation/__init__.py +0 -184
  206. solara/website/pages/documentation/advanced/__init__.py +0 -36
  207. solara/website/pages/documentation/advanced/content/00-overview.md +0 -1
  208. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +0 -1
  209. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +0 -191
  210. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +0 -120
  211. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +0 -149
  212. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +0 -66
  213. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +0 -43
  214. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +0 -120
  215. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +0 -4
  216. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +0 -30
  217. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +0 -38
  218. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +0 -24
  219. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +0 -104
  220. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +0 -19
  221. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +0 -3
  222. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +0 -160
  223. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +0 -13
  224. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +0 -236
  225. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +0 -81
  226. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +0 -7
  227. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +0 -1
  228. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +0 -167
  229. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  230. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +0 -41
  231. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +0 -72
  232. solara/website/pages/documentation/advanced/content/__init__.py +0 -0
  233. solara/website/pages/documentation/api/__init__.py +0 -19
  234. solara/website/pages/documentation/api/cross_filter/__init__.py +0 -9
  235. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +0 -23
  236. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +0 -22
  237. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +0 -22
  238. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +0 -22
  239. solara/website/pages/documentation/api/hooks/__init__.py +0 -9
  240. solara/website/pages/documentation/api/hooks/use_cross_filter.py +0 -25
  241. solara/website/pages/documentation/api/hooks/use_dark_effective.py +0 -13
  242. solara/website/pages/documentation/api/hooks/use_effect.md +0 -43
  243. solara/website/pages/documentation/api/hooks/use_effect.py +0 -9
  244. solara/website/pages/documentation/api/hooks/use_exception.py +0 -33
  245. solara/website/pages/documentation/api/hooks/use_memo.md +0 -16
  246. solara/website/pages/documentation/api/hooks/use_memo.py +0 -9
  247. solara/website/pages/documentation/api/hooks/use_previous.py +0 -32
  248. solara/website/pages/documentation/api/hooks/use_reactive.py +0 -15
  249. solara/website/pages/documentation/api/hooks/use_state.py +0 -11
  250. solara/website/pages/documentation/api/hooks/use_state_or_update.py +0 -68
  251. solara/website/pages/documentation/api/hooks/use_thread.md +0 -58
  252. solara/website/pages/documentation/api/hooks/use_thread.py +0 -44
  253. solara/website/pages/documentation/api/hooks/use_trait_observe.py +0 -13
  254. solara/website/pages/documentation/api/routing/__init__.py +0 -9
  255. solara/website/pages/documentation/api/routing/generate_routes.py +0 -11
  256. solara/website/pages/documentation/api/routing/generate_routes_directory.py +0 -11
  257. solara/website/pages/documentation/api/routing/resolve_path.py +0 -36
  258. solara/website/pages/documentation/api/routing/route.py +0 -32
  259. solara/website/pages/documentation/api/routing/use_route.py +0 -80
  260. solara/website/pages/documentation/api/routing/use_router.py +0 -15
  261. solara/website/pages/documentation/api/utilities/__init__.py +0 -9
  262. solara/website/pages/documentation/api/utilities/component_vue.py +0 -11
  263. solara/website/pages/documentation/api/utilities/computed.py +0 -16
  264. solara/website/pages/documentation/api/utilities/display.py +0 -15
  265. solara/website/pages/documentation/api/utilities/get_kernel_id.py +0 -16
  266. solara/website/pages/documentation/api/utilities/get_session_id.py +0 -16
  267. solara/website/pages/documentation/api/utilities/memoize.py +0 -36
  268. solara/website/pages/documentation/api/utilities/on_kernel_start.py +0 -27
  269. solara/website/pages/documentation/api/utilities/reactive.py +0 -15
  270. solara/website/pages/documentation/api/utilities/widget.py +0 -104
  271. solara/website/pages/documentation/components/__init__.py +0 -12
  272. solara/website/pages/documentation/components/advanced/__init__.py +0 -9
  273. solara/website/pages/documentation/components/advanced/link.py +0 -28
  274. solara/website/pages/documentation/components/advanced/meta.py +0 -21
  275. solara/website/pages/documentation/components/advanced/style.py +0 -44
  276. solara/website/pages/documentation/components/common.py +0 -9
  277. solara/website/pages/documentation/components/data/__init__.py +0 -9
  278. solara/website/pages/documentation/components/data/dataframe.py +0 -44
  279. solara/website/pages/documentation/components/data/pivot_table.py +0 -81
  280. solara/website/pages/documentation/components/enterprise/__init__.py +0 -9
  281. solara/website/pages/documentation/components/enterprise/avatar.py +0 -19
  282. solara/website/pages/documentation/components/enterprise/avatar_menu.py +0 -20
  283. solara/website/pages/documentation/components/input/__init__.py +0 -9
  284. solara/website/pages/documentation/components/input/button.py +0 -22
  285. solara/website/pages/documentation/components/input/checkbox.py +0 -12
  286. solara/website/pages/documentation/components/input/file_browser.py +0 -33
  287. solara/website/pages/documentation/components/input/file_drop.py +0 -75
  288. solara/website/pages/documentation/components/input/input.py +0 -18
  289. solara/website/pages/documentation/components/input/select.py +0 -21
  290. solara/website/pages/documentation/components/input/slider.py +0 -28
  291. solara/website/pages/documentation/components/input/switch.py +0 -12
  292. solara/website/pages/documentation/components/input/togglebuttons.py +0 -20
  293. solara/website/pages/documentation/components/lab/__init__.py +0 -9
  294. solara/website/pages/documentation/components/lab/chat.py +0 -108
  295. solara/website/pages/documentation/components/lab/confirmation_dialog.py +0 -55
  296. solara/website/pages/documentation/components/lab/cookies_headers.py +0 -48
  297. solara/website/pages/documentation/components/lab/input_date.py +0 -19
  298. solara/website/pages/documentation/components/lab/menu.py +0 -21
  299. solara/website/pages/documentation/components/lab/tab.py +0 -24
  300. solara/website/pages/documentation/components/lab/tabs.py +0 -44
  301. solara/website/pages/documentation/components/lab/task.py +0 -12
  302. solara/website/pages/documentation/components/lab/theming.py +0 -72
  303. solara/website/pages/documentation/components/lab/use_task.py +0 -12
  304. solara/website/pages/documentation/components/layout/__init__.py +0 -9
  305. solara/website/pages/documentation/components/layout/app_bar.py +0 -15
  306. solara/website/pages/documentation/components/layout/app_bar_title.py +0 -15
  307. solara/website/pages/documentation/components/layout/app_layout.py +0 -23
  308. solara/website/pages/documentation/components/layout/card.py +0 -14
  309. solara/website/pages/documentation/components/layout/card_actions.py +0 -15
  310. solara/website/pages/documentation/components/layout/column.py +0 -29
  311. solara/website/pages/documentation/components/layout/columns.py +0 -26
  312. solara/website/pages/documentation/components/layout/columns_responsive.py +0 -67
  313. solara/website/pages/documentation/components/layout/griddraggable.py +0 -61
  314. solara/website/pages/documentation/components/layout/gridfixed.py +0 -21
  315. solara/website/pages/documentation/components/layout/hbox.py +0 -17
  316. solara/website/pages/documentation/components/layout/row.py +0 -29
  317. solara/website/pages/documentation/components/layout/sidebar.py +0 -23
  318. solara/website/pages/documentation/components/layout/vbox.py +0 -19
  319. solara/website/pages/documentation/components/output/__init__.py +0 -9
  320. solara/website/pages/documentation/components/output/file_download.py +0 -12
  321. solara/website/pages/documentation/components/output/html.py +0 -22
  322. solara/website/pages/documentation/components/output/image.py +0 -12
  323. solara/website/pages/documentation/components/output/markdown.py +0 -59
  324. solara/website/pages/documentation/components/output/markdown_editor.py +0 -53
  325. solara/website/pages/documentation/components/output/sql_code.py +0 -84
  326. solara/website/pages/documentation/components/output/tooltip.py +0 -12
  327. solara/website/pages/documentation/components/page/__init__.py +0 -9
  328. solara/website/pages/documentation/components/page/head.py +0 -19
  329. solara/website/pages/documentation/components/page/title.py +0 -28
  330. solara/website/pages/documentation/components/status/__init__.py +0 -9
  331. solara/website/pages/documentation/components/status/error.py +0 -40
  332. solara/website/pages/documentation/components/status/info.py +0 -40
  333. solara/website/pages/documentation/components/status/progress.py +0 -10
  334. solara/website/pages/documentation/components/status/spinner.py +0 -10
  335. solara/website/pages/documentation/components/status/success.py +0 -40
  336. solara/website/pages/documentation/components/status/warning.py +0 -47
  337. solara/website/pages/documentation/components/viz/__init__.py +0 -9
  338. solara/website/pages/documentation/components/viz/altair.py +0 -44
  339. solara/website/pages/documentation/components/viz/echarts.py +0 -78
  340. solara/website/pages/documentation/components/viz/matplotlib.py +0 -32
  341. solara/website/pages/documentation/components/viz/plotly.py +0 -63
  342. solara/website/pages/documentation/components/viz/plotly_express.py +0 -41
  343. solara/website/pages/documentation/examples/__init__.py +0 -52
  344. solara/website/pages/documentation/examples/ai/__init__.py +0 -10
  345. solara/website/pages/documentation/examples/ai/chatbot.py +0 -96
  346. solara/website/pages/documentation/examples/ai/tokenizer.py +0 -106
  347. solara/website/pages/documentation/examples/basics/__init__.py +0 -2
  348. solara/website/pages/documentation/examples/basics/sine.py +0 -28
  349. solara/website/pages/documentation/examples/fullscreen/__init__.py +0 -9
  350. solara/website/pages/documentation/examples/fullscreen/authorization.py +0 -3
  351. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +0 -3
  352. solara/website/pages/documentation/examples/fullscreen/multipage.py +0 -3
  353. solara/website/pages/documentation/examples/fullscreen/scatter.py +0 -3
  354. solara/website/pages/documentation/examples/fullscreen/scrolling.py +0 -3
  355. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +0 -3
  356. solara/website/pages/documentation/examples/general/__init__.py +0 -9
  357. solara/website/pages/documentation/examples/general/custom_storage.py +0 -69
  358. solara/website/pages/documentation/examples/general/deploy_model.py +0 -114
  359. solara/website/pages/documentation/examples/general/live_update.py +0 -38
  360. solara/website/pages/documentation/examples/general/login_oauth.py +0 -76
  361. solara/website/pages/documentation/examples/general/mycard.vue +0 -58
  362. solara/website/pages/documentation/examples/general/pokemon_search.py +0 -51
  363. solara/website/pages/documentation/examples/general/vue_component.py +0 -50
  364. solara/website/pages/documentation/examples/ipycanvas.py +0 -49
  365. solara/website/pages/documentation/examples/libraries/__init__.py +0 -9
  366. solara/website/pages/documentation/examples/libraries/altair.py +0 -63
  367. solara/website/pages/documentation/examples/libraries/bqplot.py +0 -39
  368. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +0 -32
  369. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +0 -65
  370. solara/website/pages/documentation/examples/utilities/__init__.py +0 -9
  371. solara/website/pages/documentation/examples/utilities/calculator.py +0 -157
  372. solara/website/pages/documentation/examples/utilities/countdown_timer.py +0 -64
  373. solara/website/pages/documentation/examples/utilities/todo.py +0 -195
  374. solara/website/pages/documentation/examples/visualization/__init__.py +0 -6
  375. solara/website/pages/documentation/examples/visualization/annotator.py +0 -68
  376. solara/website/pages/documentation/examples/visualization/linked_views.py +0 -84
  377. solara/website/pages/documentation/examples/visualization/plotly.py +0 -43
  378. solara/website/pages/documentation/faq/__init__.py +0 -11
  379. solara/website/pages/documentation/faq/content/99-faq.md +0 -73
  380. solara/website/pages/documentation/getting_started/__init__.py +0 -15
  381. solara/website/pages/documentation/getting_started/content/00-quickstart.md +0 -84
  382. solara/website/pages/documentation/getting_started/content/01-introduction.md +0 -121
  383. solara/website/pages/documentation/getting_started/content/02-installing.md +0 -81
  384. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +0 -9
  385. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +0 -13
  386. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +0 -84
  387. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +0 -120
  388. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +0 -141
  389. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +0 -140
  390. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +0 -64
  391. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  392. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +0 -445
  393. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +0 -1000
  394. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +0 -7
  395. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +0 -218
  396. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +0 -83
  397. solara/website/pages/documentation/getting_started/content/06-reference/00-overview.md +0 -3
  398. solara/website/pages/documentation/getting_started/content/06-reference/40-static_files.md +0 -27
  399. solara/website/pages/documentation/getting_started/content/06-reference/41-asset-files.md +0 -32
  400. solara/website/pages/documentation/getting_started/content/06-reference/60-static-site-generation.md +0 -55
  401. solara/website/pages/documentation/getting_started/content/06-reference/70-search.md +0 -30
  402. solara/website/pages/documentation/getting_started/content/06-reference/80-reloading.md +0 -30
  403. solara/website/pages/documentation/getting_started/content/06-reference/90-notebook-support.md +0 -4
  404. solara/website/pages/documentation/getting_started/content/06-reference/95-caching.md +0 -143
  405. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +0 -3
  406. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +0 -269
  407. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +0 -76
  408. solara/website/pages/documentation/getting_started/content/08-lab/00-what-is-lab.md +0 -3
  409. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +0 -22
  410. solara/website/pages/documentation/getting_started/content/__init__.py +0 -0
  411. solara/website/pages/docutils.py +0 -38
  412. solara/website/pages/showcase/__init__.py +0 -105
  413. solara/website/pages/showcase/domino_code_assist.py +0 -60
  414. solara/website/pages/showcase/planeto_tessa.py +0 -19
  415. solara/website/pages/showcase/solara_dev.py +0 -54
  416. solara/website/pages/showcase/solarathon_2023_team_2.py +0 -22
  417. solara/website/pages/showcase/solarathon_2023_team_4.py +0 -22
  418. solara/website/pages/showcase/solarathon_2023_team_5.py +0 -23
  419. solara/website/pages/showcase/solarathon_2023_team_6.py +0 -34
  420. solara/website/pages/showcase/wanderlust.py +0 -27
  421. solara/website/public/beach.jpeg +0 -0
  422. solara/website/public/logo.svg +0 -6
  423. solara/website/public/social/discord.svg +0 -1
  424. solara/website/public/social/github.svg +0 -1
  425. solara/website/public/social/twitter.svg +0 -3
  426. solara/website/public/success.html +0 -25
  427. solara/website/templates/index.html.j2 +0 -117
  428. solara/website/utils.py +0 -51
  429. solara/widgets/__init__.py +0 -1
  430. solara/widgets/vue/gridlayout.vue +0 -110
  431. solara/widgets/vue/html.vue +0 -4
  432. solara/widgets/vue/navigator.vue +0 -104
  433. solara/widgets/vue/vegalite.vue +0 -115
  434. solara/widgets/widgets.py +0 -65
  435. solara-1.30.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -7
  436. solara-1.30.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -7
  437. solara-1.30.0.dist-info/RECORD +0 -438
  438. solara-1.30.0.dist-info/entry_points.txt +0 -5
  439. /solara-1.30.0.dist-info/licenses/LICENSE → /LICENSE +0 -0
solara/server/reload.py DELETED
@@ -1,242 +0,0 @@
1
- import contextlib
2
- import errno
3
- import importlib
4
- import inspect
5
- import logging
6
- import os
7
- import sys
8
- import threading
9
- from pathlib import Path
10
- from typing import Any, Callable, Dict, List, Optional, Set, Type
11
-
12
- import solara.server.settings as settings
13
-
14
- NO_WATCHDOG = False
15
- try:
16
- from watchdog.events import FileSystemEventHandler
17
- from watchdog.observers import Observer
18
- except ImportError:
19
- pass
20
- NO_WATCHDOG = True
21
- logger = logging.getLogger("solara.server.reload")
22
-
23
-
24
- class Watcher:
25
- def __init__(self, files, on_change: Callable[[str], None]):
26
- pass
27
-
28
- def close(self):
29
- pass
30
-
31
- def add_file(self, file):
32
- pass
33
-
34
-
35
- class WatcherDummy:
36
- def __init__(self, files, on_change: Callable[[str], None]):
37
- pass
38
-
39
- def close(self):
40
- pass
41
-
42
- def add_file(self, file):
43
- pass
44
-
45
-
46
- if NO_WATCHDOG:
47
- WatcherType: Type[Watcher] = WatcherDummy # type: ignore
48
-
49
- else:
50
-
51
- class WatcherWatchdog(FileSystemEventHandler):
52
- def __init__(self, files, on_change: Callable[[str], None]):
53
- self.on_change = on_change
54
- self.observers: List[Any] = []
55
- self.directories: Set[str] = set()
56
- self.files: List[str] = []
57
- self.mtimes: Dict[str, float] = dict()
58
- for file in files:
59
- self.add_file(file)
60
-
61
- def close(self):
62
- for o in self.observers:
63
- o.unschedule_all()
64
- o.stop()
65
- # this makes testing slow
66
- # for o in self.observers:
67
- # o.join()
68
-
69
- def add_file(self, file):
70
- file = os.path.abspath(os.path.realpath(file))
71
- if file not in self.files:
72
- logger.debug("Watching file %s", file)
73
- if file in self.files:
74
- raise RuntimeError(f"{file} was already added")
75
- self.files.append(file)
76
- self._watch_file(file)
77
-
78
- def _watch_file(self, file):
79
- self.mtimes[file] = os.path.getmtime(file)
80
- directory = os.path.realpath(os.path.dirname(file))
81
- self.watch_directory(directory)
82
-
83
- def watch_directory(self, directory):
84
- if directory not in self.directories:
85
- logger.debug("Watching directory %s", directory)
86
- observer = Observer()
87
- observer.schedule(self, directory, recursive=False)
88
- try:
89
- observer.start()
90
- except OSError as e:
91
- if e.errno == errno.ENOSPC:
92
- # from rich import print()
93
- from .utils import start_error
94
-
95
- start_error(
96
- "inotify watch limit reached", "Read https://github.com/widgetti/solara/#how-to-fix-inotify-watch-limit-reached", exception=e
97
- )
98
-
99
- self.observers.append(observer)
100
- self.directories.add(directory)
101
-
102
- def on_modified(self, event):
103
- super().on_modified(event)
104
- logger.debug("Watch event: %s", event)
105
- if not event.is_directory:
106
- if event.src_path in self.files:
107
- mtime_new = os.path.getmtime(event.src_path)
108
- changed = mtime_new > self.mtimes[event.src_path]
109
- self.mtimes[event.src_path] = mtime_new
110
- if changed:
111
- logger.debug("File modified: %s", event.src_path)
112
- try:
113
- self.on_change(event.src_path)
114
- except: # noqa
115
- # we are in the watchdog thread here, all we can do is report
116
- # and continue running (otherwise reload stops working)
117
- logger.exception("Error while executing on change handler")
118
- else:
119
- logger.debug("File reported modified, but mtime did not change: %s", event.src_path)
120
- else:
121
- logger.debug("Ignore file modification: %s", event.src_path)
122
-
123
- WatcherType = WatcherWatchdog # type: ignore
124
-
125
-
126
- class Reloader:
127
- def __init__(self, on_change: Optional[Callable[[str], None]] = None) -> None:
128
- self.watched_modules: Set[str] = set()
129
- self._first = True
130
- self.on_change: Optional[Callable[[str], None]] = on_change
131
- WatcherCls = WatcherType if settings.main.mode == "development" else WatcherDummy
132
- self.watcher = WatcherCls([], self._on_change)
133
- self.requires_reload = False
134
- self.ignore_modules: Set[str] = set()
135
- self.reload_event_next = threading.Event()
136
- # should be set at app.directory
137
- self.root_path: Optional[Path] = None
138
- # maybe we want this mode enabled in the future via configuration
139
- # this is useful if you have some packages installed in editable mode
140
- # and you want to quick reload. However this does not always work:
141
- # * https://github.com/widgetti/solara/issues/177
142
- # * https://github.com/widgetti/solara/issues/148
143
- self.aggresive_reload = False
144
-
145
- def start(self):
146
- if self._first:
147
- # although we try to keep track of modules loaded (which we will watch)
148
- # it can happen that an import is done at runtime, that we miss (could be in a thread)
149
- # so we always reload all modules except the ignore_modules
150
- self.ignore_modules = set(sys.modules)
151
- logger.debug("Ignoring reloading modules: %s", self.ignore_modules)
152
- self._first = False
153
-
154
- def _on_change(self, name):
155
- # flag that we need to reload all modules next time
156
- self.requires_reload = True
157
- # and forward callback
158
- if self.on_change:
159
- self.on_change(name)
160
- # used for testing
161
- self.reload_event_next.set()
162
-
163
- def close(self):
164
- self.watcher.close()
165
-
166
- def get_reload_module_names(self):
167
- if self.aggresive_reload:
168
- # not sure why, but if we reload pandas, the integration/reload_test.py fails
169
- return {
170
- k for k in set(sys.modules) - set(self.ignore_modules) if not (k.startswith("solara.server") or k.startswith("anyio") or k.startswith("pandas"))
171
- }
172
- else:
173
- reload = []
174
- for name in sorted(sys.modules):
175
- mod = sys.modules[name]
176
- if name.startswith("solara.server"):
177
- continue # this will break everything
178
- if name in self.ignore_modules:
179
- continue # nothing we imported from solara itself like starlette etc
180
- # we only reload modules that are in the root path
181
- if (getattr(mod, "__file__", None) or "").startswith(str(self.root_path)):
182
- reload.append(name)
183
- return reload
184
-
185
- def reload(self):
186
- # before we did this:
187
- # # don't reload modules like solara.server and react
188
- # # that may cause issues (like 2 Element classes existing)
189
- reload_modules = self.get_reload_module_names()
190
- # which picks up import that are done in threads etc, but it will also reload starlette, httptools etc
191
- # which causes issues with exceptions and isinstance checks.
192
- # reload_modules = self.watched_modules
193
- logger.info("Reloading modules... %s", reload_modules)
194
- # not sure if this is needed
195
- importlib.invalidate_caches()
196
- for mod_name in sorted(reload_modules):
197
- # don't reload modules like solara.server and react
198
- # that may cause issues (like 2 Element classes existing)
199
- logger.debug("Reloading module %s", mod_name)
200
- sys.modules.pop(mod_name, None)
201
- # if all successful...
202
- self.requires_reload = False
203
-
204
- @contextlib.contextmanager
205
- def watch(self):
206
- """Use this context manager to execute code so that we can track loaded modules and reload them when needed"""
207
- if self.requires_reload:
208
- self.reload()
209
-
210
- modules_before = set(sys.modules)
211
- try:
212
- yield
213
- finally:
214
- modules_after = set(sys.modules)
215
- # these are imported during the 'yield'
216
- modules_added = modules_after - modules_before
217
- modules_to_consider = modules_added - set(self.watched_modules)
218
- # TODO: libraries that solara uses need special care
219
- # modules_always = {k for k in sys.modules if k.startswith("reacton")}
220
- # modules_to_consider = modules_to_consider | modules_always
221
- modules_watching = set()
222
- if modules_to_consider:
223
- logger.debug("Found modules %s", modules_to_consider)
224
- for modname in modules_to_consider:
225
- module = sys.modules[modname]
226
- path = None
227
- try:
228
- path = inspect.getfile(module)
229
- except Exception:
230
- pass
231
- if path and Path(path).exists():
232
- if not path.startswith(sys.prefix):
233
- self.watcher.add_file(path)
234
- self.watched_modules.add(modname)
235
- modules_watching.add(modname)
236
- if modules_watching:
237
- logger.debug("Watching modules: %s for reload", modules_watching)
238
-
239
-
240
- # there is only a reloader, and there should be only 1 app
241
- # that connect to the on_change
242
- reloader = Reloader()
solara/server/server.py DELETED
@@ -1,437 +0,0 @@
1
- import contextlib
2
- import hashlib
3
- import json
4
- import logging
5
- import os
6
- import sys
7
- import time
8
- from pathlib import Path
9
- from typing import Dict, List, Optional, Tuple, TypeVar
10
-
11
- import ipykernel
12
- import ipyvue
13
- import ipywidgets
14
- import jinja2
15
- import requests
16
- import solara
17
- import solara.routing
18
- import solara.settings
19
- from solara.lab import cookies as solara_cookies
20
- from solara.lab import headers as solara_headers
21
-
22
- from . import app, jupytertools, patch, settings, websocket
23
- from .kernel import Kernel, deserialize_binary_message
24
- from .kernel_context import initialize_virtual_kernel
25
-
26
- COOKIE_KEY_SESSION_ID = "solara-session-id"
27
-
28
- T = TypeVar("T")
29
-
30
-
31
- directory = Path(__file__).parent
32
- template_name = "index.html.j2"
33
- ipykernel_major = int(ipykernel.__version__.split(".")[0])
34
- ipywidgets_major = int(ipywidgets.__version__.split(".")[0])
35
- cache_memory = solara.cache.Memory(max_items=128)
36
- vue3 = ipyvue.__version__.startswith("3")
37
- _redirects: Dict[str, str] = {}
38
-
39
- # first look at the project directory, then the builtin solara directory
40
-
41
-
42
- @solara.memoize(storage=cache_memory)
43
- def get_jinja_env(app_name: str) -> jinja2.Environment:
44
- jinja_loader = jinja2.FileSystemLoader(
45
- [
46
- app.apps["__default__"].directory.parent / "templates",
47
- str(directory / "templates"),
48
- ]
49
- )
50
- jinja_env = jinja2.Environment(loader=jinja_loader, autoescape=True)
51
- return jinja_env
52
-
53
-
54
- logger = logging.getLogger("solara.server.server")
55
- nbextensions_ignorelist = [
56
- "jupytext/index",
57
- "nbextensions_configurator/config_menu/main",
58
- "jupytext/index",
59
- "nbdime/index",
60
- "voila/extension",
61
- "contrib_nbextensions_help_item/main",
62
- "execute_time/ExecuteTime",
63
- "dominocode/extension",
64
- "low-code-assistant/extension",
65
- "domino-code-assist/extension",
66
- "jupyter-js/extension",
67
- "jupyter-js-widgets/extension",
68
- "jupyter_dash/main",
69
- ]
70
-
71
-
72
- def readyz():
73
- return {"status": "ok"}, 200
74
-
75
-
76
- def wait_ready(url, timeout=10) -> None:
77
- """Wait for a solara server at root url to be ready, or throw a TimeoutError
78
-
79
- This uses the /readyz endpoint to check if the server is ready.
80
-
81
- >>> solara.server.server.wait_ready("http://localhost:8888")
82
- ...
83
-
84
- """
85
- t0 = time.time()
86
- while True:
87
- try:
88
- r = requests.get(url + "/readyz")
89
- if r.status_code == 200:
90
- return
91
- except Exception:
92
- pass
93
- time.sleep(0.1)
94
- if time.time() - t0 > timeout:
95
- raise TimeoutError(f"Timeout waiting for {url}")
96
-
97
-
98
- def is_ready(url) -> bool:
99
- """Returns whether a solara server at root url is ready.
100
-
101
- This uses the /readyz endpoint to check if the server is ready.
102
-
103
- >>> solara.server.server.is_ready("http://localhost:8888")
104
- True
105
-
106
- """
107
- try:
108
- r = requests.get(url + "/readyz")
109
- if r.status_code == 200:
110
- return True
111
- except Exception:
112
- pass
113
- return False
114
-
115
-
116
- async def app_loop(ws: websocket.WebsocketWrapper, cookies: Dict[str, str], headers, session_id: str, kernel_id: str, page_id: str, user: dict = None):
117
- context = initialize_virtual_kernel(session_id, kernel_id, ws)
118
- if context is None:
119
- logging.warning("invalid kernel id: %r", kernel_id)
120
- # to avoid very fast reconnects (we are in a thread anyway)
121
- time.sleep(0.5)
122
- return
123
-
124
- if settings.main.tracer:
125
- import viztracer
126
-
127
- output_file = f"viztracer-{page_id}.html"
128
- run_context = viztracer.VizTracer(output_file=output_file, max_stack_depth=10)
129
- logger.warning(f"Running with tracer: {output_file}")
130
- else:
131
- run_context = solara.util.nullcontext()
132
-
133
- kernel = context.kernel
134
- try:
135
- context.page_connect(page_id)
136
- with run_context, context:
137
- if user:
138
- from solara_enterprise.auth import user as solara_user
139
-
140
- solara_user.set(user)
141
-
142
- solara_cookies.set(cookies) # type: ignore
143
- solara_headers.set(headers) # type: ignore
144
-
145
- while True:
146
- if settings.main.timing:
147
- widgets_ids = set(patch.widgets)
148
- try:
149
- message = await ws.receive()
150
- except websocket.WebSocketDisconnect:
151
- try:
152
- context.kernel.session.websockets.remove(ws)
153
- except KeyError:
154
- pass
155
- logger.debug("Disconnected")
156
- break
157
- t0 = time.time()
158
- if isinstance(message, str):
159
- msg = json.loads(message)
160
- else:
161
- msg = deserialize_binary_message(message)
162
- t1 = time.time()
163
- if not process_kernel_messages(kernel, msg):
164
- # if we shut down the kernel, we do not keep the page session alive
165
- context.close()
166
- return
167
- t2 = time.time()
168
- if settings.main.timing:
169
- widgets_ids_after = set(patch.widgets)
170
- created_widgets_count = len(widgets_ids_after - widgets_ids)
171
- close_widgets_count = len(widgets_ids - widgets_ids_after)
172
- print( # noqa: T201
173
- f"timing: total={t2-t0:.3f}s, deserialize={t1-t0:.3f}s, kernel={t2-t1:.3f}s"
174
- f" widget: created: {created_widgets_count} closed: {close_widgets_count}"
175
- )
176
- finally:
177
- context.page_disconnect(page_id)
178
-
179
-
180
- def process_kernel_messages(kernel: Kernel, msg: Dict) -> bool:
181
- session = kernel.session
182
- assert session is not None
183
- comm_manager = kernel.comm_manager
184
-
185
- def send_status(status, parent):
186
- session.send(
187
- kernel.iopub_socket,
188
- "status",
189
- {"execution_state": status},
190
- parent=parent,
191
- ident=None,
192
- )
193
-
194
- @contextlib.contextmanager
195
- def busy_idle(parent):
196
- send_status("busy", parent=parent)
197
- try:
198
- yield
199
- finally:
200
- send_status("idle", parent=parent)
201
-
202
- msg_type = msg["header"]["msg_type"]
203
-
204
- if ipykernel_major < 6:
205
- # the channel argument was added in 6.0
206
- kernel.set_parent(None, msg)
207
- else:
208
- kernel.set_parent(None, msg, msg["channel"])
209
- if msg_type == "kernel_info_request":
210
- content = {
211
- "status": "ok",
212
- "protocol_version": "5.3",
213
- "implementation": Kernel.implementation,
214
- "implementation_version": Kernel.implementation_version,
215
- "language_info": {},
216
- "banner": Kernel.banner,
217
- "help_links": [],
218
- }
219
- with busy_idle(msg["header"]):
220
- msg = kernel.session.send(kernel.shell_stream, "kernel_info_reply", content, msg["header"], None)
221
- return True
222
- elif msg_type in ["comm_open", "comm_msg", "comm_close"]:
223
- with busy_idle(msg["header"]):
224
- getattr(comm_manager, msg_type)(kernel.shell_stream, None, msg)
225
- return True
226
- elif msg_type in ["comm_info_request"]:
227
- content = msg["content"]
228
- target_name = msg.get("target_name", None)
229
-
230
- comms = {
231
- k: dict(target_name=v.target_name) for (k, v) in comm_manager.comms.items() if v.target_name == target_name or target_name is None # type: ignore
232
- }
233
- reply_content = dict(comms=comms, status="ok")
234
- with busy_idle(msg["header"]):
235
- msg = session.send(
236
- kernel.shell_stream,
237
- "comm_info_reply",
238
- reply_content,
239
- msg["header"],
240
- None,
241
- )
242
- return True
243
- elif msg_type == "shutdown_request":
244
- send_status("dead", parent=msg["header"])
245
- return False
246
- else:
247
- logger.error("Unsupported msg with msg_type %r", msg_type)
248
- return False
249
-
250
-
251
- def read_root(path: str, root_path: str = "", render_kwargs={}, use_nbextensions=True, ssg_data=None) -> Optional[str]:
252
- if settings.ssg.enabled and ssg_data is None:
253
- # simply return the pre-rendered html
254
- from solara_enterprise import ssg
255
-
256
- content = ssg.ssg_content(path)
257
- if content is not None:
258
- return content
259
-
260
- default_app = app.apps["__default__"]
261
- routes = default_app.routes
262
- router = solara.routing.Router(path, routes)
263
- if not router.possible_match:
264
- return None
265
- if use_nbextensions:
266
- nbextensions, nbextensions_hashes = get_nbextensions()
267
- else:
268
- nbextensions, nbextensions_hashes = [], {}
269
-
270
- from markupsafe import Markup
271
-
272
- def resolve_static_path(path: str) -> Path:
273
- # this solve a similar problem as the starlette and flask endpoints
274
- # maybe this can be common code for all of them.
275
- if path.startswith("/static/public/"):
276
- directories = [default_app.directory.parent / "public"]
277
- filename = path[len("/static/public/") :]
278
- elif path.startswith("/static/assets/"):
279
- directories = [default_app.directory.parent / "assets", solara_static.parent / "assets"]
280
- filename = path[len("/static/assets/") :]
281
- elif path.startswith("/static/"):
282
- directories = [solara_static.parent / "static"]
283
- filename = path[len("/static/") :]
284
- else:
285
- raise ValueError(f"invalid static path: {path}")
286
- for directory in directories:
287
- full_path = directory / filename
288
- if full_path.exists():
289
- return full_path
290
- raise ValueError(f"static path not found: {filename} (path={path}), looked in {directories}")
291
-
292
- def include_css(path: str) -> Markup:
293
- filepath = resolve_static_path(path)
294
- content, hash = solara.util.get_file_hash(filepath)
295
- url = f"{root_path}{path}?v={hash}"
296
- # when < 10k we embed, also when we use a url, it can be relative, which can break the url
297
- embed = len(content) < 1024 * 10 and b"url" not in content
298
- # Always embed the jupyterlab theme CSS to make theme switching possible (see solara.html.j2 template)
299
- # TODO: Prevent browser from caching the theme CSS files
300
- if path.endswith("theme-dark.css") or path.endswith("theme-light.css"):
301
- content_utf8 = content.decode("utf-8")
302
- code = content_utf8
303
- elif embed:
304
- content_utf8 = content.decode("utf-8")
305
- code = f'<style class="solara-template-css">/*\npath={path}\n*/\n{content_utf8}</style>'
306
- else:
307
- code = f'<link rel="stylesheet" type="text/css" href="{url}" class="solara-template-css">'
308
- return Markup(code)
309
-
310
- def include_js(path: str, module=False) -> Markup:
311
- filepath = resolve_static_path(path)
312
- content, hash = solara.util.get_file_hash(filepath)
313
- content_utf8 = content.decode("utf-8")
314
- url = f"{root_path}{path}?v={hash}"
315
- # when < 10k we embed, but if we use currentScript, it can break things
316
- embed = len(content) < 1024 * 10 and b"currentScript" not in content
317
- if embed:
318
- if module:
319
- code = f'<script type="module">/*\npath={path}\n*/{content_utf8}</script>'
320
- else:
321
- code = f"<script>/*\npath={path}\n*/{content_utf8}</script>"
322
- else:
323
- if module:
324
- code = f'<script type="module" src="{url}"></script>'
325
- else:
326
- code = f'<script src="{url}"></script>'
327
- return Markup(code)
328
-
329
- resources = {
330
- "theme": "light",
331
- "nbextensions": nbextensions,
332
- "nbextensions_hashes": nbextensions_hashes,
333
- "include_css": include_css,
334
- "include_js": include_js,
335
- }
336
- template: jinja2.Template = get_jinja_env(app_name="__default__").get_template(template_name)
337
- pre_rendered_html = ""
338
- pre_rendered_css = ""
339
- pre_rendered_metas = ""
340
- title = "Solara ☀️"
341
- if ssg_data is not None:
342
- pre_rendered_html = ssg_data["html"]
343
- pre_rendered_css = "\n".join(ssg_data["styles"])
344
- pre_rendered_metas = "\n ".join(ssg_data["metas"])
345
- title = ssg_data["title"]
346
-
347
- if solara.settings.assets.proxy:
348
- # solara acts as a proxy
349
- cdn = f"{root_path}/_solara/cdn"
350
- else:
351
- cdn = solara.settings.assets.cdn
352
-
353
- render_settings = {
354
- "title": title,
355
- "path": path,
356
- "root_path": root_path,
357
- "resources": resources,
358
- "theme": settings.theme.dict(),
359
- "production": settings.main.mode == "production",
360
- "pre_rendered_html": pre_rendered_html,
361
- "pre_rendered_css": pre_rendered_css,
362
- "pre_rendered_metas": pre_rendered_metas,
363
- "assets": settings.assets.dict(),
364
- "cdn": cdn,
365
- "ipywidget_major_version": ipywidgets_major,
366
- "solara_version": solara.__version__,
367
- "platform": settings.main.platform,
368
- "vue3": vue3,
369
- "perform_check": settings.main.mode != "production" and solara.checks.should_perform_solara_check(),
370
- **render_kwargs,
371
- }
372
- response = template.render(**render_settings)
373
- return response
374
-
375
-
376
- def find_prefixed_directory(path):
377
- prefixes = [sys.prefix, os.path.expanduser("~/.local")]
378
- for prefix in prefixes:
379
- directory = f"{prefix}{path}"
380
- if Path(directory).exists():
381
- return directory
382
- else:
383
- raise RuntimeError(f"{path} not found at prefixes: {prefixes}")
384
-
385
-
386
- @solara.memoize(storage=cache_memory)
387
- def get_nbextensions_directories() -> List[Path]:
388
- from jupyter_core.paths import jupyter_path
389
-
390
- all_nb_directories = [Path(k) for k in jupyter_path("nbextensions")]
391
- # FIXME: remove IPython nbextensions path after a migration period
392
- try:
393
- from IPython.paths import get_ipython_dir
394
- except ImportError:
395
- pass
396
- else:
397
- all_nb_directories.append(Path(get_ipython_dir()) / "nbextensions")
398
- return [Path(k) for k in all_nb_directories]
399
-
400
-
401
- @solara.memoize(storage=cache_memory)
402
- def get_nbextensions() -> Tuple[List[str], Dict[str, Optional[str]]]:
403
- from jupyter_core.paths import jupyter_config_path
404
-
405
- paths = [Path(p) / "nbconfig" for p in jupyter_config_path()]
406
-
407
- load_extensions = jupytertools.get_config(paths, "notebook")["load_extensions"]
408
-
409
- def exists(name):
410
- for directory in nbextensions_directories:
411
- if (directory / (name + ".js")).exists():
412
- return True
413
- logger.info(f"nbextension {name} not found")
414
- return False
415
-
416
- def hash_extension(name):
417
- if sys.version_info[:2] < (3, 9):
418
- # usedforsecurity is only available in Python 3.9+
419
- h = hashlib.new("md5")
420
- else:
421
- h = hashlib.new("md5", usedforsecurity=False) # type: ignore
422
-
423
- for directory in nbextensions_directories:
424
- if (directory / (name + ".js")).exists():
425
- for file in directory.glob("**/*.*"):
426
- data = file.read_bytes()
427
- h.update(data)
428
-
429
- return h.hexdigest()
430
-
431
- nbextensions: List[str] = [name for name, enabled in load_extensions.items() if enabled and (name not in nbextensions_ignorelist) and exists(name)]
432
- nbextensions_hashes = {name: hash_extension(name) for name in nbextensions}
433
- return nbextensions, nbextensions_hashes
434
-
435
-
436
- nbextensions_directories = get_nbextensions_directories()
437
- solara_static = Path(__file__).parent / "static"