solara 1.30.0__py2.py3-none-any.whl → 1.31.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/METADATA +7 -42
- solara-1.31.0.dist-info/RECORD +5 -0
- {solara-1.30.0.dist-info → solara-1.31.0.dist-info}/WHEEL +1 -1
- {solara/template/portal → solara-1.31.0.dist-info/licenses}/LICENSE +1 -1
- solara/__init__.py +0 -123
- solara/__main__.py +0 -734
- solara/alias.py +0 -6
- solara/autorouting.py +0 -554
- solara/cache.py +0 -294
- solara/checks.html +0 -71
- solara/checks.py +0 -224
- solara/comm.py +0 -28
- solara/components/__init__.py +0 -59
- solara/components/alert.py +0 -155
- solara/components/applayout.py +0 -393
- solara/components/button.py +0 -85
- solara/components/card.py +0 -87
- solara/components/checkbox.py +0 -50
- solara/components/code_highlight_css.py +0 -11
- solara/components/code_highlight_css.vue +0 -63
- solara/components/columns.py +0 -159
- solara/components/component_vue.py +0 -109
- solara/components/cross_filter.py +0 -335
- solara/components/dataframe.py +0 -546
- solara/components/datatable.py +0 -221
- solara/components/datatable.vue +0 -175
- solara/components/details.py +0 -21
- solara/components/download.vue +0 -35
- solara/components/echarts.py +0 -75
- solara/components/echarts.vue +0 -128
- solara/components/figure_altair.py +0 -39
- solara/components/file_browser.py +0 -182
- solara/components/file_download.py +0 -199
- solara/components/file_drop.py +0 -139
- solara/components/file_drop.vue +0 -83
- solara/components/file_list_widget.vue +0 -78
- solara/components/head.py +0 -27
- solara/components/head_tag.py +0 -49
- solara/components/head_tag.vue +0 -60
- solara/components/image.py +0 -173
- solara/components/input.py +0 -440
- solara/components/link.py +0 -55
- solara/components/markdown.py +0 -371
- solara/components/markdown_editor.py +0 -25
- solara/components/markdown_editor.vue +0 -362
- solara/components/matplotlib.py +0 -74
- solara/components/meta.py +0 -47
- solara/components/misc.py +0 -333
- solara/components/pivot_table.py +0 -258
- solara/components/pivot_table.vue +0 -158
- solara/components/progress.py +0 -47
- solara/components/select.py +0 -186
- solara/components/select.vue +0 -27
- solara/components/slider.py +0 -442
- solara/components/slider_date.vue +0 -56
- solara/components/spinner-solara.vue +0 -105
- solara/components/spinner.py +0 -30
- solara/components/sql_code.py +0 -33
- solara/components/sql_code.vue +0 -128
- solara/components/style.py +0 -105
- solara/components/switch.py +0 -68
- solara/components/tab_navigation.py +0 -37
- solara/components/title.py +0 -90
- solara/components/title.vue +0 -38
- solara/components/togglebuttons.py +0 -202
- solara/components/tooltip.py +0 -61
- solara/datatypes.py +0 -143
- solara/express.py +0 -241
- solara/hooks/__init__.py +0 -4
- solara/hooks/dataframe.py +0 -99
- solara/hooks/misc.py +0 -263
- solara/hooks/use_reactive.py +0 -129
- solara/hooks/use_thread.py +0 -129
- solara/kitchensink.py +0 -8
- solara/lab/__init__.py +0 -34
- solara/lab/components/__init__.py +0 -6
- solara/lab/components/chat.py +0 -203
- solara/lab/components/confirmation_dialog.py +0 -165
- solara/lab/components/cross_filter.py +0 -7
- solara/lab/components/input_date.py +0 -298
- solara/lab/components/menu.py +0 -181
- solara/lab/components/menu.vue +0 -38
- solara/lab/components/tabs.py +0 -274
- solara/lab/components/theming.py +0 -98
- solara/lab/components/theming.vue +0 -72
- solara/lab/hooks/__init__.py +0 -0
- solara/lab/hooks/dataframe.py +0 -12
- solara/lab/toestand.py +0 -3
- solara/lab/utils/__init__.py +0 -2
- solara/lab/utils/cookies.py +0 -5
- solara/lab/utils/dataframe.py +0 -115
- solara/lab/utils/headers.py +0 -5
- solara/layout.py +0 -44
- solara/minisettings.py +0 -133
- solara/py.typed +0 -0
- solara/reactive.py +0 -93
- solara/routing.py +0 -268
- solara/scope/__init__.py +0 -87
- solara/scope/types.py +0 -55
- solara/server/__init__.py +0 -0
- solara/server/app.py +0 -490
- solara/server/assets/custom.css +0 -1
- solara/server/assets/custom.js +0 -1
- solara/server/assets/favicon.png +0 -0
- solara/server/assets/favicon.svg +0 -5
- solara/server/assets/style.css +0 -1665
- solara/server/assets/theme-dark.css +0 -437
- solara/server/assets/theme-light.css +0 -420
- solara/server/assets/theme.js +0 -3
- solara/server/cdn_helper.py +0 -77
- solara/server/esm.py +0 -69
- solara/server/fastapi.py +0 -5
- solara/server/flask.py +0 -286
- solara/server/jupyter/__init__.py +0 -2
- solara/server/jupyter/cdn_handler.py +0 -28
- solara/server/jupyter/server_extension.py +0 -29
- solara/server/jupytertools.py +0 -46
- solara/server/kernel.py +0 -319
- solara/server/kernel_context.py +0 -393
- solara/server/patch.py +0 -552
- solara/server/reload.py +0 -242
- solara/server/server.py +0 -437
- solara/server/settings.py +0 -212
- solara/server/shell.py +0 -240
- solara/server/starlette.py +0 -597
- solara/server/static/ansi.js +0 -270
- solara/server/static/highlight-dark.css +0 -82
- solara/server/static/highlight.css +0 -43
- solara/server/static/main-vuetify.js +0 -260
- solara/server/static/main.js +0 -163
- solara/server/static/solara_bootstrap.py +0 -129
- solara/server/static/sun.svg +0 -23
- solara/server/static/webworker.js +0 -42
- solara/server/telemetry.py +0 -212
- solara/server/templates/index.html.j2 +0 -1
- solara/server/templates/loader-plain.css +0 -11
- solara/server/templates/loader-plain.html +0 -20
- solara/server/templates/loader-solara.css +0 -111
- solara/server/templates/loader-solara.html +0 -40
- solara/server/templates/plain.html +0 -82
- solara/server/templates/solara.html.j2 +0 -446
- solara/server/threaded.py +0 -75
- solara/server/utils.py +0 -30
- solara/server/websocket.py +0 -44
- solara/settings.py +0 -56
- solara/tasks.py +0 -847
- solara/template/button.py +0 -16
- solara/template/markdown.py +0 -42
- solara/template/portal/.flake8 +0 -6
- solara/template/portal/.pre-commit-config.yaml +0 -28
- solara/template/portal/Procfile +0 -7
- solara/template/portal/mypy.ini +0 -3
- solara/template/portal/pyproject.toml +0 -26
- solara/template/portal/solara_portal/__init__.py +0 -3
- solara/template/portal/solara_portal/components/__init__.py +0 -2
- solara/template/portal/solara_portal/components/article.py +0 -28
- solara/template/portal/solara_portal/components/data.py +0 -28
- solara/template/portal/solara_portal/components/header.py +0 -6
- solara/template/portal/solara_portal/components/layout.py +0 -6
- solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +0 -85
- solara/template/portal/solara_portal/content/articles/substiterat-vati.md +0 -70
- solara/template/portal/solara_portal/data.py +0 -60
- solara/template/portal/solara_portal/pages/__init__.py +0 -67
- solara/template/portal/solara_portal/pages/article/__init__.py +0 -26
- solara/template/portal/solara_portal/pages/tabular.py +0 -29
- solara/template/portal/solara_portal/pages/viz/__init__.py +0 -69
- solara/template/portal/solara_portal/pages/viz/overview.py +0 -14
- solara/test/__init__.py +0 -0
- solara/test/pytest_plugin.py +0 -698
- solara/toestand.py +0 -772
- solara/util.py +0 -308
- solara/website/__init__.py +0 -0
- solara/website/assets/custom.css +0 -462
- solara/website/assets/images/logo-small.png +0 -0
- solara/website/assets/images/logo.svg +0 -17
- solara/website/assets/images/logo_white.svg +0 -50
- solara/website/assets/theme.js +0 -8
- solara/website/components/__init__.py +0 -5
- solara/website/components/algolia.vue +0 -24
- solara/website/components/algolia_api.vue +0 -157
- solara/website/components/docs.py +0 -118
- solara/website/components/header.py +0 -72
- solara/website/components/hero.py +0 -15
- solara/website/components/mailchimp.py +0 -12
- solara/website/components/mailchimp.vue +0 -47
- solara/website/components/notebook.py +0 -172
- solara/website/pages/__init__.py +0 -564
- solara/website/pages/apps/__init__.py +0 -16
- solara/website/pages/apps/authorization/__init__.py +0 -118
- solara/website/pages/apps/authorization/admin.py +0 -12
- solara/website/pages/apps/authorization/users.py +0 -12
- solara/website/pages/apps/jupyter-dashboard-1.py +0 -116
- solara/website/pages/apps/layout-demo.py +0 -40
- solara/website/pages/apps/multipage/__init__.py +0 -38
- solara/website/pages/apps/multipage/page1.py +0 -26
- solara/website/pages/apps/multipage/page2.py +0 -34
- solara/website/pages/apps/scatter.py +0 -136
- solara/website/pages/apps/scrolling.py +0 -63
- solara/website/pages/apps/tutorial-streamlit.py +0 -18
- solara/website/pages/changelog/__init__.py +0 -8
- solara/website/pages/changelog/changelog.md +0 -180
- solara/website/pages/contact/__init__.py +0 -8
- solara/website/pages/contact/contact.md +0 -17
- solara/website/pages/doc_use_download.py +0 -85
- solara/website/pages/documentation/__init__.py +0 -184
- solara/website/pages/documentation/advanced/__init__.py +0 -36
- solara/website/pages/documentation/advanced/content/00-overview.md +0 -1
- solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +0 -1
- solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +0 -191
- solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +0 -120
- solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +0 -149
- solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +0 -66
- solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +0 -43
- solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +0 -120
- solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +0 -4
- solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +0 -30
- solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +0 -38
- solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +0 -24
- solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +0 -104
- solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +0 -19
- solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +0 -3
- solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +0 -160
- solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +0 -13
- solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +0 -236
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +0 -81
- solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +0 -7
- solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +0 -1
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +0 -167
- solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
- solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +0 -41
- solara/website/pages/documentation/advanced/content/40-development/10-setup.md +0 -72
- solara/website/pages/documentation/advanced/content/__init__.py +0 -0
- solara/website/pages/documentation/api/__init__.py +0 -19
- solara/website/pages/documentation/api/cross_filter/__init__.py +0 -9
- solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +0 -23
- solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +0 -22
- solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +0 -22
- solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +0 -22
- solara/website/pages/documentation/api/hooks/__init__.py +0 -9
- solara/website/pages/documentation/api/hooks/use_cross_filter.py +0 -25
- solara/website/pages/documentation/api/hooks/use_dark_effective.py +0 -13
- solara/website/pages/documentation/api/hooks/use_effect.md +0 -43
- solara/website/pages/documentation/api/hooks/use_effect.py +0 -9
- solara/website/pages/documentation/api/hooks/use_exception.py +0 -33
- solara/website/pages/documentation/api/hooks/use_memo.md +0 -16
- solara/website/pages/documentation/api/hooks/use_memo.py +0 -9
- solara/website/pages/documentation/api/hooks/use_previous.py +0 -32
- solara/website/pages/documentation/api/hooks/use_reactive.py +0 -15
- solara/website/pages/documentation/api/hooks/use_state.py +0 -11
- solara/website/pages/documentation/api/hooks/use_state_or_update.py +0 -68
- solara/website/pages/documentation/api/hooks/use_thread.md +0 -58
- solara/website/pages/documentation/api/hooks/use_thread.py +0 -44
- solara/website/pages/documentation/api/hooks/use_trait_observe.py +0 -13
- solara/website/pages/documentation/api/routing/__init__.py +0 -9
- solara/website/pages/documentation/api/routing/generate_routes.py +0 -11
- solara/website/pages/documentation/api/routing/generate_routes_directory.py +0 -11
- solara/website/pages/documentation/api/routing/resolve_path.py +0 -36
- solara/website/pages/documentation/api/routing/route.py +0 -32
- solara/website/pages/documentation/api/routing/use_route.py +0 -80
- solara/website/pages/documentation/api/routing/use_router.py +0 -15
- solara/website/pages/documentation/api/utilities/__init__.py +0 -9
- solara/website/pages/documentation/api/utilities/component_vue.py +0 -11
- solara/website/pages/documentation/api/utilities/computed.py +0 -16
- solara/website/pages/documentation/api/utilities/display.py +0 -15
- solara/website/pages/documentation/api/utilities/get_kernel_id.py +0 -16
- solara/website/pages/documentation/api/utilities/get_session_id.py +0 -16
- solara/website/pages/documentation/api/utilities/memoize.py +0 -36
- solara/website/pages/documentation/api/utilities/on_kernel_start.py +0 -27
- solara/website/pages/documentation/api/utilities/reactive.py +0 -15
- solara/website/pages/documentation/api/utilities/widget.py +0 -104
- solara/website/pages/documentation/components/__init__.py +0 -12
- solara/website/pages/documentation/components/advanced/__init__.py +0 -9
- solara/website/pages/documentation/components/advanced/link.py +0 -28
- solara/website/pages/documentation/components/advanced/meta.py +0 -21
- solara/website/pages/documentation/components/advanced/style.py +0 -44
- solara/website/pages/documentation/components/common.py +0 -9
- solara/website/pages/documentation/components/data/__init__.py +0 -9
- solara/website/pages/documentation/components/data/dataframe.py +0 -44
- solara/website/pages/documentation/components/data/pivot_table.py +0 -81
- solara/website/pages/documentation/components/enterprise/__init__.py +0 -9
- solara/website/pages/documentation/components/enterprise/avatar.py +0 -19
- solara/website/pages/documentation/components/enterprise/avatar_menu.py +0 -20
- solara/website/pages/documentation/components/input/__init__.py +0 -9
- solara/website/pages/documentation/components/input/button.py +0 -22
- solara/website/pages/documentation/components/input/checkbox.py +0 -12
- solara/website/pages/documentation/components/input/file_browser.py +0 -33
- solara/website/pages/documentation/components/input/file_drop.py +0 -75
- solara/website/pages/documentation/components/input/input.py +0 -18
- solara/website/pages/documentation/components/input/select.py +0 -21
- solara/website/pages/documentation/components/input/slider.py +0 -28
- solara/website/pages/documentation/components/input/switch.py +0 -12
- solara/website/pages/documentation/components/input/togglebuttons.py +0 -20
- solara/website/pages/documentation/components/lab/__init__.py +0 -9
- solara/website/pages/documentation/components/lab/chat.py +0 -108
- solara/website/pages/documentation/components/lab/confirmation_dialog.py +0 -55
- solara/website/pages/documentation/components/lab/cookies_headers.py +0 -48
- solara/website/pages/documentation/components/lab/input_date.py +0 -19
- solara/website/pages/documentation/components/lab/menu.py +0 -21
- solara/website/pages/documentation/components/lab/tab.py +0 -24
- solara/website/pages/documentation/components/lab/tabs.py +0 -44
- solara/website/pages/documentation/components/lab/task.py +0 -12
- solara/website/pages/documentation/components/lab/theming.py +0 -72
- solara/website/pages/documentation/components/lab/use_task.py +0 -12
- solara/website/pages/documentation/components/layout/__init__.py +0 -9
- solara/website/pages/documentation/components/layout/app_bar.py +0 -15
- solara/website/pages/documentation/components/layout/app_bar_title.py +0 -15
- solara/website/pages/documentation/components/layout/app_layout.py +0 -23
- solara/website/pages/documentation/components/layout/card.py +0 -14
- solara/website/pages/documentation/components/layout/card_actions.py +0 -15
- solara/website/pages/documentation/components/layout/column.py +0 -29
- solara/website/pages/documentation/components/layout/columns.py +0 -26
- solara/website/pages/documentation/components/layout/columns_responsive.py +0 -67
- solara/website/pages/documentation/components/layout/griddraggable.py +0 -61
- solara/website/pages/documentation/components/layout/gridfixed.py +0 -21
- solara/website/pages/documentation/components/layout/hbox.py +0 -17
- solara/website/pages/documentation/components/layout/row.py +0 -29
- solara/website/pages/documentation/components/layout/sidebar.py +0 -23
- solara/website/pages/documentation/components/layout/vbox.py +0 -19
- solara/website/pages/documentation/components/output/__init__.py +0 -9
- solara/website/pages/documentation/components/output/file_download.py +0 -12
- solara/website/pages/documentation/components/output/html.py +0 -22
- solara/website/pages/documentation/components/output/image.py +0 -12
- solara/website/pages/documentation/components/output/markdown.py +0 -59
- solara/website/pages/documentation/components/output/markdown_editor.py +0 -53
- solara/website/pages/documentation/components/output/sql_code.py +0 -84
- solara/website/pages/documentation/components/output/tooltip.py +0 -12
- solara/website/pages/documentation/components/page/__init__.py +0 -9
- solara/website/pages/documentation/components/page/head.py +0 -19
- solara/website/pages/documentation/components/page/title.py +0 -28
- solara/website/pages/documentation/components/status/__init__.py +0 -9
- solara/website/pages/documentation/components/status/error.py +0 -40
- solara/website/pages/documentation/components/status/info.py +0 -40
- solara/website/pages/documentation/components/status/progress.py +0 -10
- solara/website/pages/documentation/components/status/spinner.py +0 -10
- solara/website/pages/documentation/components/status/success.py +0 -40
- solara/website/pages/documentation/components/status/warning.py +0 -47
- solara/website/pages/documentation/components/viz/__init__.py +0 -9
- solara/website/pages/documentation/components/viz/altair.py +0 -44
- solara/website/pages/documentation/components/viz/echarts.py +0 -78
- solara/website/pages/documentation/components/viz/matplotlib.py +0 -32
- solara/website/pages/documentation/components/viz/plotly.py +0 -63
- solara/website/pages/documentation/components/viz/plotly_express.py +0 -41
- solara/website/pages/documentation/examples/__init__.py +0 -52
- solara/website/pages/documentation/examples/ai/__init__.py +0 -10
- solara/website/pages/documentation/examples/ai/chatbot.py +0 -96
- solara/website/pages/documentation/examples/ai/tokenizer.py +0 -106
- solara/website/pages/documentation/examples/basics/__init__.py +0 -2
- solara/website/pages/documentation/examples/basics/sine.py +0 -28
- solara/website/pages/documentation/examples/fullscreen/__init__.py +0 -9
- solara/website/pages/documentation/examples/fullscreen/authorization.py +0 -3
- solara/website/pages/documentation/examples/fullscreen/layout_demo.py +0 -3
- solara/website/pages/documentation/examples/fullscreen/multipage.py +0 -3
- solara/website/pages/documentation/examples/fullscreen/scatter.py +0 -3
- solara/website/pages/documentation/examples/fullscreen/scrolling.py +0 -3
- solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +0 -3
- solara/website/pages/documentation/examples/general/__init__.py +0 -9
- solara/website/pages/documentation/examples/general/custom_storage.py +0 -69
- solara/website/pages/documentation/examples/general/deploy_model.py +0 -114
- solara/website/pages/documentation/examples/general/live_update.py +0 -38
- solara/website/pages/documentation/examples/general/login_oauth.py +0 -76
- solara/website/pages/documentation/examples/general/mycard.vue +0 -58
- solara/website/pages/documentation/examples/general/pokemon_search.py +0 -51
- solara/website/pages/documentation/examples/general/vue_component.py +0 -50
- solara/website/pages/documentation/examples/ipycanvas.py +0 -49
- solara/website/pages/documentation/examples/libraries/__init__.py +0 -9
- solara/website/pages/documentation/examples/libraries/altair.py +0 -63
- solara/website/pages/documentation/examples/libraries/bqplot.py +0 -39
- solara/website/pages/documentation/examples/libraries/ipyleaflet.py +0 -32
- solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +0 -65
- solara/website/pages/documentation/examples/utilities/__init__.py +0 -9
- solara/website/pages/documentation/examples/utilities/calculator.py +0 -157
- solara/website/pages/documentation/examples/utilities/countdown_timer.py +0 -64
- solara/website/pages/documentation/examples/utilities/todo.py +0 -195
- solara/website/pages/documentation/examples/visualization/__init__.py +0 -6
- solara/website/pages/documentation/examples/visualization/annotator.py +0 -68
- solara/website/pages/documentation/examples/visualization/linked_views.py +0 -84
- solara/website/pages/documentation/examples/visualization/plotly.py +0 -43
- solara/website/pages/documentation/faq/__init__.py +0 -11
- solara/website/pages/documentation/faq/content/99-faq.md +0 -73
- solara/website/pages/documentation/getting_started/__init__.py +0 -15
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +0 -84
- solara/website/pages/documentation/getting_started/content/01-introduction.md +0 -121
- solara/website/pages/documentation/getting_started/content/02-installing.md +0 -81
- solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +0 -9
- solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +0 -13
- solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +0 -84
- solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +0 -120
- solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +0 -141
- solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +0 -140
- solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +0 -64
- 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 +0 -445
- solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +0 -1000
- solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +0 -7
- solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +0 -218
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +0 -83
- solara/website/pages/documentation/getting_started/content/06-reference/00-overview.md +0 -3
- solara/website/pages/documentation/getting_started/content/06-reference/40-static_files.md +0 -27
- solara/website/pages/documentation/getting_started/content/06-reference/41-asset-files.md +0 -32
- solara/website/pages/documentation/getting_started/content/06-reference/60-static-site-generation.md +0 -55
- solara/website/pages/documentation/getting_started/content/06-reference/70-search.md +0 -30
- solara/website/pages/documentation/getting_started/content/06-reference/80-reloading.md +0 -30
- solara/website/pages/documentation/getting_started/content/06-reference/90-notebook-support.md +0 -4
- solara/website/pages/documentation/getting_started/content/06-reference/95-caching.md +0 -143
- solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +0 -3
- solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +0 -269
- solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +0 -76
- solara/website/pages/documentation/getting_started/content/08-lab/00-what-is-lab.md +0 -3
- solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +0 -22
- solara/website/pages/documentation/getting_started/content/__init__.py +0 -0
- solara/website/pages/docutils.py +0 -38
- solara/website/pages/showcase/__init__.py +0 -105
- solara/website/pages/showcase/domino_code_assist.py +0 -60
- solara/website/pages/showcase/planeto_tessa.py +0 -19
- solara/website/pages/showcase/solara_dev.py +0 -54
- solara/website/pages/showcase/solarathon_2023_team_2.py +0 -22
- solara/website/pages/showcase/solarathon_2023_team_4.py +0 -22
- solara/website/pages/showcase/solarathon_2023_team_5.py +0 -23
- solara/website/pages/showcase/solarathon_2023_team_6.py +0 -34
- solara/website/pages/showcase/wanderlust.py +0 -27
- solara/website/public/beach.jpeg +0 -0
- solara/website/public/logo.svg +0 -6
- solara/website/public/social/discord.svg +0 -1
- solara/website/public/social/github.svg +0 -1
- solara/website/public/social/twitter.svg +0 -3
- solara/website/public/success.html +0 -25
- solara/website/templates/index.html.j2 +0 -117
- solara/website/utils.py +0 -51
- solara/widgets/__init__.py +0 -1
- solara/widgets/vue/gridlayout.vue +0 -110
- solara/widgets/vue/html.vue +0 -4
- solara/widgets/vue/navigator.vue +0 -104
- solara/widgets/vue/vegalite.vue +0 -115
- solara/widgets/widgets.py +0 -65
- solara-1.30.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -7
- solara-1.30.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -7
- solara-1.30.0.dist-info/RECORD +0 -438
- solara-1.30.0.dist-info/entry_points.txt +0 -5
- /solara-1.30.0.dist-info/licenses/LICENSE → /LICENSE +0 -0
solara/scope/__init__.py
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import sys
|
|
3
|
-
import threading
|
|
4
|
-
from typing import MutableMapping
|
|
5
|
-
|
|
6
|
-
from .types import ObservableMutableMapping
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def _in_solara_server():
|
|
10
|
-
return "solara.server" in sys.modules
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ConnectionScope(ObservableMutableMapping):
|
|
14
|
-
def __init__(self, name="connection"):
|
|
15
|
-
super().__init__()
|
|
16
|
-
self._global_dict = {}
|
|
17
|
-
self.name = name
|
|
18
|
-
self.lock = threading.Lock()
|
|
19
|
-
|
|
20
|
-
def _get_dict(self) -> MutableMapping:
|
|
21
|
-
if _in_solara_server():
|
|
22
|
-
import solara.server.kernel_context
|
|
23
|
-
|
|
24
|
-
context = solara.server.kernel_context.get_current_context()
|
|
25
|
-
if self.name not in context.user_dicts:
|
|
26
|
-
with self.lock:
|
|
27
|
-
if self.name not in context.user_dicts:
|
|
28
|
-
context.user_dicts[self.name] = {}
|
|
29
|
-
return context.user_dicts[self.name]
|
|
30
|
-
else:
|
|
31
|
-
return self._global_dict
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class ObservableDict(ObservableMutableMapping):
|
|
35
|
-
def __init__(self):
|
|
36
|
-
super().__init__()
|
|
37
|
-
self._global_dict = {}
|
|
38
|
-
|
|
39
|
-
def _get_dict(self) -> MutableMapping:
|
|
40
|
-
return self._global_dict
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
worker = ObservableDict()
|
|
44
|
-
connection = ConnectionScope()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def get_kernel_id(ipython_fallback=True) -> str:
|
|
48
|
-
"""Returns the kernel id, a unique string for each virtual kernel.
|
|
49
|
-
|
|
50
|
-
See [Understanding solara server](/docs/understanding/solara-server) for understanding the concept of virtual kernels
|
|
51
|
-
and their lifetime.
|
|
52
|
-
|
|
53
|
-
This unique ID can be useful to to implement storing state, scoped to a kernel. See [the scope example](/examples/general/scopes) for an example.
|
|
54
|
-
|
|
55
|
-
If `ipython_fallback` is `True` (default), this function will also work in IPython notebooks, where it will return the IPython kernel id.
|
|
56
|
-
|
|
57
|
-
"""
|
|
58
|
-
import solara.server.kernel_context
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
context = solara.server.kernel_context.get_current_context()
|
|
62
|
-
except RuntimeError as e:
|
|
63
|
-
if not ipython_fallback:
|
|
64
|
-
raise
|
|
65
|
-
import IPython
|
|
66
|
-
|
|
67
|
-
ipython = IPython.get_ipython()
|
|
68
|
-
if not ipython or not hasattr(ipython, "kernel"):
|
|
69
|
-
raise RuntimeError("Not in a kernel") from e
|
|
70
|
-
kernel = ipython.kernel
|
|
71
|
-
regex = r"[\\/]kernel-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.json$"
|
|
72
|
-
connection_file = kernel.config["IPKernelApp"]["connection_file"]
|
|
73
|
-
return re.compile(regex).search(connection_file).group(1) # type: ignore
|
|
74
|
-
return context.id
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def get_session_id() -> str:
|
|
78
|
-
"""Returns the session id, which is stored using a browser cookie.
|
|
79
|
-
|
|
80
|
-
See [Understanding solara server](/docs/understanding/solara-server#session) for more information about the Solara sessions.
|
|
81
|
-
|
|
82
|
-
This unique ID can be useful to to implement storing state, scoped to a browser session. See [the scope example](/examples/general/scopes) for an example.
|
|
83
|
-
"""
|
|
84
|
-
import solara.server.kernel_context
|
|
85
|
-
|
|
86
|
-
context = solara.server.kernel_context.get_current_context()
|
|
87
|
-
return context.session_id
|
solara/scope/types.py
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
from abc import abstractmethod
|
|
3
|
-
from typing import Any, Callable, Dict, List, MutableMapping
|
|
4
|
-
from warnings import warn
|
|
5
|
-
|
|
6
|
-
ObserverCallback = Callable[[Any, Any], None]
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class MutableMappingBase(MutableMapping):
|
|
10
|
-
@abstractmethod
|
|
11
|
-
def _get_dict(self) -> MutableMapping:
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
def __delitem__(self, key) -> None:
|
|
15
|
-
self._get_dict().__delitem__(key)
|
|
16
|
-
|
|
17
|
-
def __getitem__(self, key):
|
|
18
|
-
return self._get_dict().__getitem__(key)
|
|
19
|
-
|
|
20
|
-
def __iter__(self):
|
|
21
|
-
return self._get_dict().__iter__()
|
|
22
|
-
|
|
23
|
-
def __len__(self):
|
|
24
|
-
return self._get_dict().__len__()
|
|
25
|
-
|
|
26
|
-
def __setitem__(self, key, value):
|
|
27
|
-
self._get_dict().__setitem__(key, value)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ObservableMutableMapping(MutableMappingBase):
|
|
31
|
-
# list of observers for each key
|
|
32
|
-
observers: Dict[Any, List[ObserverCallback]]
|
|
33
|
-
|
|
34
|
-
def __init__(self) -> None:
|
|
35
|
-
super().__init__()
|
|
36
|
-
self.observers = {}
|
|
37
|
-
self.lock = threading.Lock()
|
|
38
|
-
|
|
39
|
-
def subscribe_key(self, key, callback: ObserverCallback):
|
|
40
|
-
if key not in self.observers:
|
|
41
|
-
with self.lock:
|
|
42
|
-
if key not in self.observers:
|
|
43
|
-
self.observers[key] = []
|
|
44
|
-
self.observers[key].append(callback)
|
|
45
|
-
if self.observers[key].count(callback) > 1:
|
|
46
|
-
warn("Callback already subscribed")
|
|
47
|
-
|
|
48
|
-
def unsubscribe():
|
|
49
|
-
self.observers[key].remove(callback)
|
|
50
|
-
|
|
51
|
-
return unsubscribe
|
|
52
|
-
|
|
53
|
-
def trigger_key(self, key):
|
|
54
|
-
for callback in self.observers[key]:
|
|
55
|
-
callback(key, self[key])
|
solara/server/__init__.py
DELETED
|
File without changes
|
solara/server/app.py
DELETED
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
import importlib.util
|
|
3
|
-
import logging
|
|
4
|
-
import os
|
|
5
|
-
import pickle
|
|
6
|
-
import sys
|
|
7
|
-
import threading
|
|
8
|
-
import traceback
|
|
9
|
-
import warnings
|
|
10
|
-
from enum import Enum
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Any, Dict, List, Optional, cast
|
|
13
|
-
|
|
14
|
-
import ipywidgets as widgets
|
|
15
|
-
import reacton
|
|
16
|
-
from reacton.core import Element, render
|
|
17
|
-
|
|
18
|
-
import solara
|
|
19
|
-
from solara.util import nested_get
|
|
20
|
-
|
|
21
|
-
from . import kernel_context, patch, reload, settings
|
|
22
|
-
from .kernel import Kernel
|
|
23
|
-
from .utils import pdb_guard
|
|
24
|
-
|
|
25
|
-
WebSocket = Any
|
|
26
|
-
apps: Dict[str, "AppScript"] = {}
|
|
27
|
-
thread_lock = threading.Lock()
|
|
28
|
-
|
|
29
|
-
logger = logging.getLogger("solara.server.app")
|
|
30
|
-
|
|
31
|
-
reload.reloader.start()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class AppType(str, Enum):
|
|
35
|
-
SCRIPT = "script"
|
|
36
|
-
NOTEBOOK = "notebook"
|
|
37
|
-
MODULE = "module"
|
|
38
|
-
DIRECTORY = "directory"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def display(*args, **kwargs):
|
|
42
|
-
print("display not implemented", args, kwargs) # noqa
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class AppScript:
|
|
46
|
-
directory: Path
|
|
47
|
-
routes: List[solara.Route]
|
|
48
|
-
|
|
49
|
-
def __init__(self, name, default_app_name="Page"):
|
|
50
|
-
self.fullname = name
|
|
51
|
-
if reload.reloader.on_change:
|
|
52
|
-
raise RuntimeError("Previous reloader still had a on_change attached, no cleanup?")
|
|
53
|
-
reload.reloader.on_change = self.on_file_change
|
|
54
|
-
|
|
55
|
-
self.app_name = default_app_name
|
|
56
|
-
if ":" in self.fullname:
|
|
57
|
-
self.name, self.app_name = self.fullname.rsplit(":", 1)
|
|
58
|
-
if len(self.name) == 1: # a windows drive letter, restore
|
|
59
|
-
self.name = self.fullname
|
|
60
|
-
self.app_name = default_app_name
|
|
61
|
-
else:
|
|
62
|
-
self.name = name
|
|
63
|
-
self.path: Path = Path(self.name).resolve()
|
|
64
|
-
try:
|
|
65
|
-
context = kernel_context.get_current_context()
|
|
66
|
-
except RuntimeError:
|
|
67
|
-
context = None
|
|
68
|
-
if context is not None:
|
|
69
|
-
raise RuntimeError(f"We should not have an existing Solara app context when running an app for the first time: {context}")
|
|
70
|
-
dummy_kernel_context = kernel_context.create_dummy_context()
|
|
71
|
-
with dummy_kernel_context:
|
|
72
|
-
app = self._execute()
|
|
73
|
-
|
|
74
|
-
# We now ran the app, now we can check for patches that require heavy imports
|
|
75
|
-
patch.patch_heavy_imports()
|
|
76
|
-
|
|
77
|
-
self._first_execute_app = app
|
|
78
|
-
reload.reloader.root_path = self.directory
|
|
79
|
-
if self.type == AppType.MODULE:
|
|
80
|
-
package_name = self.name.split(".")[0]
|
|
81
|
-
mod = importlib.import_module(package_name)
|
|
82
|
-
if mod.__file__ is not None:
|
|
83
|
-
package_root_path = Path(mod.__file__).parent
|
|
84
|
-
reload.reloader.root_path = package_root_path
|
|
85
|
-
dummy_kernel_context.close()
|
|
86
|
-
|
|
87
|
-
def _execute(self):
|
|
88
|
-
logger.info("Executing %s", self.name)
|
|
89
|
-
app = None
|
|
90
|
-
routes: Optional[List[solara.Route]] = None
|
|
91
|
-
|
|
92
|
-
def add_path():
|
|
93
|
-
# this is not expected for modules, similar to `python script.py and python -m package.mymodule`
|
|
94
|
-
if self.type in [AppType.SCRIPT, AppType.NOTEBOOK]:
|
|
95
|
-
working_directory = str(self.path.parent)
|
|
96
|
-
if working_directory not in sys.path:
|
|
97
|
-
sys.path.insert(0, working_directory)
|
|
98
|
-
|
|
99
|
-
if self.path.is_dir():
|
|
100
|
-
self.type = AppType.DIRECTORY
|
|
101
|
-
# resolve the directory, because Path("file").parent.parent == "." != ".."
|
|
102
|
-
self.directory = self.path.resolve()
|
|
103
|
-
routes = solara.generate_routes_directory(self.path)
|
|
104
|
-
|
|
105
|
-
if any(name for name in sys.modules.keys() if name.startswith(self.name)):
|
|
106
|
-
logger.warn(
|
|
107
|
-
f"Directory {self.name} is also used as a package. This can cause modules to be loaded twice, and might "
|
|
108
|
-
"cause unexpected behavior. If you run solara from a different directory (e.g. the parent directory) you "
|
|
109
|
-
"can avoid this ambiguity."
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
elif self.name.endswith(".py"):
|
|
113
|
-
self.type = AppType.SCRIPT
|
|
114
|
-
add_path()
|
|
115
|
-
# manually add the script to the watcher
|
|
116
|
-
reload.reloader.watcher.add_file(self.path)
|
|
117
|
-
self.directory = self.path.parent.resolve()
|
|
118
|
-
initial_namespace = {
|
|
119
|
-
"__name__": "__main__",
|
|
120
|
-
}
|
|
121
|
-
with reload.reloader.watch():
|
|
122
|
-
routes = [solara.autorouting._generate_route_path(self.path, first=True, initial_namespace=initial_namespace)]
|
|
123
|
-
elif self.name.endswith(".ipynb"):
|
|
124
|
-
self.type = AppType.NOTEBOOK
|
|
125
|
-
add_path()
|
|
126
|
-
# manually add the notebook to the watcher
|
|
127
|
-
reload.reloader.watcher.add_file(self.path)
|
|
128
|
-
self.directory = self.path.parent.resolve()
|
|
129
|
-
with reload.reloader.watch():
|
|
130
|
-
routes = [solara.autorouting._generate_route_path(self.path, first=True)]
|
|
131
|
-
else:
|
|
132
|
-
# the module itself will be added by reloader
|
|
133
|
-
# automatically
|
|
134
|
-
with reload.reloader.watch():
|
|
135
|
-
self.type = AppType.MODULE
|
|
136
|
-
try:
|
|
137
|
-
spec = importlib.util.find_spec(self.name)
|
|
138
|
-
except ValueError:
|
|
139
|
-
if self.name not in sys.modules:
|
|
140
|
-
raise ImportError(f"Module {self.name} not found")
|
|
141
|
-
spec = importlib.util.spec_from_file_location(self.name, sys.modules[self.name].__file__)
|
|
142
|
-
if spec is None:
|
|
143
|
-
raise ImportError(f"Module {self.name} cannot be found")
|
|
144
|
-
assert spec is not None
|
|
145
|
-
if spec.origin is None:
|
|
146
|
-
raise ImportError(f"Module {self.name} cannot be found, or is a namespace package")
|
|
147
|
-
assert spec.origin is not None
|
|
148
|
-
self.path = Path(spec.origin)
|
|
149
|
-
self.directory = self.path.parent
|
|
150
|
-
|
|
151
|
-
mod = importlib.import_module(self.name)
|
|
152
|
-
routes = solara.generate_routes(mod)
|
|
153
|
-
|
|
154
|
-
app = solara.autorouting.RenderPage(self.app_name)
|
|
155
|
-
|
|
156
|
-
# when the root moduled defined routes, skip the enclosing route object
|
|
157
|
-
if len(routes) == 1 and routes[0].module and hasattr(routes[0].module, "routes"):
|
|
158
|
-
if routes[0].component:
|
|
159
|
-
warnings.warn(
|
|
160
|
-
f"{self.name} has a component defined, but you are also defining routes."
|
|
161
|
-
" To avoid confusing, consider renaming the {self.app_name} component."
|
|
162
|
-
)
|
|
163
|
-
routes = routes[0].children
|
|
164
|
-
|
|
165
|
-
if self.app_name != "Page":
|
|
166
|
-
# if we specified the app name, we replace the component
|
|
167
|
-
if len(routes) > 1:
|
|
168
|
-
raise ValueError(f"App {self.name} has multiple routes, but a default app name was given: {self.app_name}")
|
|
169
|
-
assert len(routes) == 1
|
|
170
|
-
component = nested_get(routes[0].module.__dict__, self.app_name, None)
|
|
171
|
-
routes = [dataclasses.replace(routes[0], component=component)]
|
|
172
|
-
|
|
173
|
-
if settings.ssg.build_path is None:
|
|
174
|
-
settings.ssg.build_path = self.directory.parent.resolve() / "build"
|
|
175
|
-
|
|
176
|
-
# auto enable search if search.json exists
|
|
177
|
-
search_index_file = self.directory.parent / "assets" / "search.json"
|
|
178
|
-
if search_index_file.exists():
|
|
179
|
-
settings.search.enabled = True
|
|
180
|
-
|
|
181
|
-
# this might be useful for development
|
|
182
|
-
# but requires reloading of react in solara itself
|
|
183
|
-
# for name, module in sys.modules.items():
|
|
184
|
-
# if name.startswith("reacton"):
|
|
185
|
-
# file = inspect.getfile(module)
|
|
186
|
-
# self.watcher.add_file(file)
|
|
187
|
-
|
|
188
|
-
# cgi vars: https://datatracker.ietf.org/doc/html/rfc3875
|
|
189
|
-
# we cannot set script name, because gunicorn uses it (and will crash)
|
|
190
|
-
# os.environ["SCRIPT_NAME"] = self.name
|
|
191
|
-
os.environ["PATH_TRANSLATED"] = str(self.path.resolve())
|
|
192
|
-
|
|
193
|
-
self.routes = routes
|
|
194
|
-
|
|
195
|
-
# this might be useful for development
|
|
196
|
-
# but requires reloading of react in solara itself
|
|
197
|
-
# for name, module in sys.modules.items():
|
|
198
|
-
# if name.startswith("reacton"):
|
|
199
|
-
# file = inspect.getfile(module)
|
|
200
|
-
# self.watcher.add_file(file)
|
|
201
|
-
|
|
202
|
-
# cgi vars: https://datatracker.ietf.org/doc/html/rfc3875
|
|
203
|
-
# we cannot set script name, because gunicorn uses it (and will crash)
|
|
204
|
-
# os.environ["SCRIPT_NAME"] = self.name
|
|
205
|
-
os.environ["PATH_TRANSLATED"] = str(self.path.resolve())
|
|
206
|
-
return app
|
|
207
|
-
|
|
208
|
-
def close(self):
|
|
209
|
-
reload.reloader.on_change = None
|
|
210
|
-
context_values = list(kernel_context.contexts.values())
|
|
211
|
-
kernel_context.contexts.clear()
|
|
212
|
-
for context in context_values:
|
|
213
|
-
context.close()
|
|
214
|
-
|
|
215
|
-
def run(self):
|
|
216
|
-
if reload.reloader.requires_reload or self._first_execute_app is None:
|
|
217
|
-
with thread_lock:
|
|
218
|
-
if reload.reloader.requires_reload or self._first_execute_app is None:
|
|
219
|
-
self._first_execute_app = None
|
|
220
|
-
self._first_execute_app = self._execute()
|
|
221
|
-
print("Re-executed app", self.name) # noqa
|
|
222
|
-
# We now ran the app again, might contain new imports
|
|
223
|
-
patch.patch_heavy_imports()
|
|
224
|
-
|
|
225
|
-
return self._first_execute_app
|
|
226
|
-
|
|
227
|
-
def on_file_change(self, name):
|
|
228
|
-
path = Path(name)
|
|
229
|
-
if path.suffix == ".vue":
|
|
230
|
-
logger.info("Vue file changed: %s", name)
|
|
231
|
-
template_content = path.read_text()
|
|
232
|
-
for context in list(kernel_context.contexts.values()):
|
|
233
|
-
with context:
|
|
234
|
-
for filepath, widget in context.templates.items():
|
|
235
|
-
if filepath == str(path):
|
|
236
|
-
widget.template = template_content
|
|
237
|
-
else:
|
|
238
|
-
logger.info("Reload requires due to change in module: %s", name)
|
|
239
|
-
self.reload()
|
|
240
|
-
|
|
241
|
-
def reload(self):
|
|
242
|
-
# if multiple files change in a short time, we want to do this
|
|
243
|
-
# not concurrently. Even better would be to do a debounce?
|
|
244
|
-
with thread_lock:
|
|
245
|
-
# TODO: clearing the type_counter is a bit of a hack
|
|
246
|
-
# and we should introduce reload 'hooks', so there is
|
|
247
|
-
# less interdependency between modules
|
|
248
|
-
import solara.lab.toestand
|
|
249
|
-
|
|
250
|
-
solara.lab.toestand.ConnectionStore._type_counter.clear()
|
|
251
|
-
|
|
252
|
-
# we need to remove callbacks that are added in the app code
|
|
253
|
-
# which will be re-executed after the reload and we do not
|
|
254
|
-
# want to keep executing the old ones.
|
|
255
|
-
for kc in kernel_context._on_kernel_start_callbacks.copy():
|
|
256
|
-
callback, path, module, cleanup = kc
|
|
257
|
-
will_reload = False
|
|
258
|
-
if module is not None:
|
|
259
|
-
module_name = module.__name__
|
|
260
|
-
if module_name in reload.reloader.get_reload_module_names():
|
|
261
|
-
will_reload = True
|
|
262
|
-
elif path is not None:
|
|
263
|
-
if str(path.resolve()).startswith(str(self.directory)):
|
|
264
|
-
will_reload = True
|
|
265
|
-
else:
|
|
266
|
-
logger.warning(
|
|
267
|
-
"script %s is not in the same directory as the app %s but is using on_kernel_start, "
|
|
268
|
-
"this might lead to multiple entries, and might indicate a bug.",
|
|
269
|
-
path,
|
|
270
|
-
self.directory,
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
if will_reload:
|
|
274
|
-
logger.info("reload: Removing on_kernel_start callback: %s (since it will be added when reloaded)", callback)
|
|
275
|
-
cleanup()
|
|
276
|
-
|
|
277
|
-
context_values = list(kernel_context.contexts.values())
|
|
278
|
-
# save states into the context so the hot reload will
|
|
279
|
-
# keep the same state
|
|
280
|
-
for context in context_values:
|
|
281
|
-
render_context = cast(reacton.core._RenderContext, context.app_object)
|
|
282
|
-
if render_context:
|
|
283
|
-
with context:
|
|
284
|
-
# we save the state for when the app reruns, so we stay in the same state.
|
|
285
|
-
# (e.g. button clicks, chosen options etc)
|
|
286
|
-
# for instance a dataframe, needs to be pickled, because after the pandas
|
|
287
|
-
# module is reloaded, it's a different class type
|
|
288
|
-
logger.info("pickling state: %s", render_context.state_get())
|
|
289
|
-
try:
|
|
290
|
-
context.state = pickle.dumps(render_context.state_get())
|
|
291
|
-
except Exception as e:
|
|
292
|
-
logger.warning("Could not pickle state, next render the state will be lost: %s", e)
|
|
293
|
-
# clear/cleanup the render_context, so during reload we start
|
|
294
|
-
# from scratch
|
|
295
|
-
context.app_object = None
|
|
296
|
-
# we want to reuse the container
|
|
297
|
-
render_context.container = None
|
|
298
|
-
try:
|
|
299
|
-
render_context.close()
|
|
300
|
-
except Exception as e:
|
|
301
|
-
logger.exception("Could not close render context: %s", e)
|
|
302
|
-
|
|
303
|
-
# ask all contexts/users to reload
|
|
304
|
-
for context in context_values:
|
|
305
|
-
with context:
|
|
306
|
-
context.reload()
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
def _run_app(
|
|
310
|
-
app_state,
|
|
311
|
-
app_script: AppScript,
|
|
312
|
-
pathname: str,
|
|
313
|
-
render_context: reacton.core._RenderContext = None,
|
|
314
|
-
):
|
|
315
|
-
# app.signal_hook_install()
|
|
316
|
-
main_object = app_script.run()
|
|
317
|
-
app_state = pickle.loads(app_state) if app_state is not None else None
|
|
318
|
-
if app_state:
|
|
319
|
-
logger.info("Restoring state: %r", app_state)
|
|
320
|
-
|
|
321
|
-
context = kernel_context.get_current_context()
|
|
322
|
-
container = context.container
|
|
323
|
-
if isinstance(main_object, widgets.Widget):
|
|
324
|
-
return main_object, render_context
|
|
325
|
-
elif isinstance(main_object, Element) or isinstance(main_object, reacton.core.Component):
|
|
326
|
-
if isinstance(main_object, Element):
|
|
327
|
-
children = [main_object]
|
|
328
|
-
else:
|
|
329
|
-
children = [main_object()]
|
|
330
|
-
solara_context = solara.RoutingProvider(children=children, routes=app_script.routes, pathname=pathname)
|
|
331
|
-
if render_context is None:
|
|
332
|
-
result = render(solara_context, container, handle_error=True, initial_state=app_state)
|
|
333
|
-
# support older versions of react
|
|
334
|
-
if isinstance(result, tuple):
|
|
335
|
-
container, render_context = result
|
|
336
|
-
else:
|
|
337
|
-
render_context = result
|
|
338
|
-
else:
|
|
339
|
-
if app_state:
|
|
340
|
-
render_context.state_set(render_context.context_root, app_state)
|
|
341
|
-
result = render_context.render(solara_context)
|
|
342
|
-
container = render_context.container
|
|
343
|
-
# return container, render_context
|
|
344
|
-
else:
|
|
345
|
-
extra = ""
|
|
346
|
-
dotted = []
|
|
347
|
-
for key, value in vars(main_object).items():
|
|
348
|
-
if isinstance(value, (Element, widgets.Widget)):
|
|
349
|
-
dotted.append(f"{app_script.app_name}.{key}")
|
|
350
|
-
if dotted:
|
|
351
|
-
extra = " We did find that sub objects that might work: " + ", ".join(dotted)
|
|
352
|
-
raise ValueError(
|
|
353
|
-
f"Main object (with name {app_script.app_name} in {app_script.path}) is not a Widget, Element or Component, but {type(main_object)}." + extra
|
|
354
|
-
)
|
|
355
|
-
return container, render_context
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def load_app_widget(app_state, app_script: AppScript, pathname: str):
|
|
359
|
-
# load the app, and set it at the child of the context's container
|
|
360
|
-
app_state_initial = app_state
|
|
361
|
-
context = kernel_context.get_current_context()
|
|
362
|
-
container = context.container
|
|
363
|
-
assert container is not None
|
|
364
|
-
try:
|
|
365
|
-
import ipyreact
|
|
366
|
-
|
|
367
|
-
del ipyreact
|
|
368
|
-
except ModuleNotFoundError:
|
|
369
|
-
pass
|
|
370
|
-
else:
|
|
371
|
-
import solara.server.esm
|
|
372
|
-
|
|
373
|
-
# will create widgets, but will clean itself up when the kernel closes
|
|
374
|
-
solara.server.esm.create_modules()
|
|
375
|
-
solara.server.esm.create_import_map()
|
|
376
|
-
|
|
377
|
-
try:
|
|
378
|
-
render_context = context.app_object
|
|
379
|
-
app_state = app_state_initial
|
|
380
|
-
with pdb_guard():
|
|
381
|
-
widget, render_context = _run_app(
|
|
382
|
-
app_state,
|
|
383
|
-
app_script,
|
|
384
|
-
pathname,
|
|
385
|
-
render_context=render_context,
|
|
386
|
-
)
|
|
387
|
-
if render_context is None:
|
|
388
|
-
assert context.container is not None
|
|
389
|
-
context.container.children = [widget]
|
|
390
|
-
|
|
391
|
-
if render_context:
|
|
392
|
-
context.app_object = render_context
|
|
393
|
-
|
|
394
|
-
except BaseException as e:
|
|
395
|
-
error = ""
|
|
396
|
-
error = "".join(traceback.format_exception(None, e, e.__traceback__))
|
|
397
|
-
print(error, file=sys.stdout, flush=True) # noqa
|
|
398
|
-
# widget = widgets.Label(value="Error, see server logs")
|
|
399
|
-
import html
|
|
400
|
-
|
|
401
|
-
error = html.escape(error)
|
|
402
|
-
with context:
|
|
403
|
-
widget = widgets.HTML(f"<pre>{error}</pre>", layout=widgets.Layout(overflow="auto"))
|
|
404
|
-
container.children = [widget]
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
def load_themes(themes: Dict[str, Dict[str, str]], dark: bool):
|
|
408
|
-
# While these usually gets set from the frontend, in solara (server) we want to know theme information directly at the first
|
|
409
|
-
# render. Also, using the same trait allows us to write code which works on all widgets platforms, instead
|
|
410
|
-
# or using something different when running under solara server
|
|
411
|
-
from solara.lab.components.theming import _set_theme, theme
|
|
412
|
-
|
|
413
|
-
_set_theme(themes)
|
|
414
|
-
theme.dark_effective = dark
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
def solara_comm_target(comm, msg_first):
|
|
418
|
-
app: Optional[AppScript] = None
|
|
419
|
-
|
|
420
|
-
def on_msg(msg):
|
|
421
|
-
nonlocal app
|
|
422
|
-
data = msg["content"]["data"]
|
|
423
|
-
method = data["method"]
|
|
424
|
-
if method == "run":
|
|
425
|
-
args = data["args"]
|
|
426
|
-
path = args.get("path", "")
|
|
427
|
-
app_name = args.get("appName") or "__default__"
|
|
428
|
-
app = apps[app_name]
|
|
429
|
-
context = kernel_context.get_current_context()
|
|
430
|
-
import ipyvuetify
|
|
431
|
-
|
|
432
|
-
container = ipyvuetify.Html(tag="div")
|
|
433
|
-
context.container = container
|
|
434
|
-
themes = args.get("themes")
|
|
435
|
-
dark = args.get("dark")
|
|
436
|
-
load_themes(themes, dark)
|
|
437
|
-
load_app_widget(None, app, path)
|
|
438
|
-
comm.send({"method": "finished", "widget_id": context.container._model_id})
|
|
439
|
-
elif method == "app-status":
|
|
440
|
-
context = kernel_context.get_current_context()
|
|
441
|
-
# if there is no container, we never ran the app
|
|
442
|
-
if context.container is not None:
|
|
443
|
-
logger.info("app-status check: %s app started", context.id)
|
|
444
|
-
comm.send({"method": "app-status", "started": True})
|
|
445
|
-
else:
|
|
446
|
-
logger.info("app-status check: %s app not started", context.id)
|
|
447
|
-
comm.send({"method": "app-status", "started": False})
|
|
448
|
-
|
|
449
|
-
elif method == "reload":
|
|
450
|
-
from solara.lab.components.theming import _get_theme, theme
|
|
451
|
-
|
|
452
|
-
assert app is not None
|
|
453
|
-
context = kernel_context.get_current_context()
|
|
454
|
-
path = data.get("path", "")
|
|
455
|
-
current_theme = theme._instance.value
|
|
456
|
-
theme_dict = _get_theme(current_theme)
|
|
457
|
-
|
|
458
|
-
with context:
|
|
459
|
-
context.restart()
|
|
460
|
-
load_themes(theme_dict, current_theme.dark_effective)
|
|
461
|
-
load_app_widget(context.state, app, path)
|
|
462
|
-
comm.send({"method": "finished"})
|
|
463
|
-
else:
|
|
464
|
-
logger.error("Unknown comm method called on solara.control comm: %s", method)
|
|
465
|
-
|
|
466
|
-
comm.on_msg(on_msg)
|
|
467
|
-
|
|
468
|
-
def reload():
|
|
469
|
-
# we don't reload the app ourself, we send a message to the client
|
|
470
|
-
# this ensures that we don't run code of any client that for some reason is connected
|
|
471
|
-
# but not working anymore. And it indirectly passes a message from the current thread
|
|
472
|
-
# (which is that of the Reloader/watchdog), to the thread of the client
|
|
473
|
-
logger.debug(f"Send reload to client: {context.id}")
|
|
474
|
-
comm.send({"method": "reload"})
|
|
475
|
-
|
|
476
|
-
context = kernel_context.get_current_context()
|
|
477
|
-
context.reload = reload
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
def register_solara_comm_target(kernel: Kernel):
|
|
481
|
-
kernel.comm_manager.register_target("solara.control", solara_comm_target)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
from . import patch # noqa
|
|
485
|
-
|
|
486
|
-
patch.patch()
|
|
487
|
-
# the default app (used in solara-server)
|
|
488
|
-
if "SOLARA_APP" in os.environ:
|
|
489
|
-
with pdb_guard():
|
|
490
|
-
apps["__default__"] = AppScript(os.environ.get("SOLARA_APP", "solara.website.pages:Page"))
|
solara/server/assets/custom.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/* not empty *
|
solara/server/assets/custom.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/* not empty */
|
solara/server/assets/favicon.png
DELETED
|
Binary file
|
solara/server/assets/favicon.svg
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="65" height="65"><svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<path d="M57.11 30.64L61.47 17.87L48.7 13.51L42.76 1.39999L30.65 7.34999L17.87 2.97999L13.51 15.75L1.40002 21.7L7.35002 33.81L2.99002 46.58L15.76 50.94L21.71 63.06L33.82 57.11L46.59 61.47L50.95 48.7L63.06 42.75L57.11 30.64ZM54.26 34.39L34.39 54.26C33.19 55.46 31.25 55.46 30.05 54.26L10.2 34.4C9.00002 33.2 9.00002 31.26 10.2 30.07L30.06 10.2C31.26 8.99999 33.2 8.99999 34.4 10.2L54.27 30.07C55.47 31.27 55.47 33.21 54.27 34.4L54.26 34.39Z" fill="#FFCF64"></path>
|
|
3
|
-
<path d="M53.62 19.42L51.65 6.07L38.3 8.04L27.46 0L19.42 10.84L6.07 12.82L8.04 26.17L0 37L10.84 45.04L12.81 58.39L26.16 56.42L37 64.46L45.04 53.62L58.39 51.64L56.42 38.29L64.46 27.45L53.62 19.4V19.42ZM52.8 24.06L44.24 50.82C43.72 52.43 42 53.32 40.39 52.81L13.63 44.25C12.02 43.74 11.13 42.01 11.64 40.4L20.21 13.64C20.72 12.03 22.45 11.14 24.06 11.65L50.82 20.21C52.43 20.72 53.32 22.45 52.81 24.06H52.8Z" fill="#FF8C3E"></path>
|
|
4
|
-
</svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
|
|
5
|
-
</style></svg>
|