solara-ui 1.45.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  2. prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  3. solara/__init__.py +124 -0
  4. solara/__main__.py +765 -0
  5. solara/_stores.py +297 -0
  6. solara/alias.py +6 -0
  7. solara/autorouting.py +555 -0
  8. solara/cache.py +305 -0
  9. solara/checks.html +71 -0
  10. solara/checks.py +227 -0
  11. solara/comm.py +28 -0
  12. solara/components/__init__.py +77 -0
  13. solara/components/alert.py +155 -0
  14. solara/components/applayout.py +397 -0
  15. solara/components/button.py +85 -0
  16. solara/components/card.py +87 -0
  17. solara/components/checkbox.py +50 -0
  18. solara/components/code_highlight_css.py +11 -0
  19. solara/components/code_highlight_css.vue +63 -0
  20. solara/components/columns.py +159 -0
  21. solara/components/component_vue.py +134 -0
  22. solara/components/cross_filter.py +335 -0
  23. solara/components/dataframe.py +546 -0
  24. solara/components/datatable.py +214 -0
  25. solara/components/datatable.vue +175 -0
  26. solara/components/details.py +56 -0
  27. solara/components/download.vue +35 -0
  28. solara/components/echarts.py +86 -0
  29. solara/components/echarts.vue +139 -0
  30. solara/components/figure_altair.py +39 -0
  31. solara/components/file_browser.py +181 -0
  32. solara/components/file_download.py +199 -0
  33. solara/components/file_drop.py +159 -0
  34. solara/components/file_drop.vue +83 -0
  35. solara/components/file_list_widget.vue +78 -0
  36. solara/components/head.py +27 -0
  37. solara/components/head_tag.py +49 -0
  38. solara/components/head_tag.vue +60 -0
  39. solara/components/image.py +173 -0
  40. solara/components/input.py +456 -0
  41. solara/components/input_text_area.py +86 -0
  42. solara/components/link.py +55 -0
  43. solara/components/markdown.py +441 -0
  44. solara/components/markdown_editor.py +33 -0
  45. solara/components/markdown_editor.vue +359 -0
  46. solara/components/matplotlib.py +74 -0
  47. solara/components/meta.py +47 -0
  48. solara/components/misc.py +333 -0
  49. solara/components/pivot_table.py +258 -0
  50. solara/components/pivot_table.vue +158 -0
  51. solara/components/progress.py +47 -0
  52. solara/components/select.py +182 -0
  53. solara/components/select.vue +27 -0
  54. solara/components/slider.py +442 -0
  55. solara/components/slider_date.vue +56 -0
  56. solara/components/spinner-solara.vue +105 -0
  57. solara/components/spinner.py +45 -0
  58. solara/components/sql_code.py +41 -0
  59. solara/components/sql_code.vue +125 -0
  60. solara/components/style.py +105 -0
  61. solara/components/switch.py +71 -0
  62. solara/components/tab_navigation.py +37 -0
  63. solara/components/title.py +90 -0
  64. solara/components/title.vue +38 -0
  65. solara/components/togglebuttons.py +200 -0
  66. solara/components/tooltip.py +61 -0
  67. solara/core.py +42 -0
  68. solara/datatypes.py +143 -0
  69. solara/express.py +241 -0
  70. solara/hooks/__init__.py +4 -0
  71. solara/hooks/dataframe.py +99 -0
  72. solara/hooks/misc.py +263 -0
  73. solara/hooks/use_reactive.py +151 -0
  74. solara/hooks/use_thread.py +129 -0
  75. solara/kitchensink.py +8 -0
  76. solara/lab/__init__.py +34 -0
  77. solara/lab/components/__init__.py +7 -0
  78. solara/lab/components/chat.py +215 -0
  79. solara/lab/components/confirmation_dialog.py +163 -0
  80. solara/lab/components/cross_filter.py +7 -0
  81. solara/lab/components/input_date.py +339 -0
  82. solara/lab/components/input_time.py +133 -0
  83. solara/lab/components/menu.py +181 -0
  84. solara/lab/components/menu.vue +38 -0
  85. solara/lab/components/tabs.py +274 -0
  86. solara/lab/components/theming.py +98 -0
  87. solara/lab/components/theming.vue +72 -0
  88. solara/lab/hooks/__init__.py +0 -0
  89. solara/lab/hooks/dataframe.py +2 -0
  90. solara/lab/toestand.py +3 -0
  91. solara/lab/utils/__init__.py +2 -0
  92. solara/lab/utils/cookies.py +5 -0
  93. solara/lab/utils/dataframe.py +165 -0
  94. solara/lab/utils/headers.py +5 -0
  95. solara/layout.py +44 -0
  96. solara/lifecycle.py +46 -0
  97. solara/minisettings.py +141 -0
  98. solara/py.typed +0 -0
  99. solara/reactive.py +99 -0
  100. solara/routing.py +268 -0
  101. solara/scope/__init__.py +88 -0
  102. solara/scope/types.py +55 -0
  103. solara/server/__init__.py +0 -0
  104. solara/server/app.py +527 -0
  105. solara/server/assets/custom.css +1 -0
  106. solara/server/assets/custom.js +1 -0
  107. solara/server/assets/favicon.png +0 -0
  108. solara/server/assets/favicon.svg +5 -0
  109. solara/server/assets/style.css +1681 -0
  110. solara/server/assets/theme-dark.css +437 -0
  111. solara/server/assets/theme-light.css +420 -0
  112. solara/server/assets/theme.js +3 -0
  113. solara/server/cdn_helper.py +91 -0
  114. solara/server/esm.py +71 -0
  115. solara/server/fastapi.py +5 -0
  116. solara/server/flask.py +297 -0
  117. solara/server/jupyter/__init__.py +2 -0
  118. solara/server/jupyter/cdn_handler.py +28 -0
  119. solara/server/jupyter/server_extension.py +40 -0
  120. solara/server/jupyter/solara.py +91 -0
  121. solara/server/jupytertools.py +46 -0
  122. solara/server/kernel.py +388 -0
  123. solara/server/kernel_context.py +467 -0
  124. solara/server/patch.py +564 -0
  125. solara/server/pyinstaller/__init__.py +9 -0
  126. solara/server/pyinstaller/hook-ipyreact.py +5 -0
  127. solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
  128. solara/server/pyinstaller/hook-solara.py +9 -0
  129. solara/server/qt.py +113 -0
  130. solara/server/reload.py +251 -0
  131. solara/server/server.py +484 -0
  132. solara/server/settings.py +249 -0
  133. solara/server/shell.py +269 -0
  134. solara/server/starlette.py +770 -0
  135. solara/server/static/ansi.js +270 -0
  136. solara/server/static/highlight-dark.css +82 -0
  137. solara/server/static/highlight.css +43 -0
  138. solara/server/static/main-vuetify.js +272 -0
  139. solara/server/static/main.js +163 -0
  140. solara/server/static/solara_bootstrap.py +129 -0
  141. solara/server/static/sun.svg +23 -0
  142. solara/server/static/webworker.js +42 -0
  143. solara/server/telemetry.py +212 -0
  144. solara/server/templates/index.html.j2 +1 -0
  145. solara/server/templates/loader-plain.css +11 -0
  146. solara/server/templates/loader-plain.html +20 -0
  147. solara/server/templates/loader-solara.css +111 -0
  148. solara/server/templates/loader-solara.html +40 -0
  149. solara/server/templates/plain.html +82 -0
  150. solara/server/templates/solara.html.j2 +486 -0
  151. solara/server/threaded.py +84 -0
  152. solara/server/utils.py +44 -0
  153. solara/server/websocket.py +45 -0
  154. solara/settings.py +86 -0
  155. solara/tasks.py +893 -0
  156. solara/template/button.py +16 -0
  157. solara/template/markdown.py +42 -0
  158. solara/template/portal/.flake8 +6 -0
  159. solara/template/portal/.pre-commit-config.yaml +28 -0
  160. solara/template/portal/LICENSE +21 -0
  161. solara/template/portal/Procfile +7 -0
  162. solara/template/portal/mypy.ini +3 -0
  163. solara/template/portal/pyproject.toml +26 -0
  164. solara/template/portal/solara_portal/__init__.py +4 -0
  165. solara/template/portal/solara_portal/components/__init__.py +2 -0
  166. solara/template/portal/solara_portal/components/article.py +28 -0
  167. solara/template/portal/solara_portal/components/data.py +28 -0
  168. solara/template/portal/solara_portal/components/header.py +6 -0
  169. solara/template/portal/solara_portal/components/layout.py +6 -0
  170. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
  171. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
  172. solara/template/portal/solara_portal/data.py +60 -0
  173. solara/template/portal/solara_portal/pages/__init__.py +67 -0
  174. solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
  175. solara/template/portal/solara_portal/pages/tabular.py +29 -0
  176. solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
  177. solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
  178. solara/test/__init__.py +0 -0
  179. solara/test/pytest_plugin.py +783 -0
  180. solara/toestand.py +998 -0
  181. solara/util.py +348 -0
  182. solara/validate_hooks.py +258 -0
  183. solara/website/__init__.py +0 -0
  184. solara/website/assets/custom.css +444 -0
  185. solara/website/assets/images/logo-small.png +0 -0
  186. solara/website/assets/images/logo.svg +17 -0
  187. solara/website/assets/images/logo_white.svg +50 -0
  188. solara/website/assets/theme.js +8 -0
  189. solara/website/components/__init__.py +5 -0
  190. solara/website/components/algolia.py +6 -0
  191. solara/website/components/algolia.vue +24 -0
  192. solara/website/components/algolia_api.vue +202 -0
  193. solara/website/components/breadcrumbs.py +28 -0
  194. solara/website/components/contact.py +144 -0
  195. solara/website/components/docs.py +143 -0
  196. solara/website/components/header.py +75 -0
  197. solara/website/components/mailchimp.py +12 -0
  198. solara/website/components/mailchimp.vue +47 -0
  199. solara/website/components/markdown.py +99 -0
  200. solara/website/components/markdown_nav.vue +34 -0
  201. solara/website/components/notebook.py +171 -0
  202. solara/website/components/sidebar.py +105 -0
  203. solara/website/pages/__init__.py +370 -0
  204. solara/website/pages/about/__init__.py +9 -0
  205. solara/website/pages/about/about.md +3 -0
  206. solara/website/pages/apps/__init__.py +16 -0
  207. solara/website/pages/apps/authorization/__init__.py +119 -0
  208. solara/website/pages/apps/authorization/admin.py +12 -0
  209. solara/website/pages/apps/authorization/users.py +12 -0
  210. solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
  211. solara/website/pages/apps/layout-demo.py +40 -0
  212. solara/website/pages/apps/multipage/__init__.py +38 -0
  213. solara/website/pages/apps/multipage/page1.py +26 -0
  214. solara/website/pages/apps/multipage/page2.py +34 -0
  215. solara/website/pages/apps/scatter.py +136 -0
  216. solara/website/pages/apps/scrolling.py +63 -0
  217. solara/website/pages/apps/tutorial-streamlit.py +18 -0
  218. solara/website/pages/careers/__init__.py +27 -0
  219. solara/website/pages/changelog/__init__.py +10 -0
  220. solara/website/pages/changelog/changelog.md +372 -0
  221. solara/website/pages/contact/__init__.py +34 -0
  222. solara/website/pages/doc_use_download.py +85 -0
  223. solara/website/pages/documentation/__init__.py +90 -0
  224. solara/website/pages/documentation/advanced/__init__.py +9 -0
  225. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  226. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
  227. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
  228. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
  229. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +417 -0
  230. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
  231. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +50 -0
  232. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
  233. solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
  234. solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
  235. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +72 -0
  236. solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
  237. solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
  238. solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
  239. solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
  240. solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
  241. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
  242. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
  243. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
  244. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
  245. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
  246. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
  247. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +192 -0
  248. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
  249. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
  250. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +256 -0
  251. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +108 -0
  252. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
  253. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +7 -0
  254. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +187 -0
  255. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  256. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
  257. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
  258. solara/website/pages/documentation/api/__init__.py +19 -0
  259. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  260. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +22 -0
  261. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +20 -0
  262. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +20 -0
  263. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +20 -0
  264. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  265. solara/website/pages/documentation/api/hooks/use_cross_filter.py +23 -0
  266. solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
  267. solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
  268. solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
  269. solara/website/pages/documentation/api/hooks/use_exception.py +31 -0
  270. solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
  271. solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
  272. solara/website/pages/documentation/api/hooks/use_previous.py +30 -0
  273. solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
  274. solara/website/pages/documentation/api/hooks/use_state.py +10 -0
  275. solara/website/pages/documentation/api/hooks/use_state_or_update.py +66 -0
  276. solara/website/pages/documentation/api/hooks/use_thread.md +64 -0
  277. solara/website/pages/documentation/api/hooks/use_thread.py +42 -0
  278. solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
  279. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  280. solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
  281. solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
  282. solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
  283. solara/website/pages/documentation/api/routing/route.py +29 -0
  284. solara/website/pages/documentation/api/routing/use_route.py +76 -0
  285. solara/website/pages/documentation/api/routing/use_router.py +16 -0
  286. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  287. solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
  288. solara/website/pages/documentation/api/utilities/computed.py +16 -0
  289. solara/website/pages/documentation/api/utilities/display.py +16 -0
  290. solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
  291. solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
  292. solara/website/pages/documentation/api/utilities/memoize.py +35 -0
  293. solara/website/pages/documentation/api/utilities/on_kernel_start.py +44 -0
  294. solara/website/pages/documentation/api/utilities/reactive.py +16 -0
  295. solara/website/pages/documentation/api/utilities/widget.py +104 -0
  296. solara/website/pages/documentation/components/__init__.py +12 -0
  297. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  298. solara/website/pages/documentation/components/advanced/link.py +25 -0
  299. solara/website/pages/documentation/components/advanced/meta.py +17 -0
  300. solara/website/pages/documentation/components/advanced/style.py +43 -0
  301. solara/website/pages/documentation/components/common.py +9 -0
  302. solara/website/pages/documentation/components/data/__init__.py +9 -0
  303. solara/website/pages/documentation/components/data/dataframe.py +44 -0
  304. solara/website/pages/documentation/components/data/pivot_table.py +81 -0
  305. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  306. solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
  307. solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
  308. solara/website/pages/documentation/components/input/__init__.py +9 -0
  309. solara/website/pages/documentation/components/input/button.py +23 -0
  310. solara/website/pages/documentation/components/input/checkbox.py +10 -0
  311. solara/website/pages/documentation/components/input/file_browser.py +30 -0
  312. solara/website/pages/documentation/components/input/file_drop.py +76 -0
  313. solara/website/pages/documentation/components/input/input.py +43 -0
  314. solara/website/pages/documentation/components/input/select.py +22 -0
  315. solara/website/pages/documentation/components/input/slider.py +29 -0
  316. solara/website/pages/documentation/components/input/switch.py +10 -0
  317. solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
  318. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  319. solara/website/pages/documentation/components/lab/chat.py +109 -0
  320. solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
  321. solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
  322. solara/website/pages/documentation/components/lab/input_date.py +20 -0
  323. solara/website/pages/documentation/components/lab/input_time.py +15 -0
  324. solara/website/pages/documentation/components/lab/menu.py +22 -0
  325. solara/website/pages/documentation/components/lab/tab.py +25 -0
  326. solara/website/pages/documentation/components/lab/tabs.py +45 -0
  327. solara/website/pages/documentation/components/lab/task.py +11 -0
  328. solara/website/pages/documentation/components/lab/theming.py +74 -0
  329. solara/website/pages/documentation/components/lab/use_task.py +11 -0
  330. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  331. solara/website/pages/documentation/components/layout/app_bar.py +16 -0
  332. solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
  333. solara/website/pages/documentation/components/layout/app_layout.py +24 -0
  334. solara/website/pages/documentation/components/layout/card.py +15 -0
  335. solara/website/pages/documentation/components/layout/card_actions.py +16 -0
  336. solara/website/pages/documentation/components/layout/column.py +30 -0
  337. solara/website/pages/documentation/components/layout/columns.py +27 -0
  338. solara/website/pages/documentation/components/layout/columns_responsive.py +66 -0
  339. solara/website/pages/documentation/components/layout/details.py +13 -0
  340. solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
  341. solara/website/pages/documentation/components/layout/gridfixed.py +19 -0
  342. solara/website/pages/documentation/components/layout/hbox.py +18 -0
  343. solara/website/pages/documentation/components/layout/row.py +30 -0
  344. solara/website/pages/documentation/components/layout/sidebar.py +24 -0
  345. solara/website/pages/documentation/components/layout/vbox.py +19 -0
  346. solara/website/pages/documentation/components/output/__init__.py +9 -0
  347. solara/website/pages/documentation/components/output/file_download.py +11 -0
  348. solara/website/pages/documentation/components/output/html.py +19 -0
  349. solara/website/pages/documentation/components/output/image.py +11 -0
  350. solara/website/pages/documentation/components/output/markdown.py +57 -0
  351. solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
  352. solara/website/pages/documentation/components/output/sql_code.py +83 -0
  353. solara/website/pages/documentation/components/output/tooltip.py +11 -0
  354. solara/website/pages/documentation/components/page/__init__.py +9 -0
  355. solara/website/pages/documentation/components/page/head.py +15 -0
  356. solara/website/pages/documentation/components/page/title.py +25 -0
  357. solara/website/pages/documentation/components/status/__init__.py +9 -0
  358. solara/website/pages/documentation/components/status/error.py +39 -0
  359. solara/website/pages/documentation/components/status/info.py +39 -0
  360. solara/website/pages/documentation/components/status/progress.py +10 -0
  361. solara/website/pages/documentation/components/status/spinner.py +11 -0
  362. solara/website/pages/documentation/components/status/success.py +40 -0
  363. solara/website/pages/documentation/components/status/warning.py +47 -0
  364. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  365. solara/website/pages/documentation/components/viz/altair.py +42 -0
  366. solara/website/pages/documentation/components/viz/echarts.py +77 -0
  367. solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
  368. solara/website/pages/documentation/components/viz/plotly.py +63 -0
  369. solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
  370. solara/website/pages/documentation/examples/__init__.py +54 -0
  371. solara/website/pages/documentation/examples/ai/__init__.py +11 -0
  372. solara/website/pages/documentation/examples/ai/chatbot.py +113 -0
  373. solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
  374. solara/website/pages/documentation/examples/basics/__init__.py +10 -0
  375. solara/website/pages/documentation/examples/basics/sine.py +28 -0
  376. solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
  377. solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
  378. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
  379. solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
  380. solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
  381. solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
  382. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
  383. solara/website/pages/documentation/examples/general/__init__.py +10 -0
  384. solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
  385. solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
  386. solara/website/pages/documentation/examples/general/live_update.py +32 -0
  387. solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
  388. solara/website/pages/documentation/examples/general/mycard.vue +58 -0
  389. solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
  390. solara/website/pages/documentation/examples/general/vue_component.py +50 -0
  391. solara/website/pages/documentation/examples/ipycanvas.py +49 -0
  392. solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
  393. solara/website/pages/documentation/examples/libraries/altair.py +65 -0
  394. solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
  395. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
  396. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
  397. solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
  398. solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
  399. solara/website/pages/documentation/examples/utilities/countdown_timer.py +62 -0
  400. solara/website/pages/documentation/examples/utilities/todo.py +196 -0
  401. solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
  402. solara/website/pages/documentation/examples/visualization/annotator.py +67 -0
  403. solara/website/pages/documentation/examples/visualization/linked_views.py +81 -0
  404. solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
  405. solara/website/pages/documentation/faq/__init__.py +12 -0
  406. solara/website/pages/documentation/faq/content/99-faq.md +112 -0
  407. solara/website/pages/documentation/getting_started/__init__.py +9 -0
  408. solara/website/pages/documentation/getting_started/content/00-quickstart.md +107 -0
  409. solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
  410. solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
  411. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
  412. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
  413. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
  414. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
  415. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
  416. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
  417. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +65 -0
  418. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  419. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
  420. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1021 -0
  421. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
  422. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +228 -0
  423. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +278 -0
  424. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
  425. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +305 -0
  426. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
  427. solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
  428. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
  429. solara/website/pages/docutils.py +38 -0
  430. solara/website/pages/home.vue +1199 -0
  431. solara/website/pages/our_team/__init__.py +83 -0
  432. solara/website/pages/pricing/__init__.py +31 -0
  433. solara/website/pages/roadmap/__init__.py +11 -0
  434. solara/website/pages/roadmap/roadmap.md +47 -0
  435. solara/website/pages/scale_ipywidgets.py +45 -0
  436. solara/website/pages/showcase/__init__.py +105 -0
  437. solara/website/pages/showcase/domino_code_assist.py +60 -0
  438. solara/website/pages/showcase/planeto_tessa.py +19 -0
  439. solara/website/pages/showcase/solara_dev.py +54 -0
  440. solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
  441. solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
  442. solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
  443. solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
  444. solara/website/pages/showcase/wanderlust.py +27 -0
  445. solara/website/public/beach.jpeg +0 -0
  446. solara/website/public/logo.svg +6 -0
  447. solara/website/public/social/discord.svg +1 -0
  448. solara/website/public/social/github.svg +1 -0
  449. solara/website/public/social/twitter.svg +3 -0
  450. solara/website/public/success.html +25 -0
  451. solara/website/templates/index.html.j2 +117 -0
  452. solara/website/utils.py +51 -0
  453. solara/widgets/__init__.py +1 -0
  454. solara/widgets/vue/gridlayout.vue +107 -0
  455. solara/widgets/vue/html.vue +4 -0
  456. solara/widgets/vue/navigator.vue +134 -0
  457. solara/widgets/vue/vegalite.vue +130 -0
  458. solara/widgets/widgets.py +74 -0
  459. solara_ui-1.45.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  460. solara_ui-1.45.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  461. solara_ui-1.45.0.dist-info/METADATA +162 -0
  462. solara_ui-1.45.0.dist-info/RECORD +464 -0
  463. solara_ui-1.45.0.dist-info/WHEEL +4 -0
  464. solara_ui-1.45.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,417 @@
1
+ ---
2
+ title: Testing your Solara application, both front and back end
3
+ description: Using solara you can test both the front and back end functionalities of your application.
4
+ ---
5
+
6
+ # Testing with Solara
7
+
8
+ When possible, we recommend to test your application without a browser. This is faster and more reliable than testing with a browser. Testing via a browser is more difficult to get right due to having to deal with two processes that communicate
9
+ asynchronously (the Python process and the browser process).
10
+
11
+ Only when you develop new components that rely on new frontend code or CSS do we recommend considering using a browser to test your component or application.
12
+
13
+ ## Testing without a Browser
14
+
15
+ When testing a component or application without a browser, we recommend to use vanilla [pytest](https://docs.pytest.org/) to test the application logic.
16
+
17
+ To get inspiration for writing tests that cover component logic and their interactions with existing components, refer to the [tests in the Solara repository](https://github.com/widgetti/solara/tree/master/tests).
18
+
19
+ The following example demonstrates how to test a simple Solara component using pytest:
20
+
21
+ ```python
22
+ import solara
23
+ import ipyvuetify as v
24
+
25
+
26
+ def test_docs_no_browser_simple():
27
+ clicks = solara.reactive(0)
28
+
29
+ @solara.component
30
+ def ClickButton():
31
+ def increment():
32
+ clicks.value += 1
33
+
34
+ solara.Button(label=f"Clicked: {clicks}", on_click=increment)
35
+
36
+ # rc is short for render context
37
+ box, rc = solara.render(ClickButton(), handle_error=False)
38
+ button = box.children[0]
39
+ assert isinstance(button, v.Btn)
40
+ assert button.children[0] == "Clicked: 0"
41
+ # trigger the click event handler without a browser
42
+ button.click()
43
+ assert clicks.value == 1
44
+ assert button.children[0] == "Clicked: 1"
45
+ ```
46
+
47
+ Here we let Solara render the component into a set of widgets without a frontend (browser) connected.
48
+ We check the resulting ipywidgets and its properties using `asserts`, as is standard with pytest.
49
+ We also show how to trigger the click handler from the Python side using [`ipyvue`'s](https://github.com/widgetti/ipyvue) `.click()` method
50
+ on the widget, again without requiring a browser.
51
+
52
+ Run this test with pytest as follows:
53
+
54
+ ```bash
55
+ pytest tests/unit/test_docs_no_browser_simple.py
56
+ ```
57
+
58
+
59
+ ### Finding a widget in the widget tree
60
+
61
+ When widgets are embedded in a larger widget tree, it becomes cumbersome to find the widget you are looking for using `.children[0].children[1]...` etc. For this use case we can use the `rc.find` method to look for a particular widget. This API is inspired on the playwright API, and is a convenient way to find a widget in the widget tree.
62
+
63
+ ```python
64
+ import solara
65
+ import ipyvuetify as v
66
+
67
+
68
+ def test_docs_no_browser_api_find():
69
+ clicks = solara.reactive(0)
70
+
71
+ @solara.component
72
+ def ClickButton():
73
+ def increment():
74
+ clicks.value += 1
75
+
76
+ with solara.Card("Button in a card"):
77
+ with solara.Column().meta(ref="my_column"):
78
+ solara.Button(label=f"Clicked: {clicks}", on_click=increment)
79
+ with solara.Column():
80
+ solara.Button(label="Not the button we need")
81
+
82
+ # rc is short for render context
83
+ box, rc = solara.render(ClickButton(), handle_error=False)
84
+ # this find will make the .widget fail, because it matches two buttons
85
+ # finder = rc.find(v.Btn)
86
+ # We can refine our search by adding constraints to attributes of the widget
87
+ button_locator = rc.find(v.Btn, children=["Clicked: 0"])
88
+ # basics asserts are supported, like assert_single(), assert_empty(), assert_not_empty()
89
+ button_locator.assert_single()
90
+ button = button_locator.widget
91
+ # .find calls can also be nested, and can use the meta_ref to find the right widget
92
+ # finder = rc.find(meta_ref="my_column").find(v.Btn)
93
+ button.click()
94
+ assert clicks.value == 1
95
+ rc.find(v.Btn, children=["Clicked: 1"]).assert_single()
96
+ ```
97
+
98
+ By including keywords arguments to the `find` method, we can get more specific about the widget we are looking for.
99
+ In the above example, a simple `.find(v.Btn)` would find two buttons, while `.find(v.Btn, children=["Clicked: 0"])` will find the button we are looking for. *(Note that this does require knowing about the internal implementation
100
+ of the Button component: i.e. `solara.Button` creates a `v.Btn`, and the label argument causes the button having `children=["Clicked 0"]`)*.
101
+
102
+
103
+ Because sometimes it is difficult to find a specific widget, we made is possible to attach meta data to a widget and
104
+ use that to find widgets. Together with nesting (i.e. `.find(...).find(...)`) calls, this makes it easier to find the widget you are looking for in
105
+ larger applications. In the above example we could have replaced the `.find(v.Btn, children=["Clicked: 0"])` with
106
+ `.find(meta_ref="my_column").find(v.Btn)` to find the button we are looking for.
107
+
108
+ Especially in larger application, adding meta data to widgets makes it much easier to find the widget you are looking for, as well
109
+ as correlate the testing code back to the application code. Having unique meta_refs makes searching through your codebase and in your tests much easier.
110
+
111
+ ### Asynchronous updating of the UI
112
+
113
+ When a [`solara.lab.task`](https://solara.dev/api/task) is executed, a new thread will spawn, which will likely update the UI somewhere in the future. We can wait for the UI to update using the `wait_for` method on the finder object. This method will poll the widget tree, waiting for the widget to appear. If the timeout is reached, the test will fail.
114
+
115
+ ```python
116
+ import solara
117
+ import solara.lab
118
+ import ipyvuetify as v
119
+ import time
120
+
121
+
122
+ def test_docs_no_browser_api_thread():
123
+ clicks = solara.reactive(0)
124
+
125
+ @solara.component
126
+ def ClickButton():
127
+ @solara.lab.task
128
+ def increment():
129
+ # now we will wait for 0.3 seconds before updating the UI
130
+ time.sleep(0.3)
131
+ clicks.value += 1
132
+
133
+ with solara.Card("Button in a card"):
134
+ with solara.Column():
135
+ solara.Button(label=f"Clicked: {clicks}", on_click=increment)
136
+
137
+ # rc is short for render context
138
+ box, rc = solara.render(ClickButton(), handle_error=False)
139
+ finder = rc.find(v.Btn)
140
+ button = finder.widget
141
+ finder.assert_single()
142
+ finder.assert_not_empty()
143
+ assert button.children[0] == "Clicked: 0"
144
+
145
+ # clicking will now start a thread, so we have to wait/poll for the UI to update
146
+ button.click()
147
+
148
+ button_after_delayed_click = rc.find(v.Btn, children=["Clicked: 1"])
149
+ button_after_delayed_click.wait_for(timeout=2.5)
150
+ ```
151
+
152
+ ## Testing with a Browser
153
+
154
+ As mentioned in the introduction, when you develop new components that need frontend code or CSS, we recommend considering using a browser to test your component or application. Although these tests are slower to run and more
155
+ difficult to get right, they may be crucial to ensure the correct rendering of your components or application.
156
+
157
+
158
+ ### Installation
159
+
160
+ We recommend using the `pytest-ipywidgets` pytest plugin together with [Playwright for Python](https://playwright.dev/python/) to test your widgets, components or applications using a browser, for both unit as well as integration tests.
161
+
162
+ Unit tests often test a single component, while integration (or smoke tests) usually tests your whole application, or a large part of it.
163
+
164
+ To install `pytest-ipywidgets` and Playwright for Python, run the following commands:
165
+ ```
166
+ $ pip install "pytest-ipywidgets[solara]" # or "pytest-ipywidgets[all]" if you also want to test with Jupyter Lab, Jupyter Notebook and Voila.
167
+ $ playwright install chromium
168
+ ```
169
+
170
+ ### Testing widgets using Solara server
171
+
172
+ The most convenient way to test a widget, is by including the `solara_test` fixture in your test function arguments. Here's an example:
173
+
174
+ ```python
175
+ import ipywidgets as widgets
176
+ import playwright.sync_api
177
+ from IPython.display import display
178
+
179
+ def test_widget_button_solara(solara_test, page_session: playwright.sync_api.Page):
180
+ # The test code runs in the same process as solara-server (which runs in a separate thread)
181
+ # Note: this test uses ipywidgets directly, not solara components.
182
+ button = widgets.Button(description="Click Me!")
183
+
184
+ def change_description(obj):
185
+ button.description = "Tested event"
186
+
187
+ button.on_click(change_description)
188
+ display(button)
189
+ button_sel = page_session.locator("text=Click Me!")
190
+ button_sel.wait_for()
191
+ button_sel.click()
192
+ page_session.locator("text=Tested event").wait_for()
193
+ ```
194
+ When this fixture is used, we can use the standard IPython display call to add your widget to the page. Using the `page_session` fixture, we can interact with the widget in the browser,
195
+ in this case we trigger a button click in the browser and check if the button description changes to "Tested event".
196
+
197
+ Run this test with pytest as follows:
198
+
199
+ ```bash
200
+ pytest tests/ui/test_widget_button.py --headed # remove --headed to run headless
201
+ ```
202
+
203
+
204
+ ### Testing state changes on the Python side with polling
205
+
206
+ In the above example, an event in the frontend led to a state change on the Python side which is reflected in
207
+ the frontend, so we could use Playwright to test if our event handler was executed correctly.
208
+
209
+ However, sometimes we want to test if a state changed on the Python side that has no
210
+ direct effect on the frontend. A possible example is is a successful database write, or an update to a
211
+ Python variable.
212
+
213
+ The following example uses a polling technique to check if a state change happened on the Python side.
214
+
215
+ ```python
216
+ import ipywidgets as widgets
217
+ import playwright.sync_api
218
+ from IPython.display import display
219
+ from typing import Callable
220
+ import time
221
+
222
+
223
+ def assert_equals_poll(getter: Callable, expected, timeout=2, iteration_delay=0.01):
224
+ start = time.time()
225
+ while time.time() - start < timeout:
226
+ if getter() == expected:
227
+ return
228
+ time.sleep(iteration_delay)
229
+ assert getter() == expected
230
+ return False
231
+
232
+
233
+ def test_event_with_polling(solara_test, page_session: playwright.sync_api.Page):
234
+ button = widgets.Button(description="Append data")
235
+ # some data that will change due to a button click
236
+ click_data = []
237
+
238
+ def on_click(button):
239
+ # change the data when the button is clicked
240
+ # this will be called from the thread the websocket is in
241
+ # so we can block/poll from the main thread (that pytest is running in)
242
+ click_data.append(42)
243
+
244
+ button.on_click(on_click)
245
+ display(button)
246
+ button_sel = page_session.locator("text=Append data")
247
+ button_sel.click()
248
+
249
+ # we block/poll until the condition is met.
250
+ assert_equals_poll(lambda: click_data, [42])
251
+ ```
252
+
253
+ ### Testing state changes on the Python side with a Future
254
+
255
+ Sometimes, state changes on the Python side emit an event that we can capture. In this case,
256
+ we can use a `concurrent.futures.Future` to block until the state change happens. This is a more
257
+ efficient way to wait for a state change than polling.
258
+
259
+ ```python
260
+ import ipywidgets as widgets
261
+ from concurrent.futures import Future
262
+ import playwright.sync_api
263
+ from IPython.display import display
264
+
265
+
266
+ def future_trait_change(widget, attribute):
267
+ """Returns a future that will be set when the trait changes."""
268
+ future = Future() # type: ignore
269
+
270
+ def on_change(change):
271
+ # set_result will cause the .result() call below to resume
272
+ future.set_result(change["new"])
273
+ widget.unobserve(on_change, attribute)
274
+
275
+ widget.observe(on_change, attribute)
276
+ return future
277
+
278
+
279
+ def test_event_with_polling(solara_test, page_session: playwright.sync_api.Page):
280
+ button = widgets.Button(description="Reset slider")
281
+ slider = widgets.IntSlider(value=42)
282
+
283
+ def on_click(button):
284
+ # change the slider value trait when the button is clicked
285
+ # this will be called from the thread the websocket from solara-server
286
+ # is running in, so we can block from the main thread (that pytest is running in)
287
+ slider.value = 0
288
+
289
+ button.on_click(on_click)
290
+ display(button)
291
+ # we could display the slider, but it's not necessary for this test
292
+ # since we are only testing if the value changes on the Python side
293
+ # display(slider)
294
+ button_sel = page_session.locator("text=Reset slider")
295
+
296
+ # create the future with the attached observer *before* clicking the button
297
+ slider_value = future_trait_change(slider, "value")
298
+ # trigger the click event handler via the frontend, this makes sure that
299
+ # the event handler (on_click) gets executed in a separate thread
300
+ # (the one that the websocket from solara-server is running in)
301
+ button_sel.click()
302
+
303
+ # .result() blocks until the value changes or the timeout condition is met.
304
+ # If no value is set, the test will fail due to a TimeoutError
305
+ assert slider_value.result(timeout=2) == 0
306
+ ```
307
+
308
+
309
+ ### Testing in Voila, Jupyter Lab, Jupyter Notebook, and Solara
310
+
311
+ In case you want to test your component in the multiple Jupyter environments (e.g., Jupyter Notebook, Jupyter Lab, Voila, and Solara) to ensure it renders correctly, use the `ipywidgets_runner` fixture to run code snippets. Here's an example:
312
+
313
+ ```python
314
+ import ipywidgets as widgets
315
+ import playwright.sync_api
316
+ from IPython.display import display
317
+
318
+
319
+ def test_solara_button_all(ipywidgets_runner, page_session: playwright.sync_api.Page, assert_solara_snapshot):
320
+ # this function (or rather its lines) will be executed in the kernel
321
+ # voila, lab, classic notebook and solara will all execute it
322
+ def kernel_code():
323
+ import solara
324
+
325
+ @solara.component
326
+ def Button():
327
+ text, set_text = solara.use_state("Click Me!")
328
+
329
+ def on_click():
330
+ set_text("Tested event")
331
+
332
+ solara.Button(text, on_click=on_click)
333
+
334
+ display(Button())
335
+
336
+ ipywidgets_runner(kernel_code)
337
+ button_sel = page_session.locator("button >> text=Click Me!")
338
+ assert_solara_snapshot(button_sel.screenshot())
339
+ button_sel.wait_for()
340
+ button_sel.click()
341
+ page_session.locator("button >> text=Tested event").wait_for()
342
+ page_session.wait_for_timeout(1000)
343
+ ```
344
+
345
+ Note that the function in the code will be executed in a different process (a Jupyter kernel), which will make it harder to debug and slower to run.
346
+ Because the function code executes in the kernel, you do not have access to local variables. However, by passing a dictionary as second argument
347
+ to `ipywidgets_runner` we can pass in extra local variables (e.g. `ipywidgets_runner(kernel_code, {"extra_argument": extra_argument})`).
348
+
349
+ These tests run slow, and are generally only recommended for ipywidgets authors that want to test if their library works in all Jupyter environments. We use these kinds of tests in libraries such as [ipyvue](https://github.com/widgetti/ipyvue), [ipyvuetify](https://github.com/widgetti/ipyvuetify), [ipyaggrid](https://github.com/widgetti/ipyaggrid), but should in general not be needed for most applications.
350
+
351
+
352
+ ### Limiting the Jupyter Environments
353
+ To limit the ipywidgets_runner fixture to only run in a specific environment, use the `SOLARA_TEST_RUNNERS` environment variable:
354
+
355
+ * `SOLARA_TEST_RUNNERS=solara pytest tests/ui`
356
+ * `SOLARA_TEST_RUNNERS=voila pytest tests/ui`
357
+ * `SOLARA_TEST_RUNNERS=jupyter_lab pytest tests/ui`
358
+ * `SOLARA_TEST_RUNNERS=jupyter_notebook pytest tests/ui`
359
+ * `SOLARA_TEST_RUNNERS=solara,voila pytest tests/ui`
360
+
361
+
362
+
363
+ ### Organizing Tests and Managing Snapshots
364
+ We recommend organizing your visual tests in a separate directory, such as `tests/ui`. This allows you to run fast tests (`test/unit`) separately from slow tests (`test/ui`). Use the `solara_snapshots_directory` fixture to change the default directory for storing snapshots, which is `tests/ui/snapshots` by default.
365
+
366
+ ```bash
367
+ $ pytest tests/unit # run fast test
368
+ $ pytest tests/ui # run slow test
369
+ $ pytest tests # run all tests
370
+ ```
371
+
372
+ To compare a captured image from a part of your page with the reference image, use the `assert_solara_snapshot` fixture. For example, `assert_solara_snapshot(button_sel.screenshot())` will take a screenshot of the button and compare it to the reference image. If the images are different, the test will fail.
373
+
374
+ For local development, you can use the --solara-update-snapshots flag to update the reference images. This will overwrite the existing reference images with the new ones generated during the test run. However, you should carefully review the changes before committing them to your repository to ensure the updates are accurate and expected.
375
+
376
+
377
+ ### Continuous Integration Recommendations
378
+
379
+ When a test fails, the output will be placed in a directory structure similar to what would be put in the `solara_snapshots_directory` directory but under the test-results directory in the root of your project (unless changed by passing `--output=someotherdirectory` to pytest).
380
+
381
+ In CI, we recommend downloading this directory using, for example, GitHub Actions:
382
+
383
+ ```yaml
384
+ - name: Download test results
385
+ uses: actions/download-artifact@v2
386
+ with:
387
+ name: myproject-test-results
388
+ path: test-results
389
+ ```
390
+
391
+
392
+ After inspecting and approving the screenshots, you can copy them to the `solara_snapshots_directory` directory and commit them to your repository. This way, you ensure that the reference images are up-to-date and accurate for future tests.
393
+
394
+
395
+ ### Note about the Playwright
396
+
397
+ Visual testing with solara is based on [Playwright for Python](https://playwright.dev/python/), which provides a `page` fixture. However, this fixture will make a new page for each test, which is not what we want. Therefore, we provide a `page_session` fixture that will reuse the same page for all tests. This is important because it will make the tests faster.
398
+
399
+ By following these recommendations and guidelines, you can efficiently test your Solara applications and ensure a smooth developer experience.
400
+
401
+ ### Configuration
402
+
403
+ #### Changing the Hostname
404
+
405
+ To configure the hostname the socket is bound to when starting the test server, use the `HOST` or `SOLARA_HOST` environment variable (e.g. `SOLARA_HOST=0.0.0.0`). This hostname is also used for the jupyter server and voila. Alternatively the `--solara-host` argument can be passed on the command line for pytest.
406
+
407
+ #### Changing the Port
408
+
409
+ To configure the ports the socket is bound to when starting the test servers, use the `PORT` environment variable (e.g. `PORT=18865`). This port and subsequent port will be used for solara-server, jupyter-server and voila. Alternatively the `--solara-port` argument can be passed on the command line for pytest for the solara server, and `--jupyter-port` and `--voila-port` for the ports of jupyter server and voila respectively.
410
+
411
+ #### Vuetify warmup
412
+
413
+ By default, we insert an ipyvuetify widget with an icon into the frontend to force loading all the vuetify assets, such as CSS and fonts. However, if you are using the solara test plugin to test pure ipywidgets or a 3rd ipywidget based party library you might not need this. Disable this vuetify warmup phase by passing the `--no-solara-vuetify-warmup` argument to pytest, or setting the environment variable `SOLARA_TEST_VUETIFY_WARMUP` to a falsey value (e.g. `SOLARA_TEST_VUETIFY_WARMUP=0`).
414
+
415
+ #### Changing the application wait timeout
416
+
417
+ By default, we wait for 10 seconds for the browser to connect to the server when the solara server is used for testing. On slower systems, this may be too short. To change this timeout, set the `PYTEST_IPYWIDGETS_SOLARA_APP_WAIT_TIMEOUT` environment variable to the desired value in seconds (e.g. `PYTEST_IPYWIDGETS_SOLARA_APP_WAIT_TIMEOUT=20`).
@@ -0,0 +1,69 @@
1
+ ---
2
+ title: Debugging Solara applications
3
+ description: You can use the Python debugger to debug your Solara app.
4
+ ---
5
+ # Debugging
6
+
7
+ ## PDB
8
+
9
+ You can use the [python debugger](https://docs.python.org/3/library/pdb.html) to debug your Solara app.
10
+
11
+ Simply add `breakpoint()` to your code, and trigger the code, and you will enter the debugger.
12
+
13
+ ```python
14
+ import solara
15
+
16
+ clicks = solara.reactive(0)
17
+
18
+
19
+ @solara.component
20
+ def Page():
21
+ color = "green"
22
+ if clicks.value >= 5:
23
+ color = "red"
24
+
25
+ def increment():
26
+ clicks.value += 1
27
+ # this will trigger the debugger
28
+ breakpoint()
29
+ print("clicks", clicks) # noqa
30
+
31
+ solara.Button(label=f"Clicked: {clicks}", on_click=increment, color=color)
32
+ ```
33
+
34
+ ## PyCharm or IntelliJ
35
+
36
+ You can also use the debugger of PyCharm or IntelliJ to debug your Solara app.
37
+ The following settings works for PyCharm or IntelliJ:
38
+
39
+ ![](https://dxhl76zpt6fap.cloudfront.net/public/docs/howto/debugger-intellij.webp)
40
+
41
+ ## VSCode
42
+
43
+
44
+ In VSCode, you can use the following launch.json to debug your Solara app:
45
+
46
+ ```json
47
+ {
48
+ // Use IntelliSense to learn about possible attributes.
49
+ // Hover to view descriptions of existing attributes.
50
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
51
+ "version": "0.2.0",
52
+ "configurations": [
53
+ {
54
+ "name": "Solara: Launch",
55
+ "type": "python",
56
+ "request": "launch",
57
+ "program": "/Users/maartenbreddels/miniconda3/envs/dev/bin/solara",
58
+ "args": [
59
+ "run",
60
+ "${file}"
61
+ ],
62
+ "console": "integratedTerminal",
63
+ "justMyCode": true,
64
+ }
65
+ ]
66
+ }
67
+ ```
68
+
69
+ Now keep your script tab open, and press F5 to start debugging (or click the play icon in the UI).
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Embedding Solara applications into existing websites
3
+ description: Solara can be embedded into existing websites. Although it is technically possible to embed a Solara app into an existing webpage,
4
+ we currently support embedding primarily via iframes.
5
+ ---
6
+
7
+ # Embedding in existing websites
8
+
9
+ Solara can be embedded into existing websites. Although it is technically possible to embed a Solara app into an existing webpage, we currently support embedding primarily via iframes.
10
+
11
+
12
+ ## Embed via iframe
13
+
14
+ Here we demonstrate how to embed Solara into an existing webpage via an iframe. Let's start by creating a simple HTML page (here we choose the filename embed.html):
15
+
16
+ ```html
17
+ <html>
18
+ <body>
19
+ <h1>This is on the main page</h1>
20
+ <iframe src="http://localhost:8765" width="100%" height="100%"></iframe>
21
+ </body>
22
+ </html>
23
+ ```
24
+
25
+ Now, start an http server (in this example we use the standard Python http server):
26
+ ```bash
27
+ $ python -m http.server
28
+ Serving HTTP on :: port 8000 (http://[::]:8000/) ...
29
+ ```
30
+
31
+ Additionally, start the Solara server:
32
+
33
+ ```bash
34
+ $ solara run my-solara-app.py
35
+ Solara server is starting at http://localhost:8765
36
+ ```
37
+
38
+ Ensure the port number matches that of the iframe in `embed.html`. Now open `http://localhost:8000/embed.html` in your browser, and you should see the Solara app embedded in the page.
39
+
40
+ If you do not see your app, you can open the browser developer tools in your browser and look for errors in the console. If you use the Brave browser, you might want to disable the Brave shields for your local server.
41
+
42
+ ### Security considerations
43
+
44
+ Solara uses a cookie to implement sessions. To support setting cookies in an iframe, we set the session cookie using `Secure`, and `SameSite=Strict`. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) for more details. This means that we can only support iframes via https or localhost. Note that proxy servers can tell
45
+ solara-server that the connection is secure by forwarding the `X-Forwarded-Proto` header, see [our self hosted deployment documentation for more information](https://solara.dev/documentation/getting_started/deploying/self-hosted).
46
+
47
+
48
+ ## Embed into an existing page
49
+
50
+ If embedding into an iframe does not suit your needs (for example, dialogs not being fullscreen), [please contact us](/contact) and we can discuss other options.
@@ -0,0 +1,124 @@
1
+ ---
2
+ title: Using various ipywidgets libraries within a Solara application
3
+ description: Solara can work with virtually any ipywidget library, and enables powerful interactivity with libraries like ipyleaflet, ipydatagrid, and bqplot.
4
+ ---
5
+ # How can I use ipywidget library X?
6
+
7
+ Solara can work with any ipywidget library, such as [ipyleaflet](https://github.com/jupyter-widgets/ipyleaflet), [ipydatagrid](https://github.com/bloomberg/ipydatagrid) or [bqplot](https://github.com/bqplot/bqplot).
8
+
9
+ After `solara` is imported, every widget class has an extra `.element(...)` method added to itself. This allows us to create elements for all existing widgets. For example using regular ipywidgets:
10
+
11
+ ```python
12
+ import ipywidgets
13
+ button_element = ipywidgets.Button.element(description="Click me")
14
+ ```
15
+
16
+ ## Example with ipyleaflet
17
+
18
+ For instance, if we want to use ipyleaflet using the classical ipywidget API, we can do:
19
+
20
+ ```python
21
+ import ipyleaflet
22
+
23
+ map = ipyleaflet.Map(center=(52, 10), zoom=8)
24
+
25
+ marker = Marker(location=(52.1, 10.1), draggable=True)
26
+ m.add_layer(marker)
27
+ ```
28
+
29
+ In Solara, we should not create widgets, but elements instead. We can create elements using the `.element(...)` method. This method takes the same arguments as the widget constructor, but returns an element instead of a widget. The element can be used in the same way as a widget, but it is not a widget. It is a special object that can be used in Solara.
30
+
31
+ However, how do we add the marker to the map? The map element object does not have an `add_layer` method. That is the downside of using the React-like API of Solara. We cannot call methods on the widget
32
+ anymore. Instead, we need to pass the marker to the layers argument. That, however, introduces a new problem. Ipyleaflet by default adds a layer to the map when it is created, and the `add_layer` adds the second layer. We now need to manually add the map layer ourselves.
33
+
34
+ Putting this together.
35
+ ```solara
36
+ import ipyleaflet
37
+ import solara
38
+
39
+ url = ipyleaflet.basemaps.OpenStreetMap.Mapnik["url"]
40
+
41
+ @solara.component
42
+ def Page():
43
+ marker = ipyleaflet.Marker.element(location=(52.1, 10.1), draggable=True)
44
+ map = ipyleaflet.Map.element(
45
+ center=(52, 10),
46
+ zoom=8,
47
+ layers=[
48
+ ipyleaflet.TileLayer.element(url=url),
49
+ marker,
50
+ ],
51
+ )
52
+ ```
53
+
54
+ Note that this is about the worst example of something that looks easy in ipyleaflet using the classical API becoming a bit more involved in Solara.
55
+ In practice, this does not happen often, and your code in general will be shorter and more readable.
56
+
57
+ Another thing of note is that ipyleaflet uses CSS `z-index` to layer content, potentially causing issues with your map overlaying other content. This can be avoided by styling the parent element of the map with `isolation: isolate;`. For examples of how to do this, you can see the below examples.
58
+
59
+ See also [the basic ipyleaflet example](/examples/libraries/ipyleaflet) and [the advanced ipyleaflet example](/examples/libraries/ipyleaflet_advanced).
60
+
61
+ ## Example with ipywidgets
62
+
63
+ Most widgets in (classic) ipywidgets can be used without problems in Solara. Two widgets stand out that are difficult to use.
64
+
65
+ ### Image
66
+
67
+ The `Image` widget can be used normally, but we cannot use the factory methods like `Image.from_file` and `Image.from_url`, for this reason we create the [Image](/api/image) component that
68
+ makes this easier.
69
+
70
+ ### Video
71
+
72
+ The `Video` widget does not have a corresponding component in solara (yet), but we can manually fill in the `value`. For example:
73
+
74
+ ```solara
75
+ import solara
76
+ import ipywidgets
77
+
78
+ url = 'https://user-images.githubusercontent.com/1765949/240697327-25b296bd-72c6-4412-948b-2d37e8196260.mp4'
79
+
80
+
81
+ @solara.component
82
+ def Page():
83
+ ipywidgets.Video.element(value=url.encode('utf8'),
84
+ format='url',
85
+ width=500
86
+ )
87
+
88
+ ```
89
+
90
+ ## Wrapper libraries
91
+
92
+ However, because we care about type safety, we generate wrapper components for some libraries. This enables type completion in VSCode, type checks with VSCode, and mypy.
93
+
94
+ The following libraries are fully wrapped:
95
+
96
+ * `ipywidgets` wrapper: `reacton.ipywidgets`
97
+ * `ipyvuetify` wrapper: `reacton.ipyvuetify`
98
+ * `bqplot` wrapper: `reacton.bqplot`
99
+ * `ipycanvas` wrapper: `reacton.ipycanvas`
100
+
101
+ This allows us to do instead:
102
+ ```python
103
+ import reacton.ipywidgets as w
104
+ button_element = w.Button(description="Click me)
105
+ ```
106
+
107
+ And enjoy auto complete and type checking.
108
+
109
+ ## Create your own wrapper
110
+
111
+ The best example would be to take a look at the source code for now:
112
+
113
+ * [ipywidgets](https://github.com/widgetti/reacton/blob/master/reacton/ipywidgets.py)
114
+ * [bqplot](https://github.com/widgetti/reacton/blob/master/reacton/bqplot.py)
115
+ * [ipyvuetify](https://github.com/widgetti/reacton/blob/master/reacton/ipyvuetify.py)
116
+
117
+ The code is generated by executing:
118
+
119
+ $ python -m reacton.ipywidgets
120
+
121
+
122
+ ## Limitation
123
+
124
+ Reacton assumes the widget constructor arguments match the traits. If this is not the case, this may result in runtime errors. If this leads to issues, please open an [Issue](https://github.com/widgetti/solara/issues/new) to discuss this.
@@ -0,0 +1,3 @@
1
+ # Reference documentation
2
+
3
+ Our reference documentation informs you about how certain parts in Solara work.