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
solara/server/patch.py
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import pdb
|
|
4
|
+
import sys
|
|
5
|
+
import threading
|
|
6
|
+
import traceback
|
|
7
|
+
import warnings
|
|
8
|
+
from typing import Any, Dict, MutableMapping
|
|
9
|
+
from unittest import mock
|
|
10
|
+
|
|
11
|
+
import ipykernel.kernelbase
|
|
12
|
+
import IPython.display
|
|
13
|
+
import ipywidgets
|
|
14
|
+
import ipywidgets.widgets.widget_output
|
|
15
|
+
from IPython.core.interactiveshell import InteractiveShell
|
|
16
|
+
|
|
17
|
+
import solara
|
|
18
|
+
import solara.util
|
|
19
|
+
|
|
20
|
+
from . import app, kernel_context, reload, settings
|
|
21
|
+
from .utils import pdb_guard
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger("solara.server.patch")
|
|
24
|
+
try:
|
|
25
|
+
from reacton.patch_display import patch as patch_display
|
|
26
|
+
except: # noqa
|
|
27
|
+
patch_display = None # type: ignore
|
|
28
|
+
|
|
29
|
+
if patch_display is not None and sys.platform != "emscripten":
|
|
30
|
+
patch_display()
|
|
31
|
+
ipywidget_version_major = int(ipywidgets.__version__.split(".")[0])
|
|
32
|
+
ipykernel_version_major = int(ipykernel.__version__.split(".")[0])
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FakeIPython:
|
|
36
|
+
def __init__(self, context: kernel_context.VirtualKernelContext):
|
|
37
|
+
self.context = context
|
|
38
|
+
self.kernel = context.kernel
|
|
39
|
+
self.display_pub = self.kernel.shell.display_pub
|
|
40
|
+
# needed for the pyplot interface of matplotlib
|
|
41
|
+
# (although we don't really support it)
|
|
42
|
+
self.events = mock.MagicMock()
|
|
43
|
+
self.user_ns: Dict[Any, Any] = {}
|
|
44
|
+
self.custom_exceptions = ()
|
|
45
|
+
|
|
46
|
+
def enable_gui(self, gui):
|
|
47
|
+
logger.error("ignoring call to enable_gui(%s)", gui)
|
|
48
|
+
|
|
49
|
+
def register_post_execute(self, callback):
|
|
50
|
+
# mpl requires this
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
def set_parent(self, *args):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
def showtraceback(self):
|
|
57
|
+
if settings.main.use_pdb:
|
|
58
|
+
logger.exception("Exception, will be handled by debugger")
|
|
59
|
+
pdb.post_mortem()
|
|
60
|
+
etype, value, tb = sys.exc_info()
|
|
61
|
+
traceback_string = "".join(traceback.format_exception(etype, value, tb))
|
|
62
|
+
logger.error("Uncaught exception: %s", traceback_string)
|
|
63
|
+
msg = {
|
|
64
|
+
"type": "exception",
|
|
65
|
+
"traceback": traceback_string,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for socket in self.context.control_sockets:
|
|
69
|
+
try:
|
|
70
|
+
socket.send_json(msg)
|
|
71
|
+
except: # noqa
|
|
72
|
+
# TODO: should we remove it from the list?
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
def magic(self, *args):
|
|
76
|
+
# proplot requires this
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
def set_custom_exc(self, exc_tuple, handler):
|
|
80
|
+
# make dask work
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Kernel_instance_original = ipykernel.kernelbase.Kernel.instance.__func__ # type: ignore
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def kernel_instance_dispatch(cls, *args, **kwargs):
|
|
88
|
+
if kernel_context.has_current_context():
|
|
89
|
+
context = kernel_context.get_current_context()
|
|
90
|
+
return context.kernel
|
|
91
|
+
else:
|
|
92
|
+
return Kernel_instance_original(cls, *args, **kwargs)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
Kernel_initialized_initial = ipykernel.kernelbase.Kernel.initialized.__func__ # type: ignore
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def kernel_initialized_dispatch(cls):
|
|
99
|
+
if app is None: # python is shutting down, and the comm dtor wants to send a close message
|
|
100
|
+
return False
|
|
101
|
+
if kernel_context.has_current_context():
|
|
102
|
+
return True
|
|
103
|
+
else:
|
|
104
|
+
return Kernel_initialized_initial(cls)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
InteractiveShell_instance_initial = InteractiveShell.instance.__func__ # type: ignore
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def interactive_shell_instance_dispatch(cls, *args, **kwargs):
|
|
111
|
+
if kernel_context.has_current_context():
|
|
112
|
+
context = kernel_context.get_current_context()
|
|
113
|
+
return context.kernel.shell
|
|
114
|
+
else:
|
|
115
|
+
return InteractiveShell_instance_initial(cls, *args, **kwargs)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def display_solara(
|
|
119
|
+
*objs,
|
|
120
|
+
include=None,
|
|
121
|
+
exclude=None,
|
|
122
|
+
metadata=None,
|
|
123
|
+
transient=None,
|
|
124
|
+
display_id=None,
|
|
125
|
+
raw=False,
|
|
126
|
+
clear=False,
|
|
127
|
+
**kwargs,
|
|
128
|
+
):
|
|
129
|
+
print(*objs) # noqa
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# from IPython.core.interactiveshell import InteractiveShell
|
|
133
|
+
|
|
134
|
+
# if transient is None:
|
|
135
|
+
# transient = {}
|
|
136
|
+
# if metadata is None:
|
|
137
|
+
# metadata = {}
|
|
138
|
+
# from IPython.core.display_functions import _new_id
|
|
139
|
+
|
|
140
|
+
# if display_id:
|
|
141
|
+
# if display_id is True:
|
|
142
|
+
# display_id = _new_id()
|
|
143
|
+
# transient["display_id"] = display_id
|
|
144
|
+
# if kwargs.get("update") and "display_id" not in transient:
|
|
145
|
+
# raise TypeError("display_id required for update_display")
|
|
146
|
+
# if transient:
|
|
147
|
+
# kwargs["transient"] = transient
|
|
148
|
+
|
|
149
|
+
# if not objs and display_id:
|
|
150
|
+
# # if given no objects, but still a request for a display_id,
|
|
151
|
+
# # we assume the user wants to insert an empty output that
|
|
152
|
+
# # can be updated later
|
|
153
|
+
# objs = [{}]
|
|
154
|
+
# raw = True
|
|
155
|
+
|
|
156
|
+
# if not raw:
|
|
157
|
+
# format = InteractiveShell.instance().display_formatter.format
|
|
158
|
+
|
|
159
|
+
# if clear:
|
|
160
|
+
# clear_output(wait=True)
|
|
161
|
+
|
|
162
|
+
# for obj in objs:
|
|
163
|
+
# if raw:
|
|
164
|
+
# publish_display_data(data=obj, metadata=metadata, **kwargs)
|
|
165
|
+
# else:
|
|
166
|
+
# format_dict, md_dict = format(obj, include=include, exclude=exclude)
|
|
167
|
+
# if not format_dict:
|
|
168
|
+
# # nothing to display (e.g. _ipython_display_ took over)
|
|
169
|
+
# continue
|
|
170
|
+
# if metadata:
|
|
171
|
+
# # kwarg-specified metadata gets precedence
|
|
172
|
+
# _merge(md_dict, metadata)
|
|
173
|
+
# publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
|
|
174
|
+
# if display_id:
|
|
175
|
+
# return DisplayHandle(display_id)
|
|
176
|
+
|
|
177
|
+
get_ipython_original = IPython.get_ipython
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_ipython():
|
|
181
|
+
if kernel_context.has_current_context():
|
|
182
|
+
context = kernel_context.get_current_context()
|
|
183
|
+
our_fake_ipython = FakeIPython(context)
|
|
184
|
+
return our_fake_ipython
|
|
185
|
+
else:
|
|
186
|
+
return get_ipython_original()
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class context_dict(MutableMapping):
|
|
190
|
+
def _get_context_dict(self) -> dict:
|
|
191
|
+
raise NotImplementedError
|
|
192
|
+
|
|
193
|
+
def __delitem__(self, key) -> None:
|
|
194
|
+
self._get_context_dict().__delitem__(key)
|
|
195
|
+
|
|
196
|
+
def __getitem__(self, key):
|
|
197
|
+
return self._get_context_dict().__getitem__(key)
|
|
198
|
+
|
|
199
|
+
def __iter__(self):
|
|
200
|
+
return self._get_context_dict().__iter__()
|
|
201
|
+
|
|
202
|
+
def __len__(self):
|
|
203
|
+
return self._get_context_dict().__len__()
|
|
204
|
+
|
|
205
|
+
def __setitem__(self, key, value):
|
|
206
|
+
self._get_context_dict().__setitem__(key, value)
|
|
207
|
+
|
|
208
|
+
# support OrderedDict API for matplotlib
|
|
209
|
+
def move_to_end(self, key, last=True):
|
|
210
|
+
assert last, "only last=True is supported"
|
|
211
|
+
item = self.pop(key)
|
|
212
|
+
self[key] = item
|
|
213
|
+
|
|
214
|
+
# matplotlib assumes .values() returns a list
|
|
215
|
+
def values(self):
|
|
216
|
+
return list(self._get_context_dict().values())
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class context_dict_widgets(context_dict):
|
|
220
|
+
def _get_context_dict(self) -> dict:
|
|
221
|
+
if kernel_context.has_current_context():
|
|
222
|
+
context = kernel_context.get_current_context()
|
|
223
|
+
return context.widgets
|
|
224
|
+
else:
|
|
225
|
+
return global_widgets_dict
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class context_dict_templates(context_dict):
|
|
229
|
+
def _get_context_dict(self) -> dict:
|
|
230
|
+
if kernel_context.has_current_context():
|
|
231
|
+
context = kernel_context.get_current_context()
|
|
232
|
+
return context.templates
|
|
233
|
+
else:
|
|
234
|
+
return global_templates_dict
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class context_dict_user(context_dict):
|
|
238
|
+
def __init__(self, name, default_dict):
|
|
239
|
+
self.name = name
|
|
240
|
+
self.default_dict = default_dict
|
|
241
|
+
|
|
242
|
+
def _get_context_dict(self) -> dict:
|
|
243
|
+
if kernel_context.has_current_context():
|
|
244
|
+
context = kernel_context.get_current_context()
|
|
245
|
+
if self.name not in context.user_dicts:
|
|
246
|
+
context.user_dicts[self.name] = {}
|
|
247
|
+
return context.user_dicts[self.name]
|
|
248
|
+
else:
|
|
249
|
+
return self.default_dict
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def auto_watch_get_template(get_template):
|
|
253
|
+
"""Wraps get_template and adds a file listener for automatic .vue file reloading"""
|
|
254
|
+
|
|
255
|
+
def wrapper(abs_path):
|
|
256
|
+
template = get_template(abs_path)
|
|
257
|
+
with kernel_context.without_context():
|
|
258
|
+
reload.reloader.watcher.add_file(abs_path)
|
|
259
|
+
return template
|
|
260
|
+
|
|
261
|
+
return wrapper
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ThreadDebugInfo:
|
|
265
|
+
lock = threading.Lock()
|
|
266
|
+
created = 0
|
|
267
|
+
running = 0
|
|
268
|
+
stopped = 0
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
Thread__init__ = threading.Thread.__init__
|
|
272
|
+
Thread__bootstrap = threading.Thread._bootstrap # type: ignore
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def WidgetContextAwareThread__init__(self, *args, **kwargs):
|
|
276
|
+
Thread__init__(self, *args, **kwargs)
|
|
277
|
+
with ThreadDebugInfo.lock:
|
|
278
|
+
ThreadDebugInfo.created += 1
|
|
279
|
+
|
|
280
|
+
self.current_context = None
|
|
281
|
+
# if we do this for the dummy threads, we got into a recursion
|
|
282
|
+
# since threading.current_thread will call the _DummyThread constructor
|
|
283
|
+
if not ("name" in kwargs and "Dummy-" in kwargs["name"]):
|
|
284
|
+
try:
|
|
285
|
+
self.current_context = kernel_context.get_current_context()
|
|
286
|
+
except RuntimeError:
|
|
287
|
+
logger.debug(f"No context for thread {self._name}")
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def WidgetContextAwareThread__bootstrap(self):
|
|
291
|
+
with ThreadDebugInfo.lock:
|
|
292
|
+
ThreadDebugInfo.running += 1
|
|
293
|
+
try:
|
|
294
|
+
_WidgetContextAwareThread__bootstrap(self)
|
|
295
|
+
finally:
|
|
296
|
+
with ThreadDebugInfo.lock:
|
|
297
|
+
ThreadDebugInfo.running -= 1
|
|
298
|
+
ThreadDebugInfo.stopped += 1
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _WidgetContextAwareThread__bootstrap(self):
|
|
302
|
+
if not hasattr(self, "current_context"):
|
|
303
|
+
# this happens when a thread was running before we patched
|
|
304
|
+
return Thread__bootstrap(self)
|
|
305
|
+
if self.current_context:
|
|
306
|
+
# we need to call this manually, because set_context_for_thread
|
|
307
|
+
# uses this, and the original _bootstrap calls it too late for us
|
|
308
|
+
self._set_ident()
|
|
309
|
+
if kernel_context.async_context_id is not None:
|
|
310
|
+
kernel_context.async_context_id.set(self.current_context.id)
|
|
311
|
+
kernel_context.set_context_for_thread(self.current_context, self)
|
|
312
|
+
shell = self.current_context.kernel.shell
|
|
313
|
+
display_pub = shell.display_pub
|
|
314
|
+
display_in_reacton_hook = shell.display_in_reacton_hook
|
|
315
|
+
display_pub.register_hook(display_in_reacton_hook)
|
|
316
|
+
try:
|
|
317
|
+
context = self.current_context or solara.util.nullcontext()
|
|
318
|
+
with pdb_guard(), context:
|
|
319
|
+
Thread__bootstrap(self)
|
|
320
|
+
finally:
|
|
321
|
+
current_context = self.current_context
|
|
322
|
+
self.current_context = None
|
|
323
|
+
kernel_context.clear_context_for_thread(self)
|
|
324
|
+
if current_context:
|
|
325
|
+
display_pub.unregister_hook(display_in_reacton_hook)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
_patched = False
|
|
329
|
+
global_widgets_dict = {}
|
|
330
|
+
global_templates_dict: Dict[Any, Any] = {}
|
|
331
|
+
widgets = context_dict_widgets()
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def Output_enter(self):
|
|
335
|
+
self._flush()
|
|
336
|
+
|
|
337
|
+
def hook(msg):
|
|
338
|
+
if msg["msg_type"] == "display_data":
|
|
339
|
+
self.outputs += ({"output_type": "display_data", "data": msg["content"]["data"], "metadata": msg["content"]["metadata"]},)
|
|
340
|
+
return None
|
|
341
|
+
if msg["msg_type"] == "clear_output":
|
|
342
|
+
self.outputs = ()
|
|
343
|
+
return None
|
|
344
|
+
return msg
|
|
345
|
+
|
|
346
|
+
ip = get_ipython()
|
|
347
|
+
if ip:
|
|
348
|
+
ip.display_pub.register_hook(hook)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def Output_exit(self, exc_type, exc_value, traceback):
|
|
352
|
+
ip = get_ipython()
|
|
353
|
+
if ip:
|
|
354
|
+
ip.display_pub._hooks.pop()
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def patch_ipyreact():
|
|
358
|
+
import ipyreact
|
|
359
|
+
import ipyreact.module
|
|
360
|
+
|
|
361
|
+
from . import esm
|
|
362
|
+
|
|
363
|
+
ipyreact.module.define_module = esm.define_module
|
|
364
|
+
ipyreact.module.get_module_names = esm.get_module_names
|
|
365
|
+
# define_module is also exported top level
|
|
366
|
+
ipyreact.define_module = esm.define_module
|
|
367
|
+
|
|
368
|
+
# make this a no-op, we'll create the widget when needed
|
|
369
|
+
ipyreact.importmap._update_import_map = lambda: None
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
@solara.util.once
|
|
373
|
+
def patch_matplotlib():
|
|
374
|
+
import matplotlib
|
|
375
|
+
import matplotlib._pylab_helpers
|
|
376
|
+
|
|
377
|
+
prev = matplotlib._pylab_helpers.Gcf.figs
|
|
378
|
+
matplotlib._pylab_helpers.Gcf.figs = context_dict_user("matplotlib.pylab.figure_managers", prev) # type: ignore
|
|
379
|
+
|
|
380
|
+
RcParamsOriginal = matplotlib.RcParams
|
|
381
|
+
counter = 0
|
|
382
|
+
lock = threading.Lock()
|
|
383
|
+
|
|
384
|
+
class RcParamsScoped(context_dict, matplotlib.RcParams):
|
|
385
|
+
_was_initialized = False
|
|
386
|
+
_without_kernel_dict: Dict[Any, Any]
|
|
387
|
+
|
|
388
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
389
|
+
self._init()
|
|
390
|
+
RcParamsOriginal.__init__(self, *args, **kwargs)
|
|
391
|
+
|
|
392
|
+
def _init(self):
|
|
393
|
+
nonlocal counter
|
|
394
|
+
with lock:
|
|
395
|
+
counter += 1
|
|
396
|
+
self._user_dict_name = f"matplotlib.rcParams:{counter}"
|
|
397
|
+
# this creates a copy of the CPython side of the dict
|
|
398
|
+
self._without_kernel_dict = dict(zip(dict.keys(self), dict.values(self)))
|
|
399
|
+
self._was_initialized = True
|
|
400
|
+
|
|
401
|
+
def _set(self, key, val):
|
|
402
|
+
# in matplotlib this directly calls dict.__setitem__
|
|
403
|
+
# which would not call context_dict.__setitem__
|
|
404
|
+
self[key] = val
|
|
405
|
+
|
|
406
|
+
def _get(self, key):
|
|
407
|
+
# same as _get
|
|
408
|
+
return self[key]
|
|
409
|
+
|
|
410
|
+
def clear(self):
|
|
411
|
+
# in matplotlib .clear is effectively a no-op
|
|
412
|
+
# see https://github.com/matplotlib/matplotlib/issues/25855
|
|
413
|
+
pass
|
|
414
|
+
# in the future, we may want to clear the context dict if this is fixed
|
|
415
|
+
# self._get_context_dict().clear()
|
|
416
|
+
|
|
417
|
+
def _get_context_dict(self) -> dict:
|
|
418
|
+
if not self._was_initialized:
|
|
419
|
+
# since we monkey patch the class after __init__ was called
|
|
420
|
+
# we may have to do that later on
|
|
421
|
+
self._init()
|
|
422
|
+
if kernel_context.has_current_context():
|
|
423
|
+
context = kernel_context.get_current_context()
|
|
424
|
+
if self._user_dict_name not in context.user_dicts:
|
|
425
|
+
# copy over the global settings when needed
|
|
426
|
+
context.user_dicts[self._user_dict_name] = self._without_kernel_dict.copy()
|
|
427
|
+
return context.user_dicts[self._user_dict_name]
|
|
428
|
+
else:
|
|
429
|
+
return self._without_kernel_dict
|
|
430
|
+
|
|
431
|
+
matplotlib.RcParams = RcParamsScoped
|
|
432
|
+
matplotlib.rcParams.__class__ = RcParamsScoped
|
|
433
|
+
# we chose to monkeypatch the class, instead of re-assiging to reParams for 2 reasons:
|
|
434
|
+
# 1. the RcParams object could be imported in different namespaces
|
|
435
|
+
# 2. the rcParams has extra methods, which means we have to otherwise monkeypatch the context_dict
|
|
436
|
+
|
|
437
|
+
def cleanup():
|
|
438
|
+
matplotlib._pylab_helpers.Gcf.figs = prev
|
|
439
|
+
matplotlib.RcParams = RcParamsOriginal
|
|
440
|
+
matplotlib.rcParams.__class__ = RcParamsOriginal
|
|
441
|
+
|
|
442
|
+
return cleanup
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def patch_heavy_imports():
|
|
446
|
+
# patches that we only want to do if a package is imported, because they may slow down startup
|
|
447
|
+
if "matplotlib" in sys.modules:
|
|
448
|
+
patch_matplotlib()
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def patch():
|
|
452
|
+
global _patched
|
|
453
|
+
global global_widgets_dict
|
|
454
|
+
if _patched:
|
|
455
|
+
warnings.warn("patch() called twice")
|
|
456
|
+
return
|
|
457
|
+
_patched = True
|
|
458
|
+
__builtins__["display"] = IPython.display.display
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
import ipyreact
|
|
462
|
+
|
|
463
|
+
del ipyreact
|
|
464
|
+
except ModuleNotFoundError:
|
|
465
|
+
pass
|
|
466
|
+
else:
|
|
467
|
+
patch_ipyreact()
|
|
468
|
+
|
|
469
|
+
if "MPLBACKEND" not in os.environ:
|
|
470
|
+
if ipykernel_version_major < 6:
|
|
471
|
+
# changed in https://github.com/ipython/ipykernel/pull/591
|
|
472
|
+
os.environ["MPLBACKEND"] = "module://ipykernel.pylab.backend_inline"
|
|
473
|
+
else:
|
|
474
|
+
os.environ["MPLBACKEND"] = "module://matplotlib_inline.backend_inline"
|
|
475
|
+
# if matplotlib is already imported, we need to set the backend
|
|
476
|
+
# similar to how matplotlib does it in it's __init__.py
|
|
477
|
+
if "matplotlib" in sys.modules:
|
|
478
|
+
import matplotlib
|
|
479
|
+
|
|
480
|
+
matplotlib.rcParams["backend"] = os.environ.get("MPLBACKEND")
|
|
481
|
+
|
|
482
|
+
# the ipyvue.Template module cannot be accessed like ipyvue.Template
|
|
483
|
+
# because the import in ipvue overrides it
|
|
484
|
+
template_mod = sys.modules["ipyvue.Template"]
|
|
485
|
+
template_mod.template_registry = context_dict_templates() # type: ignore
|
|
486
|
+
template_mod.get_template = auto_watch_get_template(template_mod.get_template) # type: ignore
|
|
487
|
+
|
|
488
|
+
# this module also imports get_template
|
|
489
|
+
template_mod_vue = sys.modules["ipyvue.VueTemplateWidget"]
|
|
490
|
+
template_mod_vue.get_template = template_mod.get_template # type: ignore
|
|
491
|
+
|
|
492
|
+
component_mod_vue = sys.modules["ipyvue.VueComponentRegistry"]
|
|
493
|
+
component_mod_vue.vue_component_registry = context_dict_user("vue_component_registry", component_mod_vue.vue_component_registry) # type: ignore
|
|
494
|
+
component_mod_vue.vue_component_files = context_dict_user("vue_component_files", component_mod_vue.vue_component_files) # type: ignore
|
|
495
|
+
|
|
496
|
+
if ipywidget_version_major < 8:
|
|
497
|
+
global_widgets_dict = ipywidgets.widget.Widget.widgets
|
|
498
|
+
ipywidgets.widget.Widget.widgets = widgets # type: ignore
|
|
499
|
+
else:
|
|
500
|
+
if hasattr(ipywidgets.widgets.widget, "_instances"): # since 8.0.3
|
|
501
|
+
global_widgets_dict = ipywidgets.widgets.widget._instances
|
|
502
|
+
ipywidgets.widgets.widget._instances = widgets # type: ignore
|
|
503
|
+
elif hasattr(ipywidgets.widget.Widget, "_instances"):
|
|
504
|
+
global_widgets_dict = ipywidgets.widget.Widget._instances
|
|
505
|
+
ipywidgets.widget.Widget._instances = widgets # type: ignore
|
|
506
|
+
else:
|
|
507
|
+
raise RuntimeError("Could not find _instances on ipywidgets version %r" % ipywidgets.__version__)
|
|
508
|
+
threading.Thread.__init__ = WidgetContextAwareThread__init__ # type: ignore
|
|
509
|
+
threading.Thread._bootstrap = WidgetContextAwareThread__bootstrap # type: ignore
|
|
510
|
+
# on CI we get a mypy error:
|
|
511
|
+
# solara/server/patch.py:210: error: Cannot assign to a method
|
|
512
|
+
# solara/server/patch.py:210: error: Incompatible types in assignment (expression has type "classmethod[Any]",\
|
|
513
|
+
# variable has type "Callable[[VarArg(Any), KwArg(Any)], Any]")
|
|
514
|
+
# not sure why we cannot reproduce that locally
|
|
515
|
+
ipykernel.kernelbase.Kernel.instance = classmethod(kernel_instance_dispatch) # type: ignore
|
|
516
|
+
InteractiveShell.instance = classmethod(interactive_shell_instance_dispatch) # type: ignore
|
|
517
|
+
# on CI we get a mypy error:
|
|
518
|
+
# solara/server/patch.py:211: error: Cannot assign to a method
|
|
519
|
+
# solara/server/patch.py:211: error: Incompatible types in assignment (expression has type "classmethod[Any]", variable has type "Callable[[], Any]")
|
|
520
|
+
# not sure why we cannot reproduce that locally
|
|
521
|
+
ipykernel.kernelbase.Kernel.initialized = classmethod(kernel_initialized_dispatch) # type: ignore
|
|
522
|
+
ipywidgets.widgets.widget.get_ipython = get_ipython
|
|
523
|
+
# TODO: find a way to actually monkeypatch get_ipython
|
|
524
|
+
IPython.get_ipython = get_ipython
|
|
525
|
+
|
|
526
|
+
ipywidgets.widgets.widget_output.Output.__enter__ = Output_enter
|
|
527
|
+
ipywidgets.widgets.widget_output.Output.__exit__ = Output_exit
|
|
528
|
+
|
|
529
|
+
original_close = ipywidgets.widget.Widget.close
|
|
530
|
+
closed_ids = set()
|
|
531
|
+
closed_stack: Dict[int, str] = {}
|
|
532
|
+
|
|
533
|
+
def model_id_debug(self: ipywidgets.widgets.widget.Widget):
|
|
534
|
+
from ipyvue.ForceLoad import force_load_instance
|
|
535
|
+
|
|
536
|
+
import solara.comm
|
|
537
|
+
|
|
538
|
+
if self.comm is None and id(self) in closed_ids and id(self) in closed_stack:
|
|
539
|
+
raise RuntimeError(f"Widget {type(self)} has been closed, the stacktrace when the widget was closed is:\n{closed_stack[id(self)]}")
|
|
540
|
+
|
|
541
|
+
if self.comm is None or isinstance(self.comm, solara.comm.DummyComm) and force_load_instance.comm is not self.comm:
|
|
542
|
+
stack = solara.comm.orphan_comm_stacks.get(self.comm)
|
|
543
|
+
if stack:
|
|
544
|
+
raise RuntimeError(
|
|
545
|
+
"Widget has no comm, you are probably using a widget that was created at app startup, the stacktrace when the widget was created is:\n"
|
|
546
|
+
+ stack
|
|
547
|
+
)
|
|
548
|
+
else:
|
|
549
|
+
raise RuntimeError("Widget has no comm, you are probably using a widget that was closed. The widget is:\n" + repr(self))
|
|
550
|
+
|
|
551
|
+
return self.comm.comm_id
|
|
552
|
+
|
|
553
|
+
ipywidgets.widget.Widget.model_id = property(model_id_debug)
|
|
554
|
+
|
|
555
|
+
def close_widget_debug(self: ipywidgets.widgets.widget.Widget):
|
|
556
|
+
# only in development mode, since this leaks memory
|
|
557
|
+
# can be called during shutdown/gc, so we need to check if the module is still there
|
|
558
|
+
if settings and settings.main.mode == "development":
|
|
559
|
+
stacktrace = "".join(traceback.format_stack())
|
|
560
|
+
closed_stack[id(self)] = stacktrace
|
|
561
|
+
closed_ids.add(id(self))
|
|
562
|
+
original_close(self)
|
|
563
|
+
|
|
564
|
+
ipywidgets.widget.Widget.close = close_widget_debug
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
from PyInstaller.utils.hooks import collect_data_files, copy_metadata, collect_submodules
|
|
2
|
+
|
|
3
|
+
hiddenimports = collect_submodules("ipyvuetify")
|
|
4
|
+
datas = collect_data_files("ipyvuetify") # codespell:ignore datas
|
|
5
|
+
datas += copy_metadata("ipyvuetify") # codespell:ignore datas
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
|
|
2
|
+
|
|
3
|
+
hiddenimports = collect_submodules("solara")
|
|
4
|
+
datas = collect_data_files("solara") # codespell:ignore datas
|
|
5
|
+
datas += collect_data_files("solara-ui") # codespell:ignore datas
|
|
6
|
+
|
|
7
|
+
# this makes sure that inspect.getfile works, which is used for the
|
|
8
|
+
# vue component decorator
|
|
9
|
+
module_collection_mode = "pyz+py"
|