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/alias.py
DELETED
solara/autorouting.py
DELETED
|
@@ -1,554 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
import difflib
|
|
3
|
-
import importlib
|
|
4
|
-
import inspect
|
|
5
|
-
import pkgutil
|
|
6
|
-
import re
|
|
7
|
-
import warnings
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from types import ModuleType
|
|
10
|
-
from typing import Any, Callable, Dict, List, Optional, cast
|
|
11
|
-
|
|
12
|
-
import ipywidgets
|
|
13
|
-
import reacton
|
|
14
|
-
import reacton.core
|
|
15
|
-
|
|
16
|
-
import solara
|
|
17
|
-
import solara.checks
|
|
18
|
-
from solara.alias import rv
|
|
19
|
-
from solara.util import cwd, nested_get
|
|
20
|
-
|
|
21
|
-
autoroute_level_context = solara.create_context(0)
|
|
22
|
-
DEBUG = False
|
|
23
|
-
|
|
24
|
-
solara_root = Path(solara.__file__).parent
|
|
25
|
-
|
|
26
|
-
DefaultLayout = solara.AppLayout
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def source_to_module(path: Path, initial_namespace={}) -> ModuleType:
|
|
30
|
-
fullname = path.stem
|
|
31
|
-
mod = ModuleType(fullname)
|
|
32
|
-
mod.__file__ = str(path)
|
|
33
|
-
mod.__dict__.update(initial_namespace)
|
|
34
|
-
if path.suffix == ".py":
|
|
35
|
-
with open(path, encoding="utf8") as f:
|
|
36
|
-
ast = compile(f.read(), path, "exec")
|
|
37
|
-
exec(ast, mod.__dict__)
|
|
38
|
-
elif path.suffix == ".ipynb":
|
|
39
|
-
import nbformat
|
|
40
|
-
|
|
41
|
-
nb: nbformat.NotebookNode = nbformat.read(path, 4)
|
|
42
|
-
with cwd(Path(path).parent):
|
|
43
|
-
for cell_index, cell in enumerate(nb.cells):
|
|
44
|
-
cell_index += 1 # used 1 based
|
|
45
|
-
if cell.cell_type == "code":
|
|
46
|
-
source = cell.source
|
|
47
|
-
cell_path = f"{path} input cell {cell_index}"
|
|
48
|
-
ast = compile(source, cell_path, "exec")
|
|
49
|
-
exec(ast, mod.__dict__)
|
|
50
|
-
else:
|
|
51
|
-
raise TypeError(f"Only .py and .ipynb supported (not {path})")
|
|
52
|
-
return mod
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def count_arguments(f: Callable):
|
|
56
|
-
if isinstance(f, reacton.core.ComponentFunction):
|
|
57
|
-
f = f.f
|
|
58
|
-
sig = inspect.signature(f)
|
|
59
|
-
return len([k for name, k in sig.parameters.items() if (k.default == k.empty) and (k.kind != k.VAR_POSITIONAL) and (k.kind != k.VAR_KEYWORD)])
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def arg_cast(args: List[str], f: Callable):
|
|
63
|
-
if isinstance(f, reacton.core.ComponentFunction):
|
|
64
|
-
f = f.f
|
|
65
|
-
sig = inspect.signature(f)
|
|
66
|
-
results = []
|
|
67
|
-
for i, (name, param) in enumerate(sig.parameters.items()):
|
|
68
|
-
if i >= len(args):
|
|
69
|
-
break
|
|
70
|
-
# TODO: can we give a better error message?
|
|
71
|
-
# raise TypeError(f"{f} expected positional argument {param}, but not enough argument supplied")
|
|
72
|
-
annotation = param.annotation
|
|
73
|
-
value = args[i]
|
|
74
|
-
check_optional_types = [str, int, float]
|
|
75
|
-
for check_type in check_optional_types:
|
|
76
|
-
if annotation == Optional[check_type]:
|
|
77
|
-
annotation = check_type
|
|
78
|
-
if annotation == param.empty:
|
|
79
|
-
results.append(value)
|
|
80
|
-
else:
|
|
81
|
-
try:
|
|
82
|
-
results.append(annotation(value))
|
|
83
|
-
except Exception as e:
|
|
84
|
-
raise ValueError(f"Cannot cast argument {name} of {f} to type {annotation} with value {value}") from e
|
|
85
|
-
return results
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@solara.component
|
|
89
|
-
def RoutingProvider(children: List[reacton.core.Element] = [], routes: List[solara.Route] = [], pathname: str = ""):
|
|
90
|
-
"""Wraps the app, adds extra context, like navigation/routing."""
|
|
91
|
-
path, set_path = solara.use_state(pathname, key="solara-context-path")
|
|
92
|
-
# TODO: since we provide a cross filter context here, I don't think name `RoutingProvider` is a good name
|
|
93
|
-
# we might want to change/refactor this.
|
|
94
|
-
solara.provide_cross_filter()
|
|
95
|
-
nav = solara.Navigator(location=path, on_location=set_path)
|
|
96
|
-
solara.routing._location_context.provide(solara.routing._Location(path, set_path))
|
|
97
|
-
solara.routing.router_context.provide(solara.routing.Router(path, routes=routes, set_path=set_path))
|
|
98
|
-
|
|
99
|
-
def get_nav_widget():
|
|
100
|
-
# not sure why get_widget(nav) does not work
|
|
101
|
-
nav_widget.current = solara.get_widget(main).children[0] # type: ignore
|
|
102
|
-
|
|
103
|
-
import solara.widgets as w
|
|
104
|
-
|
|
105
|
-
nav_widget = solara.use_ref(cast(Optional[w.Navigator], None))
|
|
106
|
-
if nav_widget.current:
|
|
107
|
-
nav_widget.current.location = path
|
|
108
|
-
solara.use_effect(get_nav_widget)
|
|
109
|
-
|
|
110
|
-
if solara.checks.should_perform_solara_check():
|
|
111
|
-
children = [solara.checks.SolaraCheck(), *children]
|
|
112
|
-
|
|
113
|
-
main = solara.VBox(
|
|
114
|
-
children=[
|
|
115
|
-
nav,
|
|
116
|
-
*children,
|
|
117
|
-
]
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
return main
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@solara.component
|
|
124
|
-
def RenderPage(main_name: str = "Page"):
|
|
125
|
-
"""Renders the page that matches the route."""
|
|
126
|
-
router = solara.use_context(solara.routing.router_context)
|
|
127
|
-
# we use these to cache script runs that use regular ipywidgets
|
|
128
|
-
modules = cast(Dict[str, ModuleType], solara.use_memo(dict, dependencies=[]))
|
|
129
|
-
modules_modified_times = cast(Dict[str, float], solara.use_memo(dict, dependencies=[]))
|
|
130
|
-
|
|
131
|
-
if not router.path_routes:
|
|
132
|
-
with solara.VBox() as main:
|
|
133
|
-
solara.Error(f"Page not found: {router.path}")
|
|
134
|
-
parent = "/" + "/".join(router.parts[:-1])
|
|
135
|
-
with solara.Link(parent):
|
|
136
|
-
solara.Button(f"Go to parent: {parent}", text=True)
|
|
137
|
-
if DEBUG:
|
|
138
|
-
from reacton.core import pp
|
|
139
|
-
|
|
140
|
-
from solara.components.captureoutput import CaptureOutput
|
|
141
|
-
|
|
142
|
-
with CaptureOutput():
|
|
143
|
-
pp(router.routes)
|
|
144
|
-
return main
|
|
145
|
-
|
|
146
|
-
layouts = [] # nested layouts
|
|
147
|
-
level_max = len(router.path_routes) - 1
|
|
148
|
-
for level in range(level_max + 1):
|
|
149
|
-
# we always level_start the 'package'/'root' layout
|
|
150
|
-
roots = [k for k in router.path_routes_siblings[level] if k.path == "/"]
|
|
151
|
-
if len(roots) == 1:
|
|
152
|
-
root = roots[0]
|
|
153
|
-
if root.layout:
|
|
154
|
-
layouts.append(root.layout)
|
|
155
|
-
route = router.path_routes[level]
|
|
156
|
-
# and, if not the root layout, include the layout for the current route
|
|
157
|
-
if route.path != "/" and route.layout:
|
|
158
|
-
layouts.append(route.layout)
|
|
159
|
-
# used in for example the docs for use_route, only the route path are specified,
|
|
160
|
-
# nothing else, which means we will not follow that route path, but limit it to rendering
|
|
161
|
-
# router.path_routes[level_max] instead. It's assumed that component (Page) will continue
|
|
162
|
-
# handling the rest of the routing
|
|
163
|
-
if route.data is None and route.module is None and route.component is None:
|
|
164
|
-
level_max = level - 1
|
|
165
|
-
route_current = router.path_routes[level_max]
|
|
166
|
-
routes_siblings = router.path_routes_siblings[level_max]
|
|
167
|
-
routes_siblings_index = routes_siblings.index(route_current)
|
|
168
|
-
# if no layouts are found, we use the default layout
|
|
169
|
-
if layouts == []:
|
|
170
|
-
layouts = [DefaultLayout]
|
|
171
|
-
if route_current.data is None and route_current.module is None and route_current.component is None:
|
|
172
|
-
return solara.Error(f"Page not found: {router.path}, route does not link to a path or module or component")
|
|
173
|
-
|
|
174
|
-
def wrap_in_layouts(element: reacton.core.Element, layouts):
|
|
175
|
-
for Layout in reversed(layouts):
|
|
176
|
-
element = Layout(children=[element])
|
|
177
|
-
return element
|
|
178
|
-
|
|
179
|
-
def get_args(f):
|
|
180
|
-
if len(router.path_routes) < len(router.parts):
|
|
181
|
-
arg_strings = router.parts[len(router.path_routes) :]
|
|
182
|
-
args = arg_cast(arg_strings, f)
|
|
183
|
-
return args
|
|
184
|
-
else:
|
|
185
|
-
return []
|
|
186
|
-
|
|
187
|
-
if isinstance(route_current.data, Path):
|
|
188
|
-
path = cast(Path, route_current.data)
|
|
189
|
-
if path.suffix == ".md":
|
|
190
|
-
with solara.HBox() as navigation:
|
|
191
|
-
if routes_siblings_index > 0:
|
|
192
|
-
prev = routes_siblings[routes_siblings_index - 1]
|
|
193
|
-
with solara.Link(prev):
|
|
194
|
-
solara.Button(f"{prev.label}", text=True, icon_name="mdi-arrow-left")
|
|
195
|
-
rv.Spacer()
|
|
196
|
-
if routes_siblings_index < len(routes_siblings) - 1:
|
|
197
|
-
next = routes_siblings[routes_siblings_index + 1]
|
|
198
|
-
with solara.Link(next):
|
|
199
|
-
solara.Button(f"{next.label}", text=True, icon_name="mdi-arrow-right")
|
|
200
|
-
is_relative = str(path.resolve()).startswith(str(solara_root.resolve()))
|
|
201
|
-
if is_relative:
|
|
202
|
-
# this is now hardcoded to solara only
|
|
203
|
-
url = solara.util.github_edit_url(path)
|
|
204
|
-
with solara.Div(style={"position": "relative"}) as content:
|
|
205
|
-
with solara.Tooltip("Edit on GitHub"):
|
|
206
|
-
solara.Button(
|
|
207
|
-
icon_name="mdi-pencil", icon=True, href=url, target="_blank", style={"position": "absolute", "top": "0px", "right": "0px"}
|
|
208
|
-
)
|
|
209
|
-
solara.Markdown(path.read_text(), unsafe_solara_execute=True)
|
|
210
|
-
else:
|
|
211
|
-
content = solara.Markdown(path.read_text(), unsafe_solara_execute=True)
|
|
212
|
-
|
|
213
|
-
main = solara.Div(
|
|
214
|
-
classes=["solara-autorouter-content"],
|
|
215
|
-
children=[
|
|
216
|
-
solara.Title(route_current.label or "No title"),
|
|
217
|
-
content,
|
|
218
|
-
navigation,
|
|
219
|
-
],
|
|
220
|
-
)
|
|
221
|
-
main = wrap_in_layouts(main, layouts)
|
|
222
|
-
else:
|
|
223
|
-
main = solara.Error(f"Suffix {path.suffix} not supported")
|
|
224
|
-
else:
|
|
225
|
-
title = route_current.label or "No title"
|
|
226
|
-
title_element = solara.Title(title)
|
|
227
|
-
module = None
|
|
228
|
-
Page = route_current.component
|
|
229
|
-
if route_current.module is not None and (Page is None):
|
|
230
|
-
# if not a custom component is given, we try to find a Page component
|
|
231
|
-
# in the module
|
|
232
|
-
assert route_current.module is not None
|
|
233
|
-
module = route_current.module
|
|
234
|
-
namespace = module.__dict__
|
|
235
|
-
Page = nested_get(namespace, main_name, Page)
|
|
236
|
-
if Page is None:
|
|
237
|
-
# app is for backwards compatibility
|
|
238
|
-
Page = namespace.get("page", namespace.get("app", Page))
|
|
239
|
-
Page = nested_get(namespace, main_name, Page)
|
|
240
|
-
|
|
241
|
-
if isinstance(Page, ipywidgets.Widget):
|
|
242
|
-
# If we have a widget, we need to execute this again for each
|
|
243
|
-
# connection, since we cannot share widgets between connections/users.
|
|
244
|
-
# We also cannot tear them down, so we cache the widget based pages.
|
|
245
|
-
# To support hot reload, we manually need to check the mtimes
|
|
246
|
-
# because the reload support for modules in reloader.py only works
|
|
247
|
-
# for modules.
|
|
248
|
-
if route_current.file is None:
|
|
249
|
-
page = solara.Error(f"{route_current.path} is not associated with a file")
|
|
250
|
-
else:
|
|
251
|
-
assert route_current.file is not None
|
|
252
|
-
if route_current.path not in modules:
|
|
253
|
-
modules[route_current.path] = source_to_module(route_current.file)
|
|
254
|
-
modules_modified_times[route_current.path] = route_current.file.stat().st_mtime
|
|
255
|
-
else:
|
|
256
|
-
if modules_modified_times[route_current.path] != route_current.file.stat().st_mtime:
|
|
257
|
-
# out of date, 'reload'
|
|
258
|
-
modules[route_current.path] = source_to_module(route_current.file)
|
|
259
|
-
modules_modified_times[route_current.path] = route_current.file.stat().st_mtime
|
|
260
|
-
Page = nested_get(modules[route_current.path], main_name, None)
|
|
261
|
-
if Page is None:
|
|
262
|
-
Page = getattr(modules[route_current.path], "app", None)
|
|
263
|
-
Page = getattr(modules[route_current.path], "page", Page)
|
|
264
|
-
main = solara.Div(
|
|
265
|
-
classes=["solara-autorouter-content"],
|
|
266
|
-
children=[
|
|
267
|
-
title_element,
|
|
268
|
-
Page,
|
|
269
|
-
],
|
|
270
|
-
)
|
|
271
|
-
main = wrap_in_layouts(main, layouts)
|
|
272
|
-
elif Page is not None:
|
|
273
|
-
if isinstance(Page, reacton.core.ComponentFunction):
|
|
274
|
-
args = get_args(Page)
|
|
275
|
-
page = Page(*args)
|
|
276
|
-
elif isinstance(Page, solara.Element):
|
|
277
|
-
page = Page
|
|
278
|
-
else:
|
|
279
|
-
page = solara.Error(f"{Page} is not a component or element, but {type(Page)}")
|
|
280
|
-
main = solara.Div(
|
|
281
|
-
classes=["solara-autorouter-content"],
|
|
282
|
-
children=[
|
|
283
|
-
title_element,
|
|
284
|
-
page,
|
|
285
|
-
],
|
|
286
|
-
)
|
|
287
|
-
main = wrap_in_layouts(main, layouts)
|
|
288
|
-
else:
|
|
289
|
-
if route_current.module:
|
|
290
|
-
path_str = route_current.module.__file__
|
|
291
|
-
local_scope = route_current.module.__dict__
|
|
292
|
-
ignore = ["display"]
|
|
293
|
-
options = [k for k in list(local_scope) if k not in ignore and not k.startswith("_")]
|
|
294
|
-
matches = difflib.get_close_matches(main_name, options)
|
|
295
|
-
msg = f"No object with name {main_name} found for {path_str}"
|
|
296
|
-
if matches:
|
|
297
|
-
msg += " Did you mean: " + " or ".join(map(repr, matches))
|
|
298
|
-
else:
|
|
299
|
-
msg += " We did find: " + " or ".join(map(repr, options))
|
|
300
|
-
else:
|
|
301
|
-
msg = f"{module} does not have a Page component or an app element"
|
|
302
|
-
|
|
303
|
-
with DefaultLayout() as main:
|
|
304
|
-
solara.Error(msg)
|
|
305
|
-
return main
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def get_page(module: ModuleType, required=True):
|
|
309
|
-
page = getattr(module, "Page", None)
|
|
310
|
-
if required and page is None:
|
|
311
|
-
raise NameError(f"No component names 'Page' in module {module}")
|
|
312
|
-
return page
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
def get_renderable(module: ModuleType, required=False):
|
|
316
|
-
var_names = "app Page page".split()
|
|
317
|
-
for var_name in var_names:
|
|
318
|
-
if not hasattr(module, var_name):
|
|
319
|
-
continue
|
|
320
|
-
entry = getattr(module, var_name)
|
|
321
|
-
return entry
|
|
322
|
-
if required:
|
|
323
|
-
raise NameError(f"No component, element or widget found in module {module} with names: {', '.join(var_names[:-1])} or {var_names[-1]}")
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
def get_title(module: ModuleType, required=True):
|
|
327
|
-
assert module.__file__ is not None
|
|
328
|
-
name = Path(module.__file__).stem
|
|
329
|
-
if module.__file__.endswith("__init__.py"):
|
|
330
|
-
name = Path(module.__file__).parent.stem
|
|
331
|
-
# if title is a submodule it may shadown the variable in __init__
|
|
332
|
-
# in this case, _title is an escape hatch
|
|
333
|
-
if hasattr(module, "_title") and isinstance(module._title, str):
|
|
334
|
-
title = module._title
|
|
335
|
-
elif hasattr(module, "title") and isinstance(module.title, str):
|
|
336
|
-
title = module.title
|
|
337
|
-
else:
|
|
338
|
-
match = re.match("([0-9\\-_ ]*)(.*)", name)
|
|
339
|
-
if match:
|
|
340
|
-
_prefix, name = match.groups()
|
|
341
|
-
title_parts = re.split("[\\-_ ]+", name)
|
|
342
|
-
title = " ".join(k.title() for k in title_parts)
|
|
343
|
-
return title
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
def fix_route(route: solara.Route, new_file: Path, new_layout=None) -> solara.Route:
|
|
347
|
-
file = route.file or new_file
|
|
348
|
-
layout = route.layout or new_layout
|
|
349
|
-
children = fix_routes(route.children, new_file) if route.children else []
|
|
350
|
-
|
|
351
|
-
return dataclasses.replace(route, file=file, children=children, layout=layout)
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
def fix_routes(routes: List[solara.Route], new_file: Path, new_layout=None):
|
|
355
|
-
new_routes = []
|
|
356
|
-
for route in routes:
|
|
357
|
-
if route.path == "/":
|
|
358
|
-
route = fix_route(route, new_file, new_layout)
|
|
359
|
-
else:
|
|
360
|
-
route = fix_route(route, new_file)
|
|
361
|
-
new_routes.append(route)
|
|
362
|
-
return new_routes
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
def generate_routes(module: ModuleType) -> List[solara.Route]:
|
|
366
|
-
"""Generate routes from a module.
|
|
367
|
-
|
|
368
|
-
This is a recursive function that will generate routes for all submodules.
|
|
369
|
-
|
|
370
|
-
Note this only support .py files, since Markdown files and Jupyter notebook
|
|
371
|
-
files are not Python modules.
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
See [our multipage guide](/documentation/advanced/howto/multipage#as-a-package) for more details.
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
"""
|
|
378
|
-
from .server import reload
|
|
379
|
-
|
|
380
|
-
assert module.__file__ is not None
|
|
381
|
-
routes = []
|
|
382
|
-
children: List[solara.Route]
|
|
383
|
-
file = Path(module.__file__)
|
|
384
|
-
|
|
385
|
-
if module.__file__.endswith("__init__.py"):
|
|
386
|
-
if hasattr(module, "routes"):
|
|
387
|
-
# if routes if provided, use them instead of us generating them
|
|
388
|
-
children = getattr(module, "routes")
|
|
389
|
-
children = fix_routes(children, file)
|
|
390
|
-
return children
|
|
391
|
-
route_order = getattr(module, "route_order", None)
|
|
392
|
-
layout = getattr(module, "Layout", None)
|
|
393
|
-
title = get_title(module)
|
|
394
|
-
children = getattr(module, "routes", [])
|
|
395
|
-
if hasattr(module, "Page"):
|
|
396
|
-
routes.append(
|
|
397
|
-
solara.Route(path="/", component=get_page(module), data=module, module=module, layout=layout, children=children, label=title, file=file)
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
assert module.__file__ is not None
|
|
401
|
-
reload.reloader.watcher.add_file(module.__file__)
|
|
402
|
-
for info in pkgutil.iter_modules([str(Path(module.__file__).parent)]):
|
|
403
|
-
submod = importlib.import_module(module.__name__ + f".{info.name}")
|
|
404
|
-
subfile = Path(submod.__file__) if submod.__file__ is not None else None
|
|
405
|
-
title = get_title(submod)
|
|
406
|
-
|
|
407
|
-
name = info.name
|
|
408
|
-
# ideally, we do this similar to generate_routes_directory
|
|
409
|
-
# however, this may break things.
|
|
410
|
-
# name = name.replace("_", "-")
|
|
411
|
-
if info.ispkg:
|
|
412
|
-
route = solara.Route(
|
|
413
|
-
name, component=get_page(submod, required=False), children=generate_routes(submod), module=submod, layout=None, label=title
|
|
414
|
-
)
|
|
415
|
-
# skip empty subpackages
|
|
416
|
-
if len(route.children) == 0:
|
|
417
|
-
continue
|
|
418
|
-
else:
|
|
419
|
-
# skip empty modules
|
|
420
|
-
if get_renderable(submod) is None and not hasattr(submod, "routes"):
|
|
421
|
-
continue
|
|
422
|
-
children = getattr(submod, "routes", [])
|
|
423
|
-
if subfile:
|
|
424
|
-
children = fix_routes(children, subfile)
|
|
425
|
-
module_layout = getattr(submod, "Layout", None)
|
|
426
|
-
route = solara.Route(
|
|
427
|
-
name, component=get_page(submod, required=False), module=submod, layout=module_layout, children=children, label=title, file=subfile
|
|
428
|
-
)
|
|
429
|
-
routes.append(route)
|
|
430
|
-
if route_order:
|
|
431
|
-
lookup = {k.path: k for k in routes}
|
|
432
|
-
for k in route_order:
|
|
433
|
-
if k not in lookup:
|
|
434
|
-
raise KeyError(f"Route {k!r} listen in route_order not found in {module}")
|
|
435
|
-
routes = [lookup[k] for k in route_order]
|
|
436
|
-
if set(lookup) - set(route_order):
|
|
437
|
-
warnings.warn(f"Some routes are not in route_order: {set(lookup) - set(route_order)}")
|
|
438
|
-
|
|
439
|
-
else:
|
|
440
|
-
layout = getattr(module, "Layout", None)
|
|
441
|
-
children = []
|
|
442
|
-
if hasattr(module, "routes"):
|
|
443
|
-
children = getattr(module, "routes", [])
|
|
444
|
-
root = get_root(children)
|
|
445
|
-
if layout is not None and root is not None and root.layout is None:
|
|
446
|
-
warnings.warn(f'You defined routes in {file}, in this case, layout should be set on the root route (with path="/"), not on the module level')
|
|
447
|
-
layout = None
|
|
448
|
-
children = fix_routes(children, file, layout)
|
|
449
|
-
return [
|
|
450
|
-
solara.Route(
|
|
451
|
-
path="/",
|
|
452
|
-
component=get_page(module, required=False),
|
|
453
|
-
data=None,
|
|
454
|
-
module=module,
|
|
455
|
-
label=get_title(module),
|
|
456
|
-
layout=layout,
|
|
457
|
-
children=children,
|
|
458
|
-
file=file,
|
|
459
|
-
)
|
|
460
|
-
]
|
|
461
|
-
|
|
462
|
-
return routes
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
def generate_routes_directory(path: Path) -> List[solara.Route]:
|
|
466
|
-
"""Generate routes for a directory.
|
|
467
|
-
|
|
468
|
-
This is a recursive function that will generate routes for all
|
|
469
|
-
subdirectories and files in the directory. It will skip any
|
|
470
|
-
files or directories that start with an underscore or a dot.
|
|
471
|
-
|
|
472
|
-
Markdown files ending in .md will be rendered as markdown.
|
|
473
|
-
|
|
474
|
-
Python files ending in .py, or Jupyter notebooks ending in .ipynb
|
|
475
|
-
will be executed and its `Page` component will be rendered.
|
|
476
|
-
|
|
477
|
-
Automatic titles will be [generated as explained in the multipage guide](/documentation/advanced/howto/multipage).
|
|
478
|
-
|
|
479
|
-
"""
|
|
480
|
-
|
|
481
|
-
subpaths = list(sorted(path.iterdir()))
|
|
482
|
-
routes = []
|
|
483
|
-
first = True
|
|
484
|
-
has_index = len([k for k in subpaths if k.name == "__init__"]) > 0
|
|
485
|
-
init = path / "__init__.py"
|
|
486
|
-
layout = None
|
|
487
|
-
if init.exists():
|
|
488
|
-
init_module = source_to_module(init)
|
|
489
|
-
layout = getattr(init_module, "Layout", None)
|
|
490
|
-
|
|
491
|
-
suffixes = [".py", ".ipynb", ".md"]
|
|
492
|
-
for subpath in subpaths:
|
|
493
|
-
# only handle directories and recognized file types
|
|
494
|
-
if not (subpath.is_dir() or subpath.suffix in suffixes):
|
|
495
|
-
continue
|
|
496
|
-
if subpath.stem.startswith("_") or subpath.stem.startswith("."):
|
|
497
|
-
continue
|
|
498
|
-
route = _generate_route_path(subpath, layout=layout, first=first, has_index=has_index)
|
|
499
|
-
first = False
|
|
500
|
-
routes.append(route)
|
|
501
|
-
return routes
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
def _generate_route_path(subpath: Path, layout=None, first=False, has_index=False, initial_namespace={}) -> solara.Route:
|
|
505
|
-
from .server import reload
|
|
506
|
-
|
|
507
|
-
name = subpath.stem
|
|
508
|
-
match = re.match("([0-9\\-_ ]*)(.*)", name)
|
|
509
|
-
if match:
|
|
510
|
-
_prefix, name = match.groups()
|
|
511
|
-
title_parts = re.split("[\\-_ ]+", name)
|
|
512
|
-
title = " ".join(k.title() for k in title_parts)
|
|
513
|
-
if not has_index and first:
|
|
514
|
-
route_path = "/"
|
|
515
|
-
else:
|
|
516
|
-
route_path = "-".join([k.lower() for k in title_parts])
|
|
517
|
-
component = None
|
|
518
|
-
children: List[solara.Route] = []
|
|
519
|
-
module: Optional[ModuleType] = None
|
|
520
|
-
data: Any = None
|
|
521
|
-
module_layout = layout if first else None
|
|
522
|
-
if subpath.suffix == ".md":
|
|
523
|
-
data = subpath
|
|
524
|
-
reload.reloader.watcher.add_file(subpath)
|
|
525
|
-
elif subpath.is_dir():
|
|
526
|
-
children = generate_routes_directory(subpath)
|
|
527
|
-
else:
|
|
528
|
-
reload.reloader.watcher.add_file(subpath)
|
|
529
|
-
module = source_to_module(subpath, initial_namespace=initial_namespace)
|
|
530
|
-
title = get_title(module)
|
|
531
|
-
layout = getattr(module, "Layout", module_layout)
|
|
532
|
-
root = get_root(children)
|
|
533
|
-
if hasattr(module, "routes"):
|
|
534
|
-
children = getattr(module, "routes", [])
|
|
535
|
-
root = get_root(children)
|
|
536
|
-
if layout is not None and root is not None and root.layout is None:
|
|
537
|
-
warnings.warn(f'You defined routes in {subpath}, in this case, layout should be set on the root route (with path="/"), not on the module level')
|
|
538
|
-
layout = None
|
|
539
|
-
children = fix_routes(children, subpath, layout)
|
|
540
|
-
component = get_page(module, required=False)
|
|
541
|
-
if root and component and root.component and component is not root.component:
|
|
542
|
-
warnings.warn(
|
|
543
|
-
f"In {subpath}, you defined a Page component, but also a component on the root route (with path='/') "
|
|
544
|
-
"which is not equal to the Page component at the module level. This is not recommended."
|
|
545
|
-
)
|
|
546
|
-
route = solara.Route(route_path, component=component, module=module, label=title, children=children, data=data, layout=layout, file=subpath)
|
|
547
|
-
return route
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
def get_root(routes: List[solara.Route]) -> Optional[solara.Route]:
|
|
551
|
-
for route in routes:
|
|
552
|
-
if route.path == "/":
|
|
553
|
-
return route
|
|
554
|
-
return None
|