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,249 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import importlib
|
|
3
|
+
import re
|
|
4
|
+
import site
|
|
5
|
+
import sys
|
|
6
|
+
import uuid
|
|
7
|
+
import warnings
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional, List
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from filelock import FileLock
|
|
14
|
+
except ModuleNotFoundError:
|
|
15
|
+
FileLock = None # type: ignore
|
|
16
|
+
|
|
17
|
+
import solara.util
|
|
18
|
+
from solara.minisettings import BaseSettings
|
|
19
|
+
|
|
20
|
+
from .. import ( # noqa # sidefx is that this module creates the ~/.solara directory
|
|
21
|
+
settings,
|
|
22
|
+
)
|
|
23
|
+
from ..util import get_solara_home
|
|
24
|
+
|
|
25
|
+
if site.getuserbase() and __file__.startswith(site.getuserbase()):
|
|
26
|
+
prefix = site.getuserbase()
|
|
27
|
+
else:
|
|
28
|
+
prefix = sys.prefix
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ThemeVariant(str, Enum):
|
|
32
|
+
light = "light"
|
|
33
|
+
dark = "dark"
|
|
34
|
+
auto = "auto"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ThemeSettings(BaseSettings):
|
|
38
|
+
variant: ThemeVariant = ThemeVariant.light
|
|
39
|
+
loader: str = "solara"
|
|
40
|
+
show_banner: bool = True
|
|
41
|
+
|
|
42
|
+
class Config:
|
|
43
|
+
env_prefix = "solara_theme_"
|
|
44
|
+
case_sensitive = False
|
|
45
|
+
env_file = ".env"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SSG(BaseSettings):
|
|
49
|
+
# the first app create will initialize this if it is not set
|
|
50
|
+
build_path: Optional[Path] = None
|
|
51
|
+
enabled: bool = False
|
|
52
|
+
headed: bool = False
|
|
53
|
+
|
|
54
|
+
class Config:
|
|
55
|
+
env_prefix = "solara_ssg_"
|
|
56
|
+
case_sensitive = False
|
|
57
|
+
env_file = ".env"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Search(BaseSettings):
|
|
61
|
+
enabled: bool = False
|
|
62
|
+
|
|
63
|
+
class Config:
|
|
64
|
+
env_prefix = "solara_search_"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Telemetry(BaseSettings):
|
|
68
|
+
mixpanel_token: str = "91845eb13a68e3db4e58d64ad23673b7"
|
|
69
|
+
mixpanel_enable: bool = True
|
|
70
|
+
server_user_id: str = "not_set"
|
|
71
|
+
server_fingerprint: str = str(uuid.getnode())
|
|
72
|
+
server_session_id: str = str(uuid.uuid4())
|
|
73
|
+
|
|
74
|
+
class Config:
|
|
75
|
+
env_prefix = "solara_telemetry_"
|
|
76
|
+
case_sensitive = False
|
|
77
|
+
env_file = ".env"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Assets(BaseSettings):
|
|
81
|
+
proxy_cache_dir: Path = Path(prefix + "/share/solara/cdn/")
|
|
82
|
+
fontawesome_enabled: bool = True
|
|
83
|
+
fontawesome_path: str = "/font-awesome@4.5.0/css/font-awesome.min.css"
|
|
84
|
+
extra_locations: List[str] = []
|
|
85
|
+
|
|
86
|
+
def extra_paths(self) -> List[Path]:
|
|
87
|
+
# translate locations (packages, directories) into list of paths
|
|
88
|
+
paths = []
|
|
89
|
+
for location in self.extra_locations:
|
|
90
|
+
if Path(location).exists():
|
|
91
|
+
paths.append(Path(location))
|
|
92
|
+
else:
|
|
93
|
+
try:
|
|
94
|
+
package = importlib.import_module(location)
|
|
95
|
+
except ModuleNotFoundError:
|
|
96
|
+
raise RuntimeError(f"Could not find {location} as a file or package (SOLARA_ASSETS_EXTRA_LOCATION={self.extra_locations!r}) ")
|
|
97
|
+
if not hasattr(package, "__path__"):
|
|
98
|
+
raise RuntimeError(f"{location} is not a package (SOLARA_ASSETS_EXTRA_LOCATION={self.extra_locations!r}) ")
|
|
99
|
+
paths.append(Path(package.__path__[0]))
|
|
100
|
+
return paths
|
|
101
|
+
|
|
102
|
+
class Config:
|
|
103
|
+
env_prefix = "solara_assets_"
|
|
104
|
+
case_sensitive = False
|
|
105
|
+
env_file = ".env"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class Kernel(BaseSettings):
|
|
109
|
+
cull_timeout: str = "24h"
|
|
110
|
+
max_count: Optional[int] = None
|
|
111
|
+
threaded: bool = solara.util.has_threads
|
|
112
|
+
|
|
113
|
+
class Config:
|
|
114
|
+
env_prefix = "solara_kernel_"
|
|
115
|
+
case_sensitive = False
|
|
116
|
+
env_file = ".env"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
AUTH0_TEST_CLIENT_ID = "cW7owP5Q52YHMZAnJwT8FPlH2ZKvvL3U"
|
|
120
|
+
AUTH0_TEST_CLIENT_SECRET = "zxITXxoz54OjuSmdn-PluQgAwbeYyoB7ALlnLoodftvAn81usDXW0quchvoNvUYD"
|
|
121
|
+
AUTH0_TEST_API_BASE_URL = "dev-y02f2bpr8skxu785.us.auth0.com"
|
|
122
|
+
AUTH0_LOGOUT_PATH = "v2/logout"
|
|
123
|
+
|
|
124
|
+
FIEF_TEST_CLIENT_ID = "x2np62qgwp6hnEGTP4JYUE3igdZWhT-AvjpjwwDyKXU"
|
|
125
|
+
FIEF_TEST_CLIENT_SECRET = "XQlByE1pVIz5h2SBN2GYDwT_ziqArHJgLD3KqMlCHjg"
|
|
126
|
+
FIEF_TEST_API_BASE_URL = "solara-dev.fief.dev"
|
|
127
|
+
FIEF_LOGOUT_PATH = "logout"
|
|
128
|
+
SESSION_SECRET_KEY_DEFAULT = "change me"
|
|
129
|
+
|
|
130
|
+
OAUTH_TEST_CLIENT_IDs = [AUTH0_TEST_CLIENT_ID, FIEF_TEST_CLIENT_ID]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class Session(BaseSettings):
|
|
134
|
+
secret_key: str = SESSION_SECRET_KEY_DEFAULT
|
|
135
|
+
http_only: bool = False
|
|
136
|
+
https_only: Optional[bool] = None
|
|
137
|
+
same_site: str = "lax"
|
|
138
|
+
|
|
139
|
+
class Config:
|
|
140
|
+
env_prefix = "solara_session_"
|
|
141
|
+
case_sensitive = False
|
|
142
|
+
env_file = ".env"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class OAuth(BaseSettings):
|
|
146
|
+
private: bool = False
|
|
147
|
+
|
|
148
|
+
client_id: str = AUTH0_TEST_CLIENT_ID
|
|
149
|
+
client_secret: str = AUTH0_TEST_CLIENT_SECRET
|
|
150
|
+
api_base_url: str = AUTH0_TEST_API_BASE_URL
|
|
151
|
+
logout_path: str = AUTH0_LOGOUT_PATH
|
|
152
|
+
scope: str = "openid profile email"
|
|
153
|
+
|
|
154
|
+
class Config:
|
|
155
|
+
env_prefix = "solara_oauth_"
|
|
156
|
+
case_sensitive = False
|
|
157
|
+
env_file = ".env"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
HOST_DEFAULT = os.environ.get("HOST", "localhost")
|
|
161
|
+
is_mac_os_conda = "arm64-apple-darwin" in HOST_DEFAULT
|
|
162
|
+
is_wsl_windows = re.match(r".*?-w1[0-9]", HOST_DEFAULT)
|
|
163
|
+
if is_mac_os_conda or is_wsl_windows:
|
|
164
|
+
HOST_DEFAULT = "localhost"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class Server(BaseSettings):
|
|
168
|
+
ignore_nbextensions: List[str] = []
|
|
169
|
+
|
|
170
|
+
class Config:
|
|
171
|
+
env_prefix = "solara_server_"
|
|
172
|
+
case_sensitive = False
|
|
173
|
+
env_file = ".env"
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class MainSettings(BaseSettings):
|
|
177
|
+
use_pdb: bool = False
|
|
178
|
+
mode: str = "production"
|
|
179
|
+
tracer: bool = False
|
|
180
|
+
timing: bool = False
|
|
181
|
+
root_path: Optional[str] = None # e.g. /myapp (without trailing slash)
|
|
182
|
+
base_url: str = "" # e.g. https://myapp.solara.run/myapp/
|
|
183
|
+
platform: str = sys.platform
|
|
184
|
+
host: str = HOST_DEFAULT
|
|
185
|
+
experimental_performance: bool = False
|
|
186
|
+
|
|
187
|
+
class Config:
|
|
188
|
+
env_prefix = "solara_"
|
|
189
|
+
case_sensitive = False
|
|
190
|
+
env_file = ".env"
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
main = MainSettings()
|
|
194
|
+
server = Server()
|
|
195
|
+
theme = ThemeSettings()
|
|
196
|
+
telemetry = Telemetry()
|
|
197
|
+
ssg = SSG()
|
|
198
|
+
search = Search()
|
|
199
|
+
assets = Assets()
|
|
200
|
+
oauth = OAuth()
|
|
201
|
+
session = Session()
|
|
202
|
+
kernel = Kernel()
|
|
203
|
+
# fail early
|
|
204
|
+
solara.util.parse_timedelta(kernel.cull_timeout)
|
|
205
|
+
|
|
206
|
+
if settings.assets.proxy:
|
|
207
|
+
try:
|
|
208
|
+
assets.proxy_cache_dir.mkdir(exist_ok=True, parents=True)
|
|
209
|
+
except OSError as e:
|
|
210
|
+
settings.assets.proxy = False
|
|
211
|
+
warnings.warn(
|
|
212
|
+
f"Could not create {assets.proxy_cache_dir} due to {e}. We will automatically disable the assets proxy for you. "
|
|
213
|
+
"If you want to disable this warning, set SOLARA_ASSETS_PROXY to False (e.g. export SOLARA_ASSETS_PROXY=false). "
|
|
214
|
+
"Or change the SOLARA_PROXY_CACHE_DIR environment variable to a directory where you have write access."
|
|
215
|
+
)
|
|
216
|
+
# that's ok, the user probably doesn't have permission to create the directory
|
|
217
|
+
# in this case, we would need to install solara-assets?
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
if telemetry.server_user_id == "not_set" and FileLock is not None:
|
|
221
|
+
home = get_solara_home()
|
|
222
|
+
server_user_id_file = home / "server_user_id.txt"
|
|
223
|
+
try:
|
|
224
|
+
with FileLock(str(server_user_id_file) + ".lock"):
|
|
225
|
+
if not server_user_id_file.exists():
|
|
226
|
+
server_user_id_file.write_text(str(uuid.uuid4()))
|
|
227
|
+
telemetry.server_user_id = server_user_id_file.read_text()
|
|
228
|
+
except OSError:
|
|
229
|
+
pass # it's ok
|
|
230
|
+
|
|
231
|
+
if oauth.client_id:
|
|
232
|
+
if oauth.client_id not in OAUTH_TEST_CLIENT_IDs:
|
|
233
|
+
if session.secret_key == SESSION_SECRET_KEY_DEFAULT:
|
|
234
|
+
raise ValueError(
|
|
235
|
+
"You must set a session secret key for oauth, it is not safe to use the default. Please set SOLARA_SESSION_SECRET_KEY in your environment."
|
|
236
|
+
)
|
|
237
|
+
if session.https_only is None:
|
|
238
|
+
raise ValueError(
|
|
239
|
+
"You must set https_only for the session to True (recommended) or False in your are using your own oauth provider."
|
|
240
|
+
"Please set SOLARA_SESSION_HTTPS_ONLY in your environment to True or False"
|
|
241
|
+
)
|
|
242
|
+
else:
|
|
243
|
+
# for the test accounts, this is fine
|
|
244
|
+
if session.https_only is None:
|
|
245
|
+
session.https_only = False
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# call early so a misconfiguration fails early
|
|
249
|
+
assets.extra_paths()
|
solara/server/shell.py
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import io
|
|
3
|
+
import sys
|
|
4
|
+
from binascii import b2a_base64
|
|
5
|
+
from threading import local
|
|
6
|
+
from unittest.mock import Mock
|
|
7
|
+
|
|
8
|
+
import reacton.patch_display
|
|
9
|
+
from IPython.core.displaypub import DisplayPublisher
|
|
10
|
+
from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
|
|
11
|
+
from jupyter_client.session import Session, extract_header
|
|
12
|
+
from traitlets import Any, CBytes, Dict, Instance, Type, default
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def encode_images(obj):
|
|
16
|
+
# no-op in ipykernel
|
|
17
|
+
return obj
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def json_clean(obj):
|
|
21
|
+
# no-op in ipykernel
|
|
22
|
+
return obj
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# based on the zmq display publisher from ipykernel
|
|
26
|
+
# ideally this goes out of ipykernel
|
|
27
|
+
class SolaraDisplayPublisher(DisplayPublisher):
|
|
28
|
+
"""A display publisher that publishes data using a ZeroMQ PUB socket."""
|
|
29
|
+
|
|
30
|
+
session = Instance(Session, allow_none=True)
|
|
31
|
+
pub_socket = Any(allow_none=True)
|
|
32
|
+
parent_header = Dict({})
|
|
33
|
+
topic = CBytes(b"display_data")
|
|
34
|
+
|
|
35
|
+
_thread_local = Any()
|
|
36
|
+
|
|
37
|
+
def set_parent(self, parent):
|
|
38
|
+
"""Set the parent for outbound messages."""
|
|
39
|
+
self.parent_header = extract_header(parent)
|
|
40
|
+
|
|
41
|
+
def _flush_streams(self):
|
|
42
|
+
"""flush IO Streams prior to display"""
|
|
43
|
+
sys.stdout.flush()
|
|
44
|
+
sys.stderr.flush()
|
|
45
|
+
|
|
46
|
+
@default("_thread_local")
|
|
47
|
+
def _default_thread_local(self):
|
|
48
|
+
"""Initialize our thread local storage"""
|
|
49
|
+
return local()
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def _hooks(self):
|
|
53
|
+
if not hasattr(self._thread_local, "hooks"):
|
|
54
|
+
# create new list for a new thread
|
|
55
|
+
self._thread_local.hooks = []
|
|
56
|
+
return self._thread_local.hooks
|
|
57
|
+
|
|
58
|
+
def publish(
|
|
59
|
+
self,
|
|
60
|
+
data,
|
|
61
|
+
metadata=None,
|
|
62
|
+
source=None,
|
|
63
|
+
*, # Enforce keyword-only arguments to match DisplayPublisher.publish
|
|
64
|
+
transient=None,
|
|
65
|
+
update=False,
|
|
66
|
+
**kwargs, # Make sure we're compatible with DisplayPublisher.publish
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Publish a display-data message
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
data : dict
|
|
73
|
+
A mime-bundle dict, keyed by mime-type.
|
|
74
|
+
metadata : dict, optional
|
|
75
|
+
Metadata associated with the data.
|
|
76
|
+
transient : dict, optional, keyword-only
|
|
77
|
+
Transient data that may only be relevant during a live display,
|
|
78
|
+
such as display_id.
|
|
79
|
+
Transient data should not be persisted to documents.
|
|
80
|
+
update : bool, optional, keyword-only
|
|
81
|
+
If True, send an update_display_data message instead of display_data.
|
|
82
|
+
"""
|
|
83
|
+
self._flush_streams()
|
|
84
|
+
if metadata is None:
|
|
85
|
+
metadata = {}
|
|
86
|
+
if transient is None:
|
|
87
|
+
transient = {}
|
|
88
|
+
self._validate_data(data, metadata)
|
|
89
|
+
content = {}
|
|
90
|
+
content["data"] = encode_images(data)
|
|
91
|
+
content["metadata"] = metadata
|
|
92
|
+
content["transient"] = transient
|
|
93
|
+
|
|
94
|
+
msg_type = "update_display_data" if update else "display_data"
|
|
95
|
+
|
|
96
|
+
# Use 2-stage process to send a message,
|
|
97
|
+
# in order to put it through the transform
|
|
98
|
+
# hooks before potentially sending.
|
|
99
|
+
assert self.session is not None
|
|
100
|
+
msg = self.session.msg(msg_type, json_clean(content), parent=self.parent_header)
|
|
101
|
+
|
|
102
|
+
# Each transform either returns a new
|
|
103
|
+
# message or None. If None is returned,
|
|
104
|
+
# the message has been 'used' and we return.
|
|
105
|
+
for hook in self._hooks:
|
|
106
|
+
msg = hook(msg)
|
|
107
|
+
if msg is None:
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
self.session.send(
|
|
111
|
+
self.pub_socket,
|
|
112
|
+
msg,
|
|
113
|
+
ident=self.topic,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def clear_output(self, wait=False):
|
|
117
|
+
"""Clear output associated with the current execution (cell).
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
wait : bool (default: False)
|
|
122
|
+
If True, the output will not be cleared immediately,
|
|
123
|
+
instead waiting for the next display before clearing.
|
|
124
|
+
This reduces bounce during repeated clear & display loops.
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
assert self.session is not None
|
|
128
|
+
content = dict(wait=wait)
|
|
129
|
+
self._flush_streams()
|
|
130
|
+
msg = self.session.msg("clear_output", json_clean(content), parent=self.parent_header)
|
|
131
|
+
for hook in self._hooks:
|
|
132
|
+
msg = hook(msg)
|
|
133
|
+
if msg is None:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
self.session.send(
|
|
137
|
+
self.pub_socket,
|
|
138
|
+
msg,
|
|
139
|
+
ident=self.topic,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def register_hook(self, hook):
|
|
143
|
+
"""
|
|
144
|
+
Registers a hook with the thread-local storage.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
hook : Any callable object
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
Either a publishable message, or `None`.
|
|
153
|
+
The DisplayHook objects must return a message from
|
|
154
|
+
the __call__ method if they still require the
|
|
155
|
+
`session.send` method to be called after transformation.
|
|
156
|
+
Returning `None` will halt that execution path, and
|
|
157
|
+
session.send will not be called.
|
|
158
|
+
"""
|
|
159
|
+
self._hooks.append(hook)
|
|
160
|
+
|
|
161
|
+
def unregister_hook(self, hook):
|
|
162
|
+
"""
|
|
163
|
+
Un-registers a hook with the thread-local storage.
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
hook : Any callable object which has previously been
|
|
168
|
+
registered as a hook.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
bool - `True` if the hook was removed, `False` if it wasn't
|
|
173
|
+
found.
|
|
174
|
+
"""
|
|
175
|
+
try:
|
|
176
|
+
self._hooks.remove(hook)
|
|
177
|
+
return True
|
|
178
|
+
except ValueError:
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class SolaraInteractiveShell(InteractiveShell):
|
|
183
|
+
display_pub_class = Type(SolaraDisplayPublisher)
|
|
184
|
+
history_manager = Any() # type: ignore
|
|
185
|
+
display_pub: SolaraDisplayPublisher
|
|
186
|
+
|
|
187
|
+
def __init__(self, *args, **kwargs):
|
|
188
|
+
super().__init__(*args, **kwargs)
|
|
189
|
+
atexit.unregister(self.atexit_operations)
|
|
190
|
+
|
|
191
|
+
if self.magics_manager:
|
|
192
|
+
magic = self.magics_manager.registry["ScriptMagics"]
|
|
193
|
+
atexit.unregister(magic.kill_bg_processes)
|
|
194
|
+
|
|
195
|
+
def set_parent(self, parent):
|
|
196
|
+
"""Tell the children about the parent message."""
|
|
197
|
+
self.display_pub.set_parent(parent)
|
|
198
|
+
|
|
199
|
+
def init_sys_modules(self):
|
|
200
|
+
pass # don't create a __main__, it will cause a mem leak
|
|
201
|
+
|
|
202
|
+
def init_prefilter(self):
|
|
203
|
+
pass # avoid consuming memory
|
|
204
|
+
|
|
205
|
+
def init_history(self):
|
|
206
|
+
self.history_manager = Mock() # type: ignore
|
|
207
|
+
|
|
208
|
+
def init_display_formatter(self):
|
|
209
|
+
super().init_display_formatter()
|
|
210
|
+
assert self.display_formatter is not None
|
|
211
|
+
self.display_formatter.ipython_display_formatter = reacton.patch_display.ReactonDisplayFormatter()
|
|
212
|
+
|
|
213
|
+
# matplotlib support for display(figure)
|
|
214
|
+
# IPython.core.pylabtools has support for this, but it requires importing matplotlib
|
|
215
|
+
# which would slow down startup, so we do it here using for_type using a string as argument.
|
|
216
|
+
def encode_png(figure, **kwargs):
|
|
217
|
+
f = io.BytesIO()
|
|
218
|
+
format = "png"
|
|
219
|
+
figure.savefig(f, format=format, **kwargs)
|
|
220
|
+
bytes_data = f.getvalue()
|
|
221
|
+
base64_data = b2a_base64(bytes_data, newline=False).decode("ascii")
|
|
222
|
+
return base64_data
|
|
223
|
+
|
|
224
|
+
formatter = self.display_formatter.formatters["image/png"]
|
|
225
|
+
formatter.for_type("matplotlib.figure.Figure", encode_png)
|
|
226
|
+
|
|
227
|
+
def init_display_pub(self):
|
|
228
|
+
super().init_display_pub()
|
|
229
|
+
self.display_pub.register_hook(self.display_in_reacton_hook)
|
|
230
|
+
|
|
231
|
+
def display_in_reacton_hook(self, msg):
|
|
232
|
+
"""Will intercept a display call and add the display data to an output widget when in a reacton context/render function."""
|
|
233
|
+
# similar to reacton.patch_display.publish
|
|
234
|
+
from reacton.core import get_render_context
|
|
235
|
+
|
|
236
|
+
rc = get_render_context(required=False)
|
|
237
|
+
# only during the render phase we want to capture the display calls
|
|
238
|
+
# during the reconsolidation phase we want to let the original display publisher do its thing
|
|
239
|
+
# such as adding it to a output widget
|
|
240
|
+
if rc is not None and not rc.reconsolidating and msg["msg_type"] == "display_data":
|
|
241
|
+
from reacton.ipywidgets import Output
|
|
242
|
+
|
|
243
|
+
Output(
|
|
244
|
+
outputs=[
|
|
245
|
+
{
|
|
246
|
+
"output_type": "display_data",
|
|
247
|
+
"data": msg["content"]["data"],
|
|
248
|
+
"metadata": msg["content"]["metadata"],
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
)
|
|
252
|
+
return None # do not send to the frontend
|
|
253
|
+
return msg
|
|
254
|
+
|
|
255
|
+
def reset(self, new_session=True, aggressive=False):
|
|
256
|
+
# if we dont override this with a dummy, the unittests will take a long time
|
|
257
|
+
# to exit. Hitting ctrl-c showed the following stacktrace:
|
|
258
|
+
# Traceback (most recent call last):
|
|
259
|
+
# File "/Users/maartenbreddels/miniconda3/envs/dev/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3924, in atexit_operations
|
|
260
|
+
# self.reset(new_session=False)
|
|
261
|
+
# File "/Users/maartenbreddels/miniconda3/envs/dev/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 1456, in reset
|
|
262
|
+
# self.displayhook.flush()
|
|
263
|
+
# File "/Users/maartenbreddels/miniconda3/envs/dev/lib/python3.9/site-packages/IPython/core/displayhook.py", line 311, in flush
|
|
264
|
+
# gc.collect()
|
|
265
|
+
# So this dummy will prevent that.
|
|
266
|
+
pass
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
InteractiveShellABC.register(SolaraInteractiveShell)
|