solara-ui 1.31.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara/__init__.py +124 -0
- solara/__main__.py +734 -0
- solara/alias.py +6 -0
- solara/autorouting.py +546 -0
- solara/cache.py +303 -0
- solara/checks.html +71 -0
- solara/checks.py +224 -0
- solara/comm.py +28 -0
- solara/components/__init__.py +59 -0
- solara/components/alert.py +155 -0
- solara/components/applayout.py +393 -0
- solara/components/button.py +85 -0
- solara/components/card.py +87 -0
- solara/components/checkbox.py +50 -0
- solara/components/code_highlight_css.py +11 -0
- solara/components/code_highlight_css.vue +63 -0
- solara/components/columns.py +159 -0
- solara/components/component_vue.py +110 -0
- solara/components/cross_filter.py +335 -0
- solara/components/dataframe.py +546 -0
- solara/components/datatable.py +221 -0
- solara/components/datatable.vue +175 -0
- solara/components/details.py +21 -0
- solara/components/download.vue +35 -0
- solara/components/echarts.py +75 -0
- solara/components/echarts.vue +128 -0
- solara/components/figure_altair.py +39 -0
- solara/components/file_browser.py +182 -0
- solara/components/file_download.py +199 -0
- solara/components/file_drop.py +139 -0
- solara/components/file_drop.vue +83 -0
- solara/components/file_list_widget.vue +78 -0
- solara/components/head.py +27 -0
- solara/components/head_tag.py +49 -0
- solara/components/head_tag.vue +60 -0
- solara/components/image.py +173 -0
- solara/components/input.py +436 -0
- solara/components/link.py +55 -0
- solara/components/markdown.py +378 -0
- solara/components/markdown_editor.py +25 -0
- solara/components/markdown_editor.vue +362 -0
- solara/components/matplotlib.py +74 -0
- solara/components/meta.py +47 -0
- solara/components/misc.py +333 -0
- solara/components/pivot_table.py +258 -0
- solara/components/pivot_table.vue +158 -0
- solara/components/progress.py +47 -0
- solara/components/select.py +182 -0
- solara/components/select.vue +27 -0
- solara/components/slider.py +442 -0
- solara/components/slider_date.vue +56 -0
- solara/components/spinner-solara.vue +105 -0
- solara/components/spinner.py +30 -0
- solara/components/sql_code.py +33 -0
- solara/components/sql_code.vue +128 -0
- solara/components/style.py +105 -0
- solara/components/switch.py +68 -0
- solara/components/tab_navigation.py +37 -0
- solara/components/title.py +90 -0
- solara/components/title.vue +38 -0
- solara/components/togglebuttons.py +200 -0
- solara/components/tooltip.py +61 -0
- solara/datatypes.py +143 -0
- solara/express.py +241 -0
- solara/hooks/__init__.py +4 -0
- solara/hooks/dataframe.py +99 -0
- solara/hooks/misc.py +263 -0
- solara/hooks/use_reactive.py +129 -0
- solara/hooks/use_thread.py +129 -0
- solara/kitchensink.py +8 -0
- solara/lab/__init__.py +34 -0
- solara/lab/components/__init__.py +6 -0
- solara/lab/components/chat.py +203 -0
- solara/lab/components/confirmation_dialog.py +163 -0
- solara/lab/components/cross_filter.py +7 -0
- solara/lab/components/input_date.py +298 -0
- solara/lab/components/menu.py +181 -0
- solara/lab/components/menu.vue +38 -0
- solara/lab/components/tabs.py +274 -0
- solara/lab/components/theming.py +98 -0
- solara/lab/components/theming.vue +72 -0
- solara/lab/hooks/__init__.py +0 -0
- solara/lab/hooks/dataframe.py +12 -0
- solara/lab/toestand.py +3 -0
- solara/lab/utils/__init__.py +2 -0
- solara/lab/utils/cookies.py +5 -0
- solara/lab/utils/dataframe.py +115 -0
- solara/lab/utils/headers.py +5 -0
- solara/layout.py +44 -0
- solara/lifecycle.py +46 -0
- solara/minisettings.py +133 -0
- solara/py.typed +0 -0
- solara/reactive.py +93 -0
- solara/routing.py +268 -0
- solara/scope/__init__.py +88 -0
- solara/scope/types.py +55 -0
- solara/server/__init__.py +0 -0
- solara/server/app.py +491 -0
- solara/server/assets/custom.css +1 -0
- solara/server/assets/custom.js +1 -0
- solara/server/assets/favicon.png +0 -0
- solara/server/assets/favicon.svg +5 -0
- solara/server/assets/style.css +1665 -0
- solara/server/assets/theme-dark.css +437 -0
- solara/server/assets/theme-light.css +420 -0
- solara/server/assets/theme.js +3 -0
- solara/server/cdn_helper.py +77 -0
- solara/server/esm.py +69 -0
- solara/server/fastapi.py +5 -0
- solara/server/flask.py +286 -0
- solara/server/jupyter/__init__.py +2 -0
- solara/server/jupyter/cdn_handler.py +28 -0
- solara/server/jupyter/server_extension.py +29 -0
- solara/server/jupytertools.py +46 -0
- solara/server/kernel.py +338 -0
- solara/server/kernel_context.py +357 -0
- solara/server/patch.py +552 -0
- solara/server/reload.py +242 -0
- solara/server/server.py +456 -0
- solara/server/settings.py +215 -0
- solara/server/shell.py +251 -0
- solara/server/starlette.py +601 -0
- solara/server/static/ansi.js +270 -0
- solara/server/static/highlight-dark.css +82 -0
- solara/server/static/highlight.css +43 -0
- solara/server/static/main-vuetify.js +260 -0
- solara/server/static/main.js +163 -0
- solara/server/static/solara_bootstrap.py +129 -0
- solara/server/static/sun.svg +23 -0
- solara/server/static/webworker.js +42 -0
- solara/server/telemetry.py +212 -0
- solara/server/templates/index.html.j2 +1 -0
- solara/server/templates/loader-plain.css +11 -0
- solara/server/templates/loader-plain.html +20 -0
- solara/server/templates/loader-solara.css +111 -0
- solara/server/templates/loader-solara.html +40 -0
- solara/server/templates/plain.html +82 -0
- solara/server/templates/solara.html.j2 +446 -0
- solara/server/threaded.py +75 -0
- solara/server/utils.py +30 -0
- solara/server/websocket.py +45 -0
- solara/settings.py +56 -0
- solara/tasks.py +837 -0
- solara/template/button.py +16 -0
- solara/template/markdown.py +42 -0
- solara/template/portal/.flake8 +6 -0
- solara/template/portal/.pre-commit-config.yaml +28 -0
- solara/template/portal/LICENSE +21 -0
- solara/template/portal/Procfile +7 -0
- solara/template/portal/mypy.ini +3 -0
- solara/template/portal/pyproject.toml +26 -0
- solara/template/portal/solara_portal/__init__.py +4 -0
- solara/template/portal/solara_portal/components/__init__.py +2 -0
- solara/template/portal/solara_portal/components/article.py +28 -0
- solara/template/portal/solara_portal/components/data.py +28 -0
- solara/template/portal/solara_portal/components/header.py +6 -0
- solara/template/portal/solara_portal/components/layout.py +6 -0
- solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
- solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
- solara/template/portal/solara_portal/data.py +60 -0
- solara/template/portal/solara_portal/pages/__init__.py +67 -0
- solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
- solara/template/portal/solara_portal/pages/tabular.py +29 -0
- solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
- solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
- solara/test/__init__.py +0 -0
- solara/test/pytest_plugin.py +697 -0
- solara/toestand.py +772 -0
- solara/util.py +308 -0
- solara/website/__init__.py +0 -0
- solara/website/assets/custom.css +468 -0
- solara/website/assets/images/logo-small.png +0 -0
- solara/website/assets/images/logo.svg +17 -0
- solara/website/assets/images/logo_white.svg +50 -0
- solara/website/assets/theme.js +8 -0
- solara/website/components/__init__.py +5 -0
- solara/website/components/algolia.vue +24 -0
- solara/website/components/algolia_api.vue +187 -0
- solara/website/components/docs.py +118 -0
- solara/website/components/header.py +72 -0
- solara/website/components/hero.py +15 -0
- solara/website/components/mailchimp.py +12 -0
- solara/website/components/mailchimp.vue +47 -0
- solara/website/components/markdown.py +30 -0
- solara/website/components/notebook.py +171 -0
- solara/website/pages/__init__.py +575 -0
- solara/website/pages/apps/__init__.py +16 -0
- solara/website/pages/apps/authorization/__init__.py +119 -0
- solara/website/pages/apps/authorization/admin.py +12 -0
- solara/website/pages/apps/authorization/users.py +12 -0
- solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
- solara/website/pages/apps/layout-demo.py +40 -0
- solara/website/pages/apps/multipage/__init__.py +38 -0
- solara/website/pages/apps/multipage/page1.py +26 -0
- solara/website/pages/apps/multipage/page2.py +34 -0
- solara/website/pages/apps/scatter.py +136 -0
- solara/website/pages/apps/scrolling.py +63 -0
- solara/website/pages/apps/tutorial-streamlit.py +18 -0
- solara/website/pages/changelog/__init__.py +8 -0
- solara/website/pages/changelog/changelog.md +204 -0
- solara/website/pages/contact/__init__.py +8 -0
- solara/website/pages/contact/contact.md +17 -0
- solara/website/pages/doc_use_download.py +85 -0
- solara/website/pages/documentation/__init__.py +184 -0
- solara/website/pages/documentation/advanced/__init__.py +9 -0
- solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
- solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
- solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
- solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
- solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +162 -0
- solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
- solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +49 -0
- solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
- solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
- solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
- solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +36 -0
- solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
- solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
- solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
- solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
- solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
- solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
- solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
- solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
- solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
- solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
- solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
- solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +7 -0
- solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
- solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
- solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +240 -0
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +97 -0
- solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +171 -0
- solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
- solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
- solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
- solara/website/pages/documentation/api/__init__.py +19 -0
- solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +23 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +22 -0
- solara/website/pages/documentation/api/hooks/__init__.py +9 -0
- solara/website/pages/documentation/api/hooks/use_cross_filter.py +25 -0
- solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
- solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
- solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
- solara/website/pages/documentation/api/hooks/use_exception.py +33 -0
- solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
- solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
- solara/website/pages/documentation/api/hooks/use_previous.py +33 -0
- solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
- solara/website/pages/documentation/api/hooks/use_state.py +10 -0
- solara/website/pages/documentation/api/hooks/use_state_or_update.py +69 -0
- solara/website/pages/documentation/api/hooks/use_thread.md +58 -0
- solara/website/pages/documentation/api/hooks/use_thread.py +44 -0
- solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
- solara/website/pages/documentation/api/routing/__init__.py +9 -0
- solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
- solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
- solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
- solara/website/pages/documentation/api/routing/route.py +31 -0
- solara/website/pages/documentation/api/routing/use_route.py +80 -0
- solara/website/pages/documentation/api/routing/use_router.py +16 -0
- solara/website/pages/documentation/api/utilities/__init__.py +9 -0
- solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
- solara/website/pages/documentation/api/utilities/computed.py +16 -0
- solara/website/pages/documentation/api/utilities/display.py +16 -0
- solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
- solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
- solara/website/pages/documentation/api/utilities/memoize.py +35 -0
- solara/website/pages/documentation/api/utilities/on_kernel_start.py +27 -0
- solara/website/pages/documentation/api/utilities/reactive.py +16 -0
- solara/website/pages/documentation/api/utilities/widget.py +104 -0
- solara/website/pages/documentation/components/__init__.py +12 -0
- solara/website/pages/documentation/components/advanced/__init__.py +9 -0
- solara/website/pages/documentation/components/advanced/link.py +27 -0
- solara/website/pages/documentation/components/advanced/meta.py +20 -0
- solara/website/pages/documentation/components/advanced/style.py +45 -0
- solara/website/pages/documentation/components/common.py +9 -0
- solara/website/pages/documentation/components/data/__init__.py +9 -0
- solara/website/pages/documentation/components/data/dataframe.py +44 -0
- solara/website/pages/documentation/components/data/pivot_table.py +81 -0
- solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
- solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
- solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
- solara/website/pages/documentation/components/input/__init__.py +9 -0
- solara/website/pages/documentation/components/input/button.py +23 -0
- solara/website/pages/documentation/components/input/checkbox.py +10 -0
- solara/website/pages/documentation/components/input/file_browser.py +32 -0
- solara/website/pages/documentation/components/input/file_drop.py +76 -0
- solara/website/pages/documentation/components/input/input.py +19 -0
- solara/website/pages/documentation/components/input/select.py +22 -0
- solara/website/pages/documentation/components/input/slider.py +29 -0
- solara/website/pages/documentation/components/input/switch.py +10 -0
- solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
- solara/website/pages/documentation/components/lab/__init__.py +9 -0
- solara/website/pages/documentation/components/lab/chat.py +109 -0
- solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
- solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
- solara/website/pages/documentation/components/lab/input_date.py +20 -0
- solara/website/pages/documentation/components/lab/menu.py +22 -0
- solara/website/pages/documentation/components/lab/tab.py +25 -0
- solara/website/pages/documentation/components/lab/tabs.py +45 -0
- solara/website/pages/documentation/components/lab/task.py +11 -0
- solara/website/pages/documentation/components/lab/theming.py +72 -0
- solara/website/pages/documentation/components/lab/use_task.py +11 -0
- solara/website/pages/documentation/components/layout/__init__.py +9 -0
- solara/website/pages/documentation/components/layout/app_bar.py +16 -0
- solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
- solara/website/pages/documentation/components/layout/app_layout.py +24 -0
- solara/website/pages/documentation/components/layout/card.py +15 -0
- solara/website/pages/documentation/components/layout/card_actions.py +16 -0
- solara/website/pages/documentation/components/layout/column.py +30 -0
- solara/website/pages/documentation/components/layout/columns.py +27 -0
- solara/website/pages/documentation/components/layout/columns_responsive.py +68 -0
- solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
- solara/website/pages/documentation/components/layout/gridfixed.py +21 -0
- solara/website/pages/documentation/components/layout/hbox.py +18 -0
- solara/website/pages/documentation/components/layout/row.py +30 -0
- solara/website/pages/documentation/components/layout/sidebar.py +24 -0
- solara/website/pages/documentation/components/layout/vbox.py +19 -0
- solara/website/pages/documentation/components/output/__init__.py +9 -0
- solara/website/pages/documentation/components/output/file_download.py +11 -0
- solara/website/pages/documentation/components/output/html.py +21 -0
- solara/website/pages/documentation/components/output/image.py +11 -0
- solara/website/pages/documentation/components/output/markdown.py +57 -0
- solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
- solara/website/pages/documentation/components/output/sql_code.py +85 -0
- solara/website/pages/documentation/components/output/tooltip.py +11 -0
- solara/website/pages/documentation/components/page/__init__.py +9 -0
- solara/website/pages/documentation/components/page/head.py +18 -0
- solara/website/pages/documentation/components/page/title.py +27 -0
- solara/website/pages/documentation/components/status/__init__.py +9 -0
- solara/website/pages/documentation/components/status/error.py +40 -0
- solara/website/pages/documentation/components/status/info.py +40 -0
- solara/website/pages/documentation/components/status/progress.py +10 -0
- solara/website/pages/documentation/components/status/spinner.py +11 -0
- solara/website/pages/documentation/components/status/success.py +40 -0
- solara/website/pages/documentation/components/status/warning.py +47 -0
- solara/website/pages/documentation/components/viz/__init__.py +9 -0
- solara/website/pages/documentation/components/viz/altair.py +42 -0
- solara/website/pages/documentation/components/viz/echarts.py +75 -0
- solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
- solara/website/pages/documentation/components/viz/plotly.py +63 -0
- solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
- solara/website/pages/documentation/examples/__init__.py +52 -0
- solara/website/pages/documentation/examples/ai/__init__.py +11 -0
- solara/website/pages/documentation/examples/ai/chatbot.py +95 -0
- solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
- solara/website/pages/documentation/examples/basics/__init__.py +10 -0
- solara/website/pages/documentation/examples/basics/sine.py +28 -0
- solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
- solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
- solara/website/pages/documentation/examples/general/__init__.py +10 -0
- solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
- solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
- solara/website/pages/documentation/examples/general/live_update.py +38 -0
- solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
- solara/website/pages/documentation/examples/general/mycard.vue +58 -0
- solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
- solara/website/pages/documentation/examples/general/vue_component.py +50 -0
- solara/website/pages/documentation/examples/ipycanvas.py +49 -0
- solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
- solara/website/pages/documentation/examples/libraries/altair.py +64 -0
- solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
- solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
- solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
- solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
- solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
- solara/website/pages/documentation/examples/utilities/countdown_timer.py +64 -0
- solara/website/pages/documentation/examples/utilities/todo.py +196 -0
- solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
- solara/website/pages/documentation/examples/visualization/annotator.py +69 -0
- solara/website/pages/documentation/examples/visualization/linked_views.py +84 -0
- solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
- solara/website/pages/documentation/faq/__init__.py +12 -0
- solara/website/pages/documentation/faq/content/99-faq.md +76 -0
- solara/website/pages/documentation/getting_started/__init__.py +9 -0
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +89 -0
- solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
- solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +64 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1000 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +223 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +88 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +273 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
- solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
- solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
- solara/website/pages/docutils.py +38 -0
- solara/website/pages/showcase/__init__.py +105 -0
- solara/website/pages/showcase/domino_code_assist.py +60 -0
- solara/website/pages/showcase/planeto_tessa.py +19 -0
- solara/website/pages/showcase/solara_dev.py +54 -0
- solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
- solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
- solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
- solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
- solara/website/pages/showcase/wanderlust.py +27 -0
- solara/website/public/beach.jpeg +0 -0
- solara/website/public/logo.svg +6 -0
- solara/website/public/social/discord.svg +1 -0
- solara/website/public/social/github.svg +1 -0
- solara/website/public/social/twitter.svg +3 -0
- solara/website/public/success.html +25 -0
- solara/website/templates/index.html.j2 +117 -0
- solara/website/utils.py +51 -0
- solara/widgets/__init__.py +1 -0
- solara/widgets/vue/gridlayout.vue +110 -0
- solara/widgets/vue/html.vue +4 -0
- solara/widgets/vue/navigator.vue +104 -0
- solara/widgets/vue/vegalite.vue +115 -0
- solara/widgets/widgets.py +66 -0
- solara_ui-1.31.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- solara_ui-1.31.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara_ui-1.31.0.dist-info/METADATA +158 -0
- solara_ui-1.31.0.dist-info/RECORD +439 -0
- solara_ui-1.31.0.dist-info/WHEEL +5 -0
- solara_ui-1.31.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Building multi-page apps in Solara
|
|
3
|
+
description: The simplest way to create a multi-page app is to create a directory with multiple scripts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Multi-page support
|
|
7
|
+
|
|
8
|
+
In the [Web App tutorial](/documentation/getting_started/tutorials/web-app), we created an application consisting of a single page. Web applications generally have multiple pages, and Solara supports this as well.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Multiple scripts
|
|
12
|
+
|
|
13
|
+
The simplest way to create a multi-page app is to create a directory with multiple scripts.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
$ solara create button multipage-demo/01-click-button.py
|
|
17
|
+
Wrote: /mypath/multipage-demo/01-click-button.py
|
|
18
|
+
...
|
|
19
|
+
$ solara create markdown multipage-demo/02-markdown-editor.py
|
|
20
|
+
Wrote: /mypath/multipage-demo/02-markdown-editor.py
|
|
21
|
+
...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
You should have the following directory structure:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
multipage-demo
|
|
29
|
+
├── 01-click-button.py
|
|
30
|
+
└── 02-markdown-editor.py
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Now run Solara, with this directory as argument:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
$ solara run ./multipage-demo
|
|
37
|
+
Solara server is starting at http://localhost:8765
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Giving you an output like:
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
Solara now:
|
|
45
|
+
|
|
46
|
+
* Sort the paths according to the filename (hence the 01- and 02- prefix)
|
|
47
|
+
* Generate a nice URL by stripping of prefix, splitting the filename taking out `-`, `_` and spaces, and join them together using a `-` (e.g. "/markdown-editor").
|
|
48
|
+
* Generate a nice default title similar to the link, but now capitalize the first letter and join with a space instead (e.g. "Mardown Editor").
|
|
49
|
+
* The first page will be the default (and its URL will be empty instead, i.e., the empty string `""`)
|
|
50
|
+
* Since the first script does not define a `Layout` component, nor did we add a `__init__.py` with a `Layout` component, Solara will add a [Layout component](/documentation/components/layout/app_layout) which includes a navigation sidebar.
|
|
51
|
+
* If a path is a directory, Solara will recursively scan the subdirectory and include it in the navigation. Read more on this in the [Layout section](layout)
|
|
52
|
+
|
|
53
|
+
Solara will render two pages:
|
|
54
|
+
|
|
55
|
+
* http://localhost:8765 with title "Click Button"
|
|
56
|
+
* http://localhost:8765/markdown-editor with title "Markdown Editor"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## Classical widgets support
|
|
61
|
+
|
|
62
|
+
Multipage is also supported for regular ipywidgets. An example directory can be seen on [GitHub](https://github.com/widgetti/solara/tree/master/tests/unit/solara_test_apps/multipage),
|
|
63
|
+
which we use for testing.
|
|
64
|
+
|
|
65
|
+
A large difference between using regular ipywidgets for pages compared to using components is that there is no lifecycle
|
|
66
|
+
management in regular ipywidgets. This means Solara cannot clean up your ipywidget-based page (garbage-collect the unused widgets, unregister callbacks)
|
|
67
|
+
when a user navigates away from your page.
|
|
68
|
+
|
|
69
|
+
At the same time, rerunning your regular ipywidget-based script each time a user navigates to that page will result in a buildup of many widgets.
|
|
70
|
+
|
|
71
|
+
This means that Solara will run your page once (the first time it is loaded by a user/browser tab), and, when navigating back,
|
|
72
|
+
will show the page in the same state as when the user left the page.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## As a package
|
|
76
|
+
|
|
77
|
+
Once you start building a larger application, it pays off using a Python package instead. This allows you to organize and distribute your app as a Python package (as a wheel for instance) and allows you to organize your application
|
|
78
|
+
into reusable packages for components, stores, hooks etc.
|
|
79
|
+
|
|
80
|
+
As a quickstart, we can generate a startup project using:
|
|
81
|
+
```bash
|
|
82
|
+
$ solara create portal solara-test-portal
|
|
83
|
+
Wrote: /Users/maartenbreddels/github/widgetti/solara/solara-test-portal
|
|
84
|
+
Install as:
|
|
85
|
+
$ (cd solara-test-portal; pip install -e .)
|
|
86
|
+
Run as:
|
|
87
|
+
$ solara run solara_test_portal.pages
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
You should have the following directory structure:
|
|
91
|
+
```bash
|
|
92
|
+
├── LICENSE
|
|
93
|
+
├── Procfile # will make it run on heroku
|
|
94
|
+
├── mypy.ini # adds strict type checking
|
|
95
|
+
├── pyproject.toml # make it installable with pip/hatch etc
|
|
96
|
+
└── solara_test_portal # Python package containing all code
|
|
97
|
+
├── __init__.py
|
|
98
|
+
├── components # contains general react components
|
|
99
|
+
│ ├── __init__.py
|
|
100
|
+
│ ├── header.py
|
|
101
|
+
│ └── layout.py
|
|
102
|
+
├── content # contains content (markdown articles in this case)
|
|
103
|
+
│ └── articles
|
|
104
|
+
│ ├── 7-reasons-why-i-love-vaex-for-data-science.md
|
|
105
|
+
│ └── a-hybrid-apache-arrow-numpy-dataframe-with-vaex-version-4.md
|
|
106
|
+
├── data.py # here is where we store shared data or application state
|
|
107
|
+
└── pages # contains the pages
|
|
108
|
+
├── __init__.py
|
|
109
|
+
├── article
|
|
110
|
+
│ └── __init__.py
|
|
111
|
+
├── tabular.py
|
|
112
|
+
└── viz
|
|
113
|
+
├── __init__.py
|
|
114
|
+
└── overview.py
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Install it using
|
|
118
|
+
```bash
|
|
119
|
+
$ (cd solara-test-portal; pip install -e .)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Run it with
|
|
123
|
+
```bash
|
|
124
|
+
$ solara run solara_test_portal.pages
|
|
125
|
+
Solara server is starting at http://localhost:8765
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Go to http://localhost:8765 ([or click here](http://localhost:8765)), explore the source code, edit it, save it, and watch the web app reload instantly.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## In a single script
|
|
132
|
+
|
|
133
|
+
If you want to setup a multipage app in a single script, you do not need to define a `Page` component, but you can define a list of routes.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import solara
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@solara.component
|
|
140
|
+
def Home():
|
|
141
|
+
solara.Markdown("Home")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@solara.component
|
|
145
|
+
def About():
|
|
146
|
+
solara.Markdown("About")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
routes = [
|
|
150
|
+
solara.Route(path="/", component=Home, label="home"),
|
|
151
|
+
solara.Route(path="about", component=About, label="about"),
|
|
152
|
+
]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
See more details in the [Route section](/documentation/advanced/understanding/routing).
|
|
156
|
+
|
|
157
|
+
## Dynamic pages
|
|
158
|
+
|
|
159
|
+
In the previous section we created the example portal app. Taking a look at
|
|
160
|
+
tabular.py, we see the `Page` component takes an additional arguments.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
@solara.component
|
|
164
|
+
def Page(name: str):
|
|
165
|
+
...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
Solara recognizes this and will pass all routes such as `/tabular/foo` and `/tabular/bar` to this Page component passing for instance `"foo"` or `"bar"` as an argument, such that you can dynamically render a page based on the URL.
|
|
170
|
+
|
|
171
|
+
An example Page component could look like this:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
@solara.component
|
|
175
|
+
def Page(name: str = "foo"):
|
|
176
|
+
subpages = ["foo", "bar", "solara", "react-ipywidgets"]
|
|
177
|
+
solara.Markdown(f"You are at: {name}")
|
|
178
|
+
# bunch of buttons which navigate to our dynamic route
|
|
179
|
+
with solara.Row():
|
|
180
|
+
for subpage in subpages:
|
|
181
|
+
with solara.Link(subpage):
|
|
182
|
+
solara.Button(label=f"Go to: {subpage}")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
By giving the name argument a default value of `"foo"`, Solara will also accept the `/tabular` url.
|
|
186
|
+
|
|
187
|
+
# What you have learned
|
|
188
|
+
|
|
189
|
+
* Putting multiple Solara app script into a directory allows Solara to show a multipage app.
|
|
190
|
+
* If no `Layout` component is provided, Solara adds a default navigation sidebar.
|
|
191
|
+
* Large application can benefit from setting up a Python package, use `solara create portal my-name` to create one.
|
|
192
|
+
* By adding an argument to the `Page` component, routes like `/tabular` will turn into dynamic routes (e.g. `/tabular/dynamic-name`) and pass the argument (`"dynamic-name"` in this case) to the `Page` component to implement dynamic pages.
|
|
193
|
+
|
|
194
|
+
# What next?
|
|
195
|
+
|
|
196
|
+
* Also check out the [Multipage example](/documentation/examples/fullscreen/multipage) for more inspiration.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Making different layouts in Solara
|
|
3
|
+
description: Solara comes with a layout system ideal for data apps. Learn how to use them in this short guide.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Layout
|
|
7
|
+
|
|
8
|
+
Solara comes with a layout system ideal for data apps.
|
|
9
|
+
|
|
10
|
+
The following example shows 80% of what you need to know to lay out your app.
|
|
11
|
+
|
|
12
|
+
```solara
|
|
13
|
+
import solara
|
|
14
|
+
|
|
15
|
+
@solara.component
|
|
16
|
+
def Page():
|
|
17
|
+
with solara.Column():
|
|
18
|
+
solara.Title("I'm in the browser tab and the toolbar")
|
|
19
|
+
with solara.Sidebar():
|
|
20
|
+
solara.Markdown("## I am in the sidebar")
|
|
21
|
+
solara.SliderInt(label="Ideal for placing controls")
|
|
22
|
+
solara.Info("I'm in the main content area, put your main content here")
|
|
23
|
+
with solara.Card("Use solara.Columns([1, 2]) to create relatively sized columns"):
|
|
24
|
+
with solara.Columns([1, 2]):
|
|
25
|
+
solara.Success("I'm in the first column")
|
|
26
|
+
solara.Warning("I'm in the second column, I am twice as wide")
|
|
27
|
+
solara.Info("I am like the first column")
|
|
28
|
+
|
|
29
|
+
with solara.Card("Use solara.Column() to create a full width column"):
|
|
30
|
+
with solara.Column():
|
|
31
|
+
solara.Success("I'm first in this full with column")
|
|
32
|
+
solara.Warning("I'm second in this full with column")
|
|
33
|
+
solara.Error("I'm third in this full with column")
|
|
34
|
+
|
|
35
|
+
with solara.Card("Use solara.ColumnsResponsive(6, large=4) to response to screen size"):
|
|
36
|
+
with solara.ColumnsResponsive(6, large=4):
|
|
37
|
+
for i in range(6):
|
|
38
|
+
solara.Info("two per column on small screens, three per column on large screens")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
[Navigate here to watch this layout in a full browser window](/documentation/examples/fullscreen/layout-demo)
|
|
42
|
+
|
|
43
|
+
The key takeaways are:
|
|
44
|
+
|
|
45
|
+
* By default, Solara will wrap your component in an [AppLayout](/documentation/components/layout/app_layout), which will give you:
|
|
46
|
+
* Room for a sidebar, that you can populate using the [Sidebar](/documentation/components/layout/sidebar) component.
|
|
47
|
+
* A toolbar showing the [Title](/documentation/components/page/title).
|
|
48
|
+
* Not visible here: In the case of [multiple pages](/documentation/advanced/howto/multipage) will include page navigation tabs. See [The multipage demo app](/documentation/examples/fullscreen/multipage) for an example.
|
|
49
|
+
* Use [Card](/documentation/components/layout/card) to put related components together with a title.
|
|
50
|
+
* Use [Column](/documentation/components/layout/column) to simply layout components under each other.
|
|
51
|
+
* Use [Columns](/documentation/components/layout/columns) if you want to have a few columns with relative sizes next to each other.
|
|
52
|
+
* Use [ColumnsResponsive](/documentation/components/layout/columns_responsive) to have the column widths respond to screen size.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Changing the default layout
|
|
57
|
+
|
|
58
|
+
While [AppLayout](/documentation/components/layout/app_layout) may be sufficient in 80% of the cases. Solara provides a way to change this default layout in [Solara server](/documentation/advanced/understanding/solara-server).
|
|
59
|
+
|
|
60
|
+
You can define your own `Layout` component in the `__init__.py` file in the same directory of your app script.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
For instance, putting the following `Layout` component in `__init__.py` will give you effectively the same [AppLayout](/documentation/components/layout/app_layout):
|
|
64
|
+
```python
|
|
65
|
+
@solara.component
|
|
66
|
+
def Layout(children=[]):
|
|
67
|
+
print("I get called before the Page component gets rendered")
|
|
68
|
+
return solara.AppLayout(children=children)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### No Layout
|
|
73
|
+
If you do not want to have any layout, you can disable it using:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
@solara.component
|
|
77
|
+
def Layout(children=[]):
|
|
78
|
+
# there will only be 1 child, which is the Page()
|
|
79
|
+
return children[0]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This layout leaves every page responsible for creating its own header, footer, and/or menu structure for navigation.
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Layout with navigation
|
|
86
|
+
|
|
87
|
+
In case you want to set up your own layout system, which sets up navigation as well, this example may get you started. It may help
|
|
88
|
+
to [understand routing](/documentation/advanced/understanding/routing).
|
|
89
|
+
```python
|
|
90
|
+
@solara.component
|
|
91
|
+
def Layout(children=[]):
|
|
92
|
+
# Note that children being passed here for this example will be a Page() element.
|
|
93
|
+
route_current, routes_all = solara.use_route()
|
|
94
|
+
with solara.Column():
|
|
95
|
+
# put all buttons in a single row
|
|
96
|
+
with solara.Row():
|
|
97
|
+
for route in routes_all:
|
|
98
|
+
with solara.Link(route):
|
|
99
|
+
solara.Button(route.path, color="red" if route_current == route else None)
|
|
100
|
+
# under the navigation buttons, we add our children (the single Page())
|
|
101
|
+
solara.Column(children=children)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Nested Layouts
|
|
106
|
+
|
|
107
|
+
Each subdirectory (or subpackage) can define a `Layout` component in its own `__init__.py`, which then is embedded into the parent Layout to provide a hierarchical
|
|
108
|
+
nested layout tree.
|
|
109
|
+
|
|
110
|
+
This is useful for larger apps where each subdirectory may add a bit of layout/chrome around your page.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
## Components
|
|
115
|
+
|
|
116
|
+
The following [Container components](/documentation/advanced/understanding/containers) can be used to define the layout of you app.
|
|
117
|
+
|
|
118
|
+
* [Row](/documentation/components/layout/row)
|
|
119
|
+
* [Column](/documentation/components/layout/column)
|
|
120
|
+
* [ColumnsResponsive](/documentation/components/layout/columns_responsive)
|
|
121
|
+
* [GridFixed](/documentation/components/layout/gridfixed)
|
|
122
|
+
* [GridDraggable](/documentation/components/layout/griddraggable)
|
|
123
|
+
* [VBox](/documentation/components/layout/vbox) (kept for ipywidgets compatibility, please use Column)
|
|
124
|
+
* [HBox](/documentation/components/layout/hbox) (kept for ipywidgets compatibility, please use Row)
|
|
125
|
+
* [AppLayout](/documentation/components/layout/app_layout) Not often used directly, since Solara will already wrap your page in it. Sometimes re-used in a new `Layout` component.
|
|
@@ -0,0 +1,162 @@
|
|
|
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
|
+
|
|
9
|
+
## Testing without a Browser
|
|
10
|
+
|
|
11
|
+
We recommend using pytest to test the application logic of your Solara components. 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).
|
|
12
|
+
|
|
13
|
+
## Testing with a Browser
|
|
14
|
+
|
|
15
|
+
### Installation
|
|
16
|
+
|
|
17
|
+
Solara is 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.
|
|
18
|
+
|
|
19
|
+
To install `pytest-ipywidgets` and Playwright for Python, run the following commands:
|
|
20
|
+
```
|
|
21
|
+
$ pip install "pytest-ipywidgets[solara]" # or "pytest-ipywidgets[all]" if you also want to test with Jupyter Lab, Jupiter Notebook and Voila.
|
|
22
|
+
$ playwright install chromium
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Testing widgets using Solara server
|
|
26
|
+
|
|
27
|
+
The most convenient way to test a widget, is by including the `solara_test` fixture in your test function arguments. Here's an example:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# file tests/ui/test_widget_button.py
|
|
31
|
+
import ipywidgets as widgets
|
|
32
|
+
import playwright.sync_api
|
|
33
|
+
from IPython.display import display
|
|
34
|
+
|
|
35
|
+
def test_widget_button_solara(solara_test, page_session: playwright.sync_api.Page):
|
|
36
|
+
# this all runs in process, which only works with solara
|
|
37
|
+
# also, this test is only with pure ipywidgets
|
|
38
|
+
button = widgets.Button(description="Click Me!")
|
|
39
|
+
|
|
40
|
+
def change_description(obj):
|
|
41
|
+
button.description = "Tested event"
|
|
42
|
+
|
|
43
|
+
button.on_click(change_description)
|
|
44
|
+
display(button)
|
|
45
|
+
button_sel = page_session.locator("text=Click Me!")
|
|
46
|
+
button_sel.wait_for()
|
|
47
|
+
button_sel.click()
|
|
48
|
+
page_session.locator("text=Tested event").wait_for()
|
|
49
|
+
```
|
|
50
|
+
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,
|
|
51
|
+
in this case we trigger a button click in the browser and check if the button description changes to "Tested event".
|
|
52
|
+
|
|
53
|
+
Run this test with pytest as follows:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pytest tests/ui/test_widget_button.py --headed # remove --headed to run headless
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Testing in the main Jupyter Environments
|
|
62
|
+
|
|
63
|
+
In case you want to test your component in the main 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:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import ipywidgets as widgets
|
|
67
|
+
import playwright.sync_api
|
|
68
|
+
from IPython.display import display
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_solara_button_all(ipywidgets_runner, page_session: playwright.sync_api.Page, assert_solara_snapshot):
|
|
72
|
+
# this function (or rather its lines) will be executed in the kernel
|
|
73
|
+
# voila, lab, classic notebook and solara will all execute it
|
|
74
|
+
def kernel_code():
|
|
75
|
+
import solara
|
|
76
|
+
|
|
77
|
+
@solara.component
|
|
78
|
+
def Button():
|
|
79
|
+
text, set_text = solara.use_state("Click Me!")
|
|
80
|
+
|
|
81
|
+
def on_click():
|
|
82
|
+
set_text("Tested event")
|
|
83
|
+
|
|
84
|
+
solara.Button(text, on_click=on_click)
|
|
85
|
+
|
|
86
|
+
display(Button())
|
|
87
|
+
|
|
88
|
+
ipywidgets_runner(kernel_code)
|
|
89
|
+
button_sel = page_session.locator("button >> text=Click Me!")
|
|
90
|
+
assert_solara_snapshot(button_sel.screenshot())
|
|
91
|
+
button_sel.wait_for()
|
|
92
|
+
button_sel.click()
|
|
93
|
+
page_session.locator("button >> text=Tested event").wait_for()
|
|
94
|
+
page_session.wait_for_timeout(1000)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
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.
|
|
98
|
+
Because the function code executes in the kernel, you do not have access to local variables. However, by passing a dictionary as second argument
|
|
99
|
+
to `ipywidgets_runner` we can pass in extra local variables (e.g. `ipywidgets_runner(kernel_code, {"extra_argument": extra_argument})`).
|
|
100
|
+
|
|
101
|
+
## Limiting the Jupyter Environments
|
|
102
|
+
To limit the ipywidgets_runner fixture to only run in a specific environment, use the `SOLARA_TEST_RUNNERS` environment variable:
|
|
103
|
+
|
|
104
|
+
* `SOLARA_TEST_RUNNERS=solara pytest tests/ui`
|
|
105
|
+
* `SOLARA_TEST_RUNNERS=voila pytest tests/ui`
|
|
106
|
+
* `SOLARA_TEST_RUNNERS=jupyter_lab pytest tests/ui`
|
|
107
|
+
* `SOLARA_TEST_RUNNERS=jupyter_notebook pytest tests/ui`
|
|
108
|
+
* `SOLARA_TEST_RUNNERS=solara,voila pytest tests/ui`
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# Organizing Tests and Managing Snapshots
|
|
113
|
+
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 (t`est/ui`). Use the `solara_snapshots_directory` fixture to change the default directory for storing snapshots, which is `tests/ui/snapshots` by default.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
$ pytest tests/unit # run fast test
|
|
117
|
+
$ pytest tests/ui # run slow test
|
|
118
|
+
$ pytest tests # run all tests
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
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.
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# Continuous Integration Recommendations
|
|
127
|
+
|
|
128
|
+
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).
|
|
129
|
+
|
|
130
|
+
In CI, we recommend downloading this directory using, for example, GitHub Actions:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
- name: Download test results
|
|
134
|
+
uses: actions/download-artifact@v2
|
|
135
|
+
with:
|
|
136
|
+
name: myproject-test-results
|
|
137
|
+
path: test-results
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
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.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Note about the Playwright
|
|
145
|
+
|
|
146
|
+
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.
|
|
147
|
+
|
|
148
|
+
By following these recommendations and guidelines, you can efficiently test your Solara applications and ensure a smooth developer experience.
|
|
149
|
+
|
|
150
|
+
# Configuration
|
|
151
|
+
|
|
152
|
+
## Changing the Hostname
|
|
153
|
+
|
|
154
|
+
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.
|
|
155
|
+
|
|
156
|
+
## Changing the Port
|
|
157
|
+
|
|
158
|
+
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.
|
|
159
|
+
|
|
160
|
+
## Vuetify warmup
|
|
161
|
+
|
|
162
|
+
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`).
|
|
@@ -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
|
+

|
|
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,49 @@
|
|
|
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 cookies settings in an iframe, we set the session cookie using `Secure`, and `SameSite=Strict`. See [https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies](MDN) for more details. This means that we can only support loading via iframes via https or localhost.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Embed into an existing page
|
|
48
|
+
|
|
49
|
+
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.
|