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.
- 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 +765 -0
- solara/_stores.py +297 -0
- solara/alias.py +6 -0
- solara/autorouting.py +555 -0
- solara/cache.py +305 -0
- solara/checks.html +71 -0
- solara/checks.py +227 -0
- solara/comm.py +28 -0
- solara/components/__init__.py +77 -0
- solara/components/alert.py +155 -0
- solara/components/applayout.py +397 -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 +134 -0
- solara/components/cross_filter.py +335 -0
- solara/components/dataframe.py +546 -0
- solara/components/datatable.py +214 -0
- solara/components/datatable.vue +175 -0
- solara/components/details.py +56 -0
- solara/components/download.vue +35 -0
- solara/components/echarts.py +86 -0
- solara/components/echarts.vue +139 -0
- solara/components/figure_altair.py +39 -0
- solara/components/file_browser.py +181 -0
- solara/components/file_download.py +199 -0
- solara/components/file_drop.py +159 -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 +456 -0
- solara/components/input_text_area.py +86 -0
- solara/components/link.py +55 -0
- solara/components/markdown.py +441 -0
- solara/components/markdown_editor.py +33 -0
- solara/components/markdown_editor.vue +359 -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 +45 -0
- solara/components/sql_code.py +41 -0
- solara/components/sql_code.vue +125 -0
- solara/components/style.py +105 -0
- solara/components/switch.py +71 -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/core.py +42 -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 +151 -0
- solara/hooks/use_thread.py +129 -0
- solara/kitchensink.py +8 -0
- solara/lab/__init__.py +34 -0
- solara/lab/components/__init__.py +7 -0
- solara/lab/components/chat.py +215 -0
- solara/lab/components/confirmation_dialog.py +163 -0
- solara/lab/components/cross_filter.py +7 -0
- solara/lab/components/input_date.py +339 -0
- solara/lab/components/input_time.py +133 -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 +2 -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 +165 -0
- solara/lab/utils/headers.py +5 -0
- solara/layout.py +44 -0
- solara/lifecycle.py +46 -0
- solara/minisettings.py +141 -0
- solara/py.typed +0 -0
- solara/reactive.py +99 -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 +527 -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 +1681 -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 +91 -0
- solara/server/esm.py +71 -0
- solara/server/fastapi.py +5 -0
- solara/server/flask.py +297 -0
- solara/server/jupyter/__init__.py +2 -0
- solara/server/jupyter/cdn_handler.py +28 -0
- solara/server/jupyter/server_extension.py +40 -0
- solara/server/jupyter/solara.py +91 -0
- solara/server/jupytertools.py +46 -0
- solara/server/kernel.py +388 -0
- solara/server/kernel_context.py +467 -0
- solara/server/patch.py +564 -0
- solara/server/pyinstaller/__init__.py +9 -0
- solara/server/pyinstaller/hook-ipyreact.py +5 -0
- solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
- solara/server/pyinstaller/hook-solara.py +9 -0
- solara/server/qt.py +113 -0
- solara/server/reload.py +251 -0
- solara/server/server.py +484 -0
- solara/server/settings.py +249 -0
- solara/server/shell.py +269 -0
- solara/server/starlette.py +770 -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 +272 -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 +486 -0
- solara/server/threaded.py +84 -0
- solara/server/utils.py +44 -0
- solara/server/websocket.py +45 -0
- solara/settings.py +86 -0
- solara/tasks.py +893 -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 +783 -0
- solara/toestand.py +998 -0
- solara/util.py +348 -0
- solara/validate_hooks.py +258 -0
- solara/website/__init__.py +0 -0
- solara/website/assets/custom.css +444 -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.py +6 -0
- solara/website/components/algolia.vue +24 -0
- solara/website/components/algolia_api.vue +202 -0
- solara/website/components/breadcrumbs.py +28 -0
- solara/website/components/contact.py +144 -0
- solara/website/components/docs.py +143 -0
- solara/website/components/header.py +75 -0
- solara/website/components/mailchimp.py +12 -0
- solara/website/components/mailchimp.vue +47 -0
- solara/website/components/markdown.py +99 -0
- solara/website/components/markdown_nav.vue +34 -0
- solara/website/components/notebook.py +171 -0
- solara/website/components/sidebar.py +105 -0
- solara/website/pages/__init__.py +370 -0
- solara/website/pages/about/__init__.py +9 -0
- solara/website/pages/about/about.md +3 -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/careers/__init__.py +27 -0
- solara/website/pages/changelog/__init__.py +10 -0
- solara/website/pages/changelog/changelog.md +372 -0
- solara/website/pages/contact/__init__.py +34 -0
- solara/website/pages/doc_use_download.py +85 -0
- solara/website/pages/documentation/__init__.py +90 -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 +417 -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 +50 -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 +72 -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 +192 -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 +256 -0
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +108 -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 +7 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +187 -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 +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +20 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +20 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +20 -0
- solara/website/pages/documentation/api/hooks/__init__.py +9 -0
- solara/website/pages/documentation/api/hooks/use_cross_filter.py +23 -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 +31 -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 +30 -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 +66 -0
- solara/website/pages/documentation/api/hooks/use_thread.md +64 -0
- solara/website/pages/documentation/api/hooks/use_thread.py +42 -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 +29 -0
- solara/website/pages/documentation/api/routing/use_route.py +76 -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 +44 -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 +25 -0
- solara/website/pages/documentation/components/advanced/meta.py +17 -0
- solara/website/pages/documentation/components/advanced/style.py +43 -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 +30 -0
- solara/website/pages/documentation/components/input/file_drop.py +76 -0
- solara/website/pages/documentation/components/input/input.py +43 -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/input_time.py +15 -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 +74 -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 +66 -0
- solara/website/pages/documentation/components/layout/details.py +13 -0
- solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
- solara/website/pages/documentation/components/layout/gridfixed.py +19 -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 +19 -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 +83 -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 +15 -0
- solara/website/pages/documentation/components/page/title.py +25 -0
- solara/website/pages/documentation/components/status/__init__.py +9 -0
- solara/website/pages/documentation/components/status/error.py +39 -0
- solara/website/pages/documentation/components/status/info.py +39 -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 +77 -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 +54 -0
- solara/website/pages/documentation/examples/ai/__init__.py +11 -0
- solara/website/pages/documentation/examples/ai/chatbot.py +113 -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 +32 -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 +65 -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 +62 -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 +67 -0
- solara/website/pages/documentation/examples/visualization/linked_views.py +81 -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 +112 -0
- solara/website/pages/documentation/getting_started/__init__.py +9 -0
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +107 -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 +65 -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 +1021 -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 +228 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +278 -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 +305 -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/home.vue +1199 -0
- solara/website/pages/our_team/__init__.py +83 -0
- solara/website/pages/pricing/__init__.py +31 -0
- solara/website/pages/roadmap/__init__.py +11 -0
- solara/website/pages/roadmap/roadmap.md +47 -0
- solara/website/pages/scale_ipywidgets.py +45 -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 +107 -0
- solara/widgets/vue/html.vue +4 -0
- solara/widgets/vue/navigator.vue +134 -0
- solara/widgets/vue/vegalite.vue +130 -0
- solara/widgets/widgets.py +74 -0
- solara_ui-1.45.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- solara_ui-1.45.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara_ui-1.45.0.dist-info/METADATA +162 -0
- solara_ui-1.45.0.dist-info/RECORD +464 -0
- solara_ui-1.45.0.dist-info/WHEEL +4 -0
- solara_ui-1.45.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installing Solara
|
|
3
|
+
description: Installation should be as easy as running pip install Solara. Read on for advanced setups.
|
|
4
|
+
---
|
|
5
|
+
# Installation
|
|
6
|
+
|
|
7
|
+
## Create a virtual environment
|
|
8
|
+
|
|
9
|
+
It is best to install Solara into a virtual environment unless you know what you are doing (you already have a virtual environment, or you are using conda or docker).
|
|
10
|
+
|
|
11
|
+
See also [The Python Packaging User Guide](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) for more information about virtual environments.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### OSX/Unix/Linux
|
|
15
|
+
|
|
16
|
+
Setting up a virtual environment on OSX/Unix/Linux:
|
|
17
|
+
|
|
18
|
+
$ python -m venv solara-env
|
|
19
|
+
$ source ./solara-env/bin/activate
|
|
20
|
+
|
|
21
|
+
### Windows
|
|
22
|
+
|
|
23
|
+
Setting up a virtual environment on Windows:
|
|
24
|
+
|
|
25
|
+
> py -m venv solara-env
|
|
26
|
+
> solara-env\Scripts\activate
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Install Solara as a user
|
|
30
|
+
|
|
31
|
+
Now install Solara using pip:
|
|
32
|
+
|
|
33
|
+
$ pip install solara
|
|
34
|
+
|
|
35
|
+
## Bleeding edge
|
|
36
|
+
|
|
37
|
+
If you want to install an unreleased version of Solara (e.g. because we just merged a feature you need)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
$ pip install "solara @ git+https://github.com/widgetti/solara"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or put the following in your `requirements.txt`:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
solara @ https://github.com/widgetti/solara/package/archive/master.tar.gz
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If you want to do development on Solara, read the [development documentation](/documentation/advanced/development/setup).
|
|
52
|
+
|
|
53
|
+
## Air-gapped installation / Firewalled network
|
|
54
|
+
|
|
55
|
+
If you want to have Solara running in an air-gapped environment or where access to a CDN is not possible due to firewall rules, you have two options
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Pre-install assets
|
|
59
|
+
|
|
60
|
+
Normally, Solara fetches assets (CSS, JavaScript and fonts) from a CDN on the fly, if that is not possible, you can pre-install the assets by running
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
$ pip install "solara[assets]"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Airgapped install
|
|
67
|
+
|
|
68
|
+
If you cannot install `solara` or `solara-assets` from pypi because the server is not connected to the internet, you can
|
|
69
|
+
follow the following steps to install Solara:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Download the required wheels from pypi.
|
|
73
|
+
$ pip wheel --wheel-dir solara-air-gapped "solara[assets]"
|
|
74
|
+
# Zip them in a tarball.
|
|
75
|
+
$ tar zcfv solara-air-gapped.tar.gz solara-air-gapped
|
|
76
|
+
# Copy the tarball to your server.
|
|
77
|
+
$ scp solara-air-gapped.tar.gz yourusername@youmachine:~/solara-air-gapped.tar.gz
|
|
78
|
+
# ssh into your server.
|
|
79
|
+
$ ssh yourusername@yourmachine
|
|
80
|
+
...
|
|
81
|
+
# Unzip the tarball.
|
|
82
|
+
$ tar zxfv solara-air-gapped.tar.gz
|
|
83
|
+
# Install all wheels.
|
|
84
|
+
$ pip install solara-air-gapped/*.whl
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Solara subpackages
|
|
88
|
+
|
|
89
|
+
The `solara` package is a meta package that installs all the necessary dependencies to get started with Solara. By default, we install:
|
|
90
|
+
|
|
91
|
+
* [`pip install "solara-ui[all]"`](https://pypi.org/project/solara-ui)
|
|
92
|
+
* [`pip install "solara-server[starlette,dev]"`](https://pypi.org/project/solara-ui)
|
|
93
|
+
|
|
94
|
+
Note that the solara (meta) package will pin exact versions of solara-ui and solara-server, which ensures you always get compatible version of the subpackages.
|
|
95
|
+
For more flexibility, and control over what you install, you can install the subpackages directly.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
### The `solara-ui` package
|
|
99
|
+
|
|
100
|
+
This package contains only the UI components, hooks and other utilities. This is the only package you need if you want to use Solara in a Jupyter environment. There are optional dependencies giving you
|
|
101
|
+
more control over what you want to install:
|
|
102
|
+
|
|
103
|
+
* `pip install "solara-ui"` - Only the UI components, hooks and other utilities.
|
|
104
|
+
* `pip install "solara-ui[markdown]"` - The above, with support for markdown rendering.
|
|
105
|
+
* `pip install "solara-ui[cache]"` - The above, with support for [caching](https://solara.dev/docs/reference/caching)
|
|
106
|
+
* `solara-ui[all]` - Installs all optional dependencies.
|
|
107
|
+
|
|
108
|
+
### The `solara-server` package
|
|
109
|
+
|
|
110
|
+
This will let you run solara applications outside a Jupyter server. See [Understanding Solara Server](https://solara.dev/documentation/advanced/understanding/solara-server) for more details about solara server.
|
|
111
|
+
|
|
112
|
+
For deployments, we recommend ``pip install "solara-server[starlette]"` which will install the starlette backend for solara server. For development, you can install the `dev` extra to get the development dependencies that enabled hot reloading.
|
|
113
|
+
|
|
114
|
+
The `solara-server` packages supports the following optional dependencies:
|
|
115
|
+
|
|
116
|
+
* `pip install "solara-server"` - Only the solara server code with required dependencies, this in general is not a functional server (it needs starlette or flask to run).
|
|
117
|
+
* `pip install "solara-server[starlette]"` - The solara server with the starlette backend.
|
|
118
|
+
* `pip install "solara-server[flask]"` - The solara server with the starlette backend and development dependencies.
|
|
119
|
+
* `pip install "solara-server[dev]"` - The solara server with dependencies for development for enabling hot reloading.
|
|
120
|
+
* `pip install "solara-server[all]"` - Installs all optional dependencies.
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
### The `pytest-ipywidgets` package
|
|
126
|
+
|
|
127
|
+
This package is a plugin for pytest that lets you test ipywidgets with playwright. It is useful for testing your ipywidgets or solara applications in a (headless) browser.
|
|
128
|
+
See [Our testing documentation](https://solara.dev/documentation/advanced/howto/testing) for more information.
|
|
129
|
+
|
|
130
|
+
* `pip install "pytest-ipywidgets"` - Minimal installation for testing ipywidgets.
|
|
131
|
+
* `pip install "pytest-ipywidgets[voila]"` - The above, with a compatible version of voila.
|
|
132
|
+
* `pip install "pytest-ipywidgets[jupyterlab]"` - The above, with a compatible version of jupyterlab.
|
|
133
|
+
* `pip install "pytest-ipywidgets[notebook]"` - The above, with a compatible version of notebook.
|
|
134
|
+
* `pip install "pytest-ipywidgets[all]"` - Installs all optional dependencies.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Solara Tutorials
|
|
3
|
+
description: A collection of tutorials for those learning to use Solara, each geared towards a users coming from particular backgrounds, such as data science, or
|
|
4
|
+
users coming from other frameworks like Streamlit.
|
|
5
|
+
---
|
|
6
|
+
# Tutorials
|
|
7
|
+
|
|
8
|
+
Instead of having one tutorial, we have tutorials for different audiences.
|
|
9
|
+
|
|
10
|
+
* [Jupyter Dashboard](/documentation/getting_started/tutorials/jupyter-dashboard-part1): Learn to create a dashboard in the Jupyter notebook.
|
|
11
|
+
* [Data science](/documentation/getting_started/tutorials/data-science): In this tutorial, we will introduce Solara from the perspective of a data scientist or when you are thinking of using Solara for a data science app.
|
|
12
|
+
* [Web app](/documentation/getting_started/tutorials/web-app): You are not a data scientist, but you are interested in using Solara to create a web app using Pure Python.
|
|
13
|
+
* [IPywidgets user](/documentation/getting_started/tutorials/ipywidgets): If you are already using [ipywidgets](/documentation/advanced/understanding/ipywidgets) you will learn how to use the [Solara server](/documentation/advanced/understanding/solara-server) to render your regular ipywidget applications.
|
|
14
|
+
* [Streamlit](/documentation/getting_started/tutorials/streamlit): If you are an existing Streamlit user, this might appeal more to you.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import solara
|
|
4
|
+
import solara.components.applayout
|
|
5
|
+
from solara.website.components.notebook import Notebook
|
|
6
|
+
|
|
7
|
+
HERE = Path(__file__).parent
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@solara.component
|
|
11
|
+
def Page():
|
|
12
|
+
# only execute once, other
|
|
13
|
+
Notebook(HERE / "_data_science.ipynb")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tutorial - Building web apps in python using Solara
|
|
3
|
+
description: In this tutorial, you will learn how to use Solara to create a tiny web app using only Python. You can run these apps using either Solara server,
|
|
4
|
+
Jupyter lab / notebook, or whatever server infrastructure you prefer.
|
|
5
|
+
---
|
|
6
|
+
# Tutorial: Web app
|
|
7
|
+
|
|
8
|
+
In this tutorial, you will learn how to use Solara to create a tiny web app using only Python.
|
|
9
|
+
|
|
10
|
+
## You should know
|
|
11
|
+
This tutorial will assume you have successfully installed Solara.
|
|
12
|
+
|
|
13
|
+
If not, please follow the [Installation guide](/documentation/getting_started/installing).
|
|
14
|
+
|
|
15
|
+
## Generate a script file
|
|
16
|
+
The simplest way to get started is to run the command
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ solara create button
|
|
20
|
+
Wrote: /Users/maartenbreddels/github/widgetti/solara/sol.py
|
|
21
|
+
Run as:
|
|
22
|
+
$ solara run /Users/maartenbreddels/github/widgetti/solara/sol.py
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This will create the `sol.py` file with the following content.
|
|
26
|
+
```solara
|
|
27
|
+
import solara
|
|
28
|
+
|
|
29
|
+
clicks = solara.reactive(0)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@solara.component
|
|
33
|
+
def Page():
|
|
34
|
+
color = "green"
|
|
35
|
+
if clicks.value >= 5:
|
|
36
|
+
color = "red"
|
|
37
|
+
|
|
38
|
+
def increment():
|
|
39
|
+
clicks.value += 1
|
|
40
|
+
print("clicks", clicks)
|
|
41
|
+
|
|
42
|
+
solara.Button(label=f"Clicked: {clicks}", on_click=increment, color=color)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Run the script
|
|
47
|
+
|
|
48
|
+
Using [Solara server](/documentation/advanced/understanding/solara-server), we can now run our Python script using:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
$ solara run sol.py
|
|
52
|
+
Solara server is starting at http://localhost:8765
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you open the URL in your browser ([or click here](http://localhost:8765)), you should see the same example as above.
|
|
56
|
+
|
|
57
|
+
Solara will run your script once, and will look for the `Page` component. Solara expects this component to exist
|
|
58
|
+
and be a [Reacton](/documentation/advanced/understanding/reacton) component. (See the [IPywidget tutorial](/documentation/getting_started/tutorials/ipywidgets) to learn how to render a regular ipywidget).
|
|
59
|
+
|
|
60
|
+
Since your script is only run once, you could put in the main body of your script code that only needs to run once (e.g. loading data from disk)
|
|
61
|
+
|
|
62
|
+
Every browser/user that connects will get an independent version of the state (in this case the number of clicks), so
|
|
63
|
+
you do not share the number of clicks with other people.
|
|
64
|
+
|
|
65
|
+
## Modify the script
|
|
66
|
+
|
|
67
|
+
Lets modify the script a little bit, possibly in this way:
|
|
68
|
+
|
|
69
|
+
```diff
|
|
70
|
+
- solara.Button(label=f"Clicked: {clicks}", on_click=increment, color=color)
|
|
71
|
+
+ label = "Not clicked yet" if clicks.value == 0 else f"Clicked: {clicks}"
|
|
72
|
+
+ solara.Button(label=label, on_click=increment, color=color)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If we save the script, Solara will automatically reload your script and update
|
|
76
|
+
your browser (we call this feature [hot reloading](/documentation/advanced/reference/reloading)).
|
|
77
|
+
|
|
78
|
+
Note that Solara will remember your state (e.g., the number of buttons clicked) when the app reloads.
|
|
79
|
+
|
|
80
|
+
(*Note: Upgrade to solara 1.14.0 for a fix in hot reloading using `pip install "solara>=1.14.0"`*)
|
|
81
|
+
|
|
82
|
+
## What you have learned
|
|
83
|
+
|
|
84
|
+
* How to create a Python script `sol.py` by running `solara create button`
|
|
85
|
+
* How to run the script with Solara server by running `solara run sol.py`
|
|
86
|
+
* Your script is executed once, which is useful for loading data in the main body of your script only once.
|
|
87
|
+
* Your script should have a component called `Page`.
|
|
88
|
+
* Every user has its own state (in the above example, the number of clicks)
|
|
89
|
+
* If you save your script, Solara will automatically re-execute your script, and all attached users will see the changes directly (hot reloading).
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tutorial - Building ipywidgets based apps
|
|
3
|
+
description: Ipywidgets can be used together with Solara to build and quickly get to users your data apps or dashboards.
|
|
4
|
+
---
|
|
5
|
+
# Tutorial: IPywidgets
|
|
6
|
+
|
|
7
|
+
If you are already using [ipywidgets](/documentation/advanced/understanding/ipywidgets) in the notebook, possibly using [Voila](/documentation/advanced/understanding/voila), you might be pleased to know that you
|
|
8
|
+
can also use the [Solara server](/documentation/advanced/understanding/solara-server) to render your regular ipywidget application.
|
|
9
|
+
|
|
10
|
+
We recommend you learn how to write applications using [Reacton](/documentation/advanced/understanding/reacton). However, if you have already written an application in
|
|
11
|
+
pure [ipywidgets](/documentation/advanced/understanding/ipywidgets), this approach will let you gradually move from pure ipywidgets to Reacton.
|
|
12
|
+
|
|
13
|
+
## You should know
|
|
14
|
+
This tutorial will assume you have successfully installed Solara.
|
|
15
|
+
|
|
16
|
+
If not, please follow the [Installation guide](/documentation/getting_started/installing).
|
|
17
|
+
|
|
18
|
+
## Your first ipywidget based Solara app
|
|
19
|
+
|
|
20
|
+
Put the following code in a file called `sol-ipywidgets.py`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import ipywidgets as widgets
|
|
24
|
+
|
|
25
|
+
clicks = 0
|
|
26
|
+
|
|
27
|
+
print("I get run at startup, and for every page request")
|
|
28
|
+
|
|
29
|
+
def on_click(button):
|
|
30
|
+
global clicks
|
|
31
|
+
clicks += 1
|
|
32
|
+
button.description = f"Clicked {clicks} times"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
button = widgets.Button(description="Clicked 0 times")
|
|
36
|
+
button.on_click(on_click)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
And run the following command in your shell
|
|
40
|
+
```bash
|
|
41
|
+
$ solara run sol-ipywidgets.py:button
|
|
42
|
+
Solara server is starting at http://localhost:8765
|
|
43
|
+
I get run at startup, and for every page request
|
|
44
|
+
...
|
|
45
|
+
# your browser opens http://localhost:8765
|
|
46
|
+
I get run at startup, and for every page request
|
|
47
|
+
...
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The Solara server will execute your script once before any browser connects,
|
|
51
|
+
as demonstrated by the `"I get run at startup, and for every page request"` output.
|
|
52
|
+
|
|
53
|
+
The `:button` part on the command line tells the Solara server the variable name of
|
|
54
|
+
the widget it should render. The default name for a widget variable Solara will look
|
|
55
|
+
for is `page`.
|
|
56
|
+
|
|
57
|
+
For every page request (for instance, you open a second tab, or do a page refresh)
|
|
58
|
+
you will see the same text printed out in the terminal.
|
|
59
|
+
This tell you that each "tab" gets its own run, and its own namespace, which means
|
|
60
|
+
that the `clicks` variable is not shared between multiple users.
|
|
61
|
+
|
|
62
|
+
If you refresh the page, the script is executed again, and the `clicks` is set to
|
|
63
|
+
`0` again.
|
|
64
|
+
|
|
65
|
+
## Hot reloading
|
|
66
|
+
|
|
67
|
+
If you edit your script, and save it, Solara server will re-execute it for all connected users without you having to manually refresh your browser.
|
|
68
|
+
|
|
69
|
+
Try making the following code change (remove the first, add the last), and watch your browser page instantly refresh.
|
|
70
|
+
```diff
|
|
71
|
+
- button = widgets.Button(description="Clicked 0 times")
|
|
72
|
+
+ button = widgets.Button(description="Did not click yet!")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Using Solara components
|
|
76
|
+
|
|
77
|
+
There are a lot of [valuable components in Solara](/documentation/components), but they are written as [Reacton/Solara components](/documentation/advanced/understanding/reacton-basics), not
|
|
78
|
+
classic ipywidgets.
|
|
79
|
+
|
|
80
|
+
Use the [.widget(...)](/documentation/api/utilities/widget) method on a component to create a widget that can be used in your existing classic ipywidget application.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
|
|
84
|
+
import ipywidgets as widgets
|
|
85
|
+
|
|
86
|
+
import solara
|
|
87
|
+
|
|
88
|
+
clicks = 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def on_click(button):
|
|
92
|
+
global clicks
|
|
93
|
+
clicks += 1
|
|
94
|
+
button.description = f"Clicked {clicks} times"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
button = widgets.Button(description="Clicked 0 times")
|
|
98
|
+
button.on_click(on_click)
|
|
99
|
+
|
|
100
|
+
page = widgets.VBox(
|
|
101
|
+
[
|
|
102
|
+
button,
|
|
103
|
+
# using .widget(..) we can create a classic ipywidget from a solara component
|
|
104
|
+
solara.FileDownload.widget(data="some text data", filename="solara-demo.txt"),
|
|
105
|
+
]
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Now we can run this app using:
|
|
110
|
+
```
|
|
111
|
+
$ solara run sol-ipywidgets.py
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Note that we did not include the `:page` here, since solara will automatically look for that.
|
|
115
|
+
|
|
116
|
+
## What you have learned
|
|
117
|
+
|
|
118
|
+
* [Solara server](/documentation/advanced/understanding/solara-server) can render [ipywidgets](/documentation/advanced/understanding/ipywidgets).
|
|
119
|
+
* Running `$ solara run filename.py:variablename` tells Solara which script to execute and which variable name from the script to render.
|
|
120
|
+
* The script is executed:
|
|
121
|
+
* Once, when the solara server starts.
|
|
122
|
+
* On each page request.
|
|
123
|
+
* For each open browser page/tab, when the script is saved (hot reloading).
|
|
124
|
+
* Using the [.widget(...)](/documentation/api/utilities/widget) method we can start using Solara components in classic ipywidget app.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Using Solara as a more scalable alternative to Streamlit
|
|
3
|
+
description: If you are coming from Streamlit, it should be simple to adapt to using Solara, and take advantage of partial re-execution, state
|
|
4
|
+
management, and reusable components.
|
|
5
|
+
---
|
|
6
|
+
# Tutorial: Streamlit
|
|
7
|
+
|
|
8
|
+
If you are coming from [Streamlit](https://streamlit.io/) you may be happy to know Solara does not re-execute your whole script. We execute components (starting with the `Page` component), and only need to re-execute what needs to.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Streamlit example
|
|
12
|
+
Let us start with a typical streamlit example:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import streamlit as st
|
|
16
|
+
|
|
17
|
+
with st.sidebar:
|
|
18
|
+
st.markdown("## My First Solara tutorial ☀️")
|
|
19
|
+
x = st.slider("x")
|
|
20
|
+
x_squared = x**2
|
|
21
|
+
st.markdown(f"{x} squared = {x_squared}")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Translated to Solara
|
|
25
|
+
|
|
26
|
+
We now translate this to the equivalent in Solara. The largest difference is we need to explicitly create (application) state using [`solara.reactive`](/documentation/api/utilities/reactive). By passing the
|
|
27
|
+
reactive variable to the [SliderInt](/documentation/components/input/slider) via `value=x` we set up a two way binding between the component and the reactive variable. The generated text is passed down to the [Markdown](/documentation/components/output/markdown) component.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
```solara
|
|
31
|
+
import solara
|
|
32
|
+
|
|
33
|
+
x = solara.reactive(2)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@solara.component
|
|
37
|
+
def Page():
|
|
38
|
+
x_squared = x.value**2
|
|
39
|
+
|
|
40
|
+
with solara.Sidebar():
|
|
41
|
+
solara.Markdown("## My First Solara app ☀️")
|
|
42
|
+
solara.SliderInt(label="x", value=x)
|
|
43
|
+
solara.Markdown(f"{x.value} squared = {x_squared}")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Running this example using Solara server
|
|
47
|
+
|
|
48
|
+
If you put this script in a file called `sol.py` and run
|
|
49
|
+
```
|
|
50
|
+
$ solara run sol.py
|
|
51
|
+
```
|
|
52
|
+
You will see:
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
Because we do some styling and because the sidebar is already used up, our preview on this page looks slightly different.
|
|
56
|
+
|
|
57
|
+
[Navigate to /apps/tutorial-streamlit](/apps/tutorial-streamlit) to see this app fullscreen.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Running this example in the notebook
|
|
61
|
+
|
|
62
|
+
If you add the above code snippet to your notebook, and include `Page()` at the end of your notebook cell, you should see:
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
Again, slightly different for a different environment.
|
|
66
|
+
|
|
67
|
+
## Hot reloading
|
|
68
|
+
|
|
69
|
+
If you are using [Solara server](/documentation/advanced/understanding/solara-server), try editing `sol.py`, and watch the page reload automatically after you save your file. Notebook users can simply edit and re-run.
|
|
70
|
+
|
|
71
|
+
(*Note: Upgrade to solara 1.14.0 for a fix in hot reloading using `pip install "solara>=1.14.0"`*)
|
|
72
|
+
|
|
73
|
+
## How are streamlit and Solara different?
|
|
74
|
+
|
|
75
|
+
### Execution model
|
|
76
|
+
As the introduction says, Solara does not re-execute your whole script after user interactions.
|
|
77
|
+
The main script is executed only once. With Solara you can use your main script to read large dataframes, or do some pre-calculations without the need for [caching](/documentation/advanced/reference/caching).
|
|
78
|
+
|
|
79
|
+
When a user navigates to a Solara server, the `Page` component (basically a function) will get executed. The `Page` component will call (lazily) new components like [solara.Markdown](/documentation/components/output/markdown) to build up the page. If state changes due to user input, Solara will trigger a cascade of re-excecutions of components which inputs or state changed, but never your whole script, nor every component.
|
|
80
|
+
|
|
81
|
+
### State
|
|
82
|
+
With Solara (and [Reacton](/documentation/advanced/understanding/reacton)) state does not live in a UI component (like a slider). Application state created with [`solara.reactive`](/documentation/api/utilities/reactive) lives on its own. Connecting the state to the UI component (in this case a slider) is a separate step, done via `value=x` in the above example. In general we recommend organising your components
|
|
83
|
+
similarly as in the example: [First use_state and other hooks, then calculations, at last the UI components](/documentation/advanced/understanding/anatomy).
|
|
84
|
+
|
|
85
|
+
For complex situations, it is important to separate the state and the UI. Especially when you need the state of a UI component as input of the UI component itself, you can get stuck with streamlit. In Solara this follows naturally.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Creating a reusable component
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
A big advantage of Solara is that you can create reusable components. A single component can be seen as the equivalent of a single streamlit script. However, in that case, we need to modify our component to have its own state, rather than using global application state, for this you can use the [`use_reactive`](/documentation/api/hooks/use_reactive), or [`use_state`](/documentation/api/hooks/use_state) hook.
|
|
92
|
+
Read more about state management in the [state management](/documentation/getting_started/fundamentals/state-management) section.
|
|
93
|
+
|
|
94
|
+
```solara
|
|
95
|
+
import solara
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@solara.component
|
|
99
|
+
def Square(name: str):
|
|
100
|
+
# x = solara.use_reactive(2) # another possibility
|
|
101
|
+
x, set_x = solara.use_state(2)
|
|
102
|
+
y = x**2
|
|
103
|
+
with solara.Sidebar():
|
|
104
|
+
solara.SliderInt(label=name, value=x, on_value=set_x)
|
|
105
|
+
solara.Markdown(f'{name}: {x} squared = {y}')
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@solara.component
|
|
109
|
+
def Page():
|
|
110
|
+
Square('a')
|
|
111
|
+
Square('b')
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
In this example, each instance of the `Square` component, calls `use_state`, and therefore has its own private
|
|
115
|
+
x variable. Truly reusable UI components!
|
|
116
|
+
|
|
117
|
+
In streamlit, this is trickier. While this would work:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import streamlit as st
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def square(name):
|
|
124
|
+
with st.sidebar:
|
|
125
|
+
x = st.slider(name)
|
|
126
|
+
x_squared = x**2
|
|
127
|
+
st.markdown(f"{name}: {x} squared = {x_squared}")
|
|
128
|
+
|
|
129
|
+
square("x")
|
|
130
|
+
square("y")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Changing that "y" to "x" will lead to an error, however. If this is a problem in practice depends on the situation.
|
|
134
|
+
|
|
135
|
+
### Long running function
|
|
136
|
+
|
|
137
|
+
In Streamlit, it is normal for your main script to block execution. In Solara, the functions bodies of your components ([called render functions](/documentation/advanced/understanding/anatomy)) should not block. Functions that block, or take a long time to execute, should be executed in a thread, such that rendering can continue. Using threads may sound scary, but using the
|
|
138
|
+
[use_thread](/documentation/api/hooks/use_thread) hook will help a lot.
|
|
139
|
+
|
|
140
|
+
## What you have learned
|
|
141
|
+
|
|
142
|
+
* Solara will not continuously re-execute your script as Streamlit does.
|
|
143
|
+
* Solara will re-execute components instead, only what needs to.
|
|
144
|
+
* State in Solara is separate from the UI components, unlike streamlit, where they are strongly linked.
|
|
145
|
+
* State can be on the application level (global) for simplicity or on the component level (local) for creating reusable components.
|
|
146
|
+
* Solara should not block the render loop. Long-running functions should be executed in a thread using [use_thread](/documentation/api/hooks/use_thread).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Using Solara as an alternative to Dash
|
|
3
|
+
description: If you are familiar with Dash, Solara should be easy to adapt to. In Solara the state is managed and stored on the server, and components are declaratively reusable.
|
|
4
|
+
---
|
|
5
|
+
# Tutorial: Dash users
|
|
6
|
+
|
|
7
|
+
Dash is quite different from Solara. In Dash, state lives in your browser, and via callbacks your app will change from 1 state to another. In Solara, the state lives on the server, and also state transitions happen at the server.
|
|
8
|
+
|
|
9
|
+
## Dash example
|
|
10
|
+
To see how Dash and Solara are different, let us start with a typical Dash example:
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from dash import Dash, Input, Output, callback, dcc, html
|
|
14
|
+
|
|
15
|
+
app = Dash(__name__)
|
|
16
|
+
|
|
17
|
+
app.layout = html.Div(
|
|
18
|
+
children=[
|
|
19
|
+
dcc.Dropdown(id="dropdown", options=["red", "green", "blue", "orange"]),
|
|
20
|
+
dcc.Markdown(id="markdown", children=["## Hello World"]),
|
|
21
|
+
]
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@callback(
|
|
26
|
+
Output("markdown", "style"),
|
|
27
|
+
Input("dropdown", "value"),
|
|
28
|
+
)
|
|
29
|
+
def update_markdown_style(color):
|
|
30
|
+
return {"color": color}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
app.run_server(debug=True)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
*This example is inspired on [a dash example](https://dash.plotly.com/all-in-one-components).*
|
|
38
|
+
|
|
39
|
+
This small app creates a dropdown (what we call Select in Solara), and some markdown text. The dropdown will trigger the callback at the server, which will update the markdown's style, which will cause the color of the text to change.
|
|
40
|
+
|
|
41
|
+
## Translated to Solara
|
|
42
|
+
|
|
43
|
+
In Solara, we need to explicitly create application state using [`solara.reactive`](/documentation/api/utilities/reactive). We wire this up with the [Select][/documentation/components/input/select] via `value=color` and pass the color value down to the [Markdown](/documentation/components/output/markdown) component.
|
|
44
|
+
|
|
45
|
+
```solara
|
|
46
|
+
import solara
|
|
47
|
+
|
|
48
|
+
color = solara.reactive("red")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@solara.component
|
|
52
|
+
def Page():
|
|
53
|
+
solara.Select(label="Color", values=["red", "green", "blue", "orange"], value=color)
|
|
54
|
+
solara.Markdown("## Hello World", style={"color": color.value})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Since this component combines two components, we have to put them together in a [container](/documentation/advanced/understanding/containers) component, here implicitly a [Column](/documentation/components/layout/column).
|
|
58
|
+
|
|
59
|
+
## Making a reusable component
|
|
60
|
+
|
|
61
|
+
### In dash
|
|
62
|
+
|
|
63
|
+
Following the [All in one component documentation](https://dash.plotly.com/all-in-one-components), we get:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import uuid
|
|
67
|
+
|
|
68
|
+
from dash import MATCH, Dash, Input, Output, State, callback, dcc, html
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class MarkdownWithColorAIO(html.Div):
|
|
72
|
+
class ids:
|
|
73
|
+
dropdown = lambda aio_id: {"component": "MarkdownWithColorAIO", "subcomponent": "dropdown", "aio_id": aio_id}
|
|
74
|
+
markdown = lambda aio_id: {"component": "MarkdownWithColorAIO", "subcomponent": "markdown", "aio_id": aio_id}
|
|
75
|
+
|
|
76
|
+
ids = ids
|
|
77
|
+
|
|
78
|
+
def __init__(self, text, colors=None, markdown_props=None, dropdown_props=None, aio_id=None):
|
|
79
|
+
colors = colors if colors else ["red", "green", "blue", "orange"]
|
|
80
|
+
|
|
81
|
+
if aio_id is None:
|
|
82
|
+
aio_id = str(uuid.uuid4())
|
|
83
|
+
|
|
84
|
+
dropdown_props = dropdown_props.copy() if dropdown_props else {}
|
|
85
|
+
if "options" not in dropdown_props:
|
|
86
|
+
dropdown_props["options"] = [{"label": i, "value": i} for i in colors]
|
|
87
|
+
dropdown_props["value"] = dropdown_props["options"][0]["value"]
|
|
88
|
+
|
|
89
|
+
markdown_props = markdown_props.copy() if markdown_props else {}
|
|
90
|
+
if "style" not in markdown_props:
|
|
91
|
+
markdown_props["style"] = {"color": dropdown_props["value"]}
|
|
92
|
+
if "children" not in markdown_props:
|
|
93
|
+
markdown_props["children"] = text
|
|
94
|
+
super().__init__([dcc.Dropdown(id=self.ids.dropdown(aio_id), **dropdown_props), dcc.Markdown(id=self.ids.markdown(aio_id), **markdown_props)])
|
|
95
|
+
|
|
96
|
+
@callback(
|
|
97
|
+
Output(ids.markdown(MATCH), "style"),
|
|
98
|
+
Input(ids.dropdown(MATCH), "value"),
|
|
99
|
+
State(ids.markdown(MATCH), "style"),
|
|
100
|
+
)
|
|
101
|
+
def update_markdown_style(color, existing_style):
|
|
102
|
+
existing_style["color"] = color
|
|
103
|
+
return existing_style
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
app = Dash(__name__)
|
|
107
|
+
|
|
108
|
+
app.layout = html.Div(
|
|
109
|
+
children=[
|
|
110
|
+
MarkdownWithColorAIO("## Hello World1"),
|
|
111
|
+
MarkdownWithColorAIO("## Hello World2"),
|
|
112
|
+
]
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
app.run_server(debug=True)
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### In Solara
|
|
121
|
+
|
|
122
|
+
A big advantage of Solara is that components are reusable by default. However, we need to modify our component to have its own state, rather than using global application state. Creating local component state with [`use_reactive`](/documentation/api/hooks/use_reactive), or [`use_state`](/documentation/api/hooks/use_state) hook. Read more about state management in the [state management](/documentation/getting_started/fundamentals/state-management) section.
|
|
123
|
+
|
|
124
|
+
We will rename (from `Page` to `MarkdownWithColor`) the component, add local state, and put in the markdown text as an argument.
|
|
125
|
+
|
|
126
|
+
```solara
|
|
127
|
+
import solara
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@solara.component
|
|
131
|
+
def MarkdownWithColor(markdown_text : str):
|
|
132
|
+
# color = solara.use_reactive() # another possibility
|
|
133
|
+
color, set_color = solara.use_state("red") # local state
|
|
134
|
+
solara.Select(label="Color",values=["red", "green", "blue", "orange"],
|
|
135
|
+
value=color, on_value=set_color)
|
|
136
|
+
solara.Markdown(markdown_text, style={"color": color})
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@solara.component
|
|
140
|
+
def Page():
|
|
141
|
+
with solara.Columns():
|
|
142
|
+
MarkdownWithColor("## Reuse is simple")
|
|
143
|
+
MarkdownWithColor("## With solara")
|
|
144
|
+
```
|