├── solara
├── py.typed
├── test
│ └── __init__.py
├── lab
│ ├── hooks
│ │ ├── __init__.py
│ │ └── dataframe.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── cookies.py
│ │ └── headers.py
│ ├── toestand.py
│ └── components
│ │ ├── cross_filter.py
│ │ └── __init__.py
├── server
│ ├── __init__.py
│ ├── assets
│ │ ├── custom.css
│ │ ├── custom.js
│ │ ├── theme.js
│ │ ├── favicon.png
│ │ └── favicon.svg
│ ├── templates
│ │ ├── index.html.j2
│ │ ├── loader-plain.css
│ │ └── loader-plain.html
│ ├── fastapi.py
│ ├── jupyter
│ │ ├── __init__.py
│ │ └── cdn_handler.py
│ └── pyinstaller
│ │ ├── __init__.py
│ │ ├── hook-ipyreact.py
│ │ ├── hook-ipyvuetify.py
│ │ └── hook-solara.py
├── website
│ ├── __init__.py
│ ├── pages
│ │ ├── documentation
│ │ │ ├── advanced
│ │ │ │ ├── content
│ │ │ │ │ ├── 40-development
│ │ │ │ │ │ └── 00-overview.md
│ │ │ │ │ ├── 15-reference
│ │ │ │ │ │ ├── 00-overview.md
│ │ │ │ │ │ ├── 90-notebook-support.md
│ │ │ │ │ │ └── 40-static_files.md
│ │ │ │ │ ├── 00-overview.md
│ │ │ │ │ ├── 10-howto
│ │ │ │ │ │ └── 00-overview.md
│ │ │ │ │ ├── 30-enterprise
│ │ │ │ │ │ └── 00-overview.md
│ │ │ │ │ └── 20-understanding
│ │ │ │ │ │ ├── 00-introduction.md
│ │ │ │ │ │ ├── 20-solara.md
│ │ │ │ │ │ └── 60-voila.md
│ │ │ │ └── __init__.py
│ │ │ ├── examples
│ │ │ │ ├── fullscreen
│ │ │ │ │ ├── scatter.py
│ │ │ │ │ ├── multipage.py
│ │ │ │ │ ├── scrolling.py
│ │ │ │ │ ├── layout_demo.py
│ │ │ │ │ ├── authorization.py
│ │ │ │ │ ├── tutorial_streamlit.py
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── visualization
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── general
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── live_update.py
│ │ │ │ ├── libraries
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── basics
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── sine.py
│ │ │ │ ├── utilities
│ │ │ │ │ └── __init__.py
│ │ │ │ └── ai
│ │ │ │ │ └── __init__.py
│ │ │ ├── getting_started
│ │ │ │ ├── content
│ │ │ │ │ ├── 04-tutorials
│ │ │ │ │ │ ├── SF_crime_sample.csv.gz
│ │ │ │ │ │ └── 10_data_science.py
│ │ │ │ │ ├── 80-what-is-lab.md
│ │ │ │ │ ├── 07-deploying
│ │ │ │ │ │ └── 00-overview.md
│ │ │ │ │ └── 05-fundamentals
│ │ │ │ │ │ └── 00-overview.md
│ │ │ │ └── __init__.py
│ │ │ ├── api
│ │ │ │ ├── hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── use_memo.py
│ │ │ │ │ ├── use_effect.py
│ │ │ │ │ ├── use_state.py
│ │ │ │ │ ├── use_reactive.py
│ │ │ │ │ ├── use_trait_observe.py
│ │ │ │ │ ├── use_dark_effective.py
│ │ │ │ │ ├── use_cross_filter.py
│ │ │ │ │ ├── use_previous.py
│ │ │ │ │ ├── use_memo.md
│ │ │ │ │ └── use_exception.py
│ │ │ │ ├── routing
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── use_router.py
│ │ │ │ │ ├── generate_routes.py
│ │ │ │ │ ├── generate_routes_directory.py
│ │ │ │ │ └── route.py
│ │ │ │ ├── cross_filter
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── cross_filter_select.py
│ │ │ │ │ ├── cross_filter_report.py
│ │ │ │ │ ├── cross_filter_slider.py
│ │ │ │ │ └── cross_filter_dataframe.py
│ │ │ │ ├── utilities
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── display.py
│ │ │ │ │ ├── reactive.py
│ │ │ │ │ ├── computed.py
│ │ │ │ │ ├── component_vue.py
│ │ │ │ │ ├── get_kernel_id.py
│ │ │ │ │ ├── get_session_id.py
│ │ │ │ │ └── memoize.py
│ │ │ │ └── __init__.py
│ │ │ ├── components
│ │ │ │ ├── data
│ │ │ │ │ └── __init__.py
│ │ │ │ ├── input
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── switch.py
│ │ │ │ │ ├── checkbox.py
│ │ │ │ │ ├── button.py
│ │ │ │ │ ├── select.py
│ │ │ │ │ ├── togglebuttons.py
│ │ │ │ │ └── slider.py
│ │ │ │ ├── lab
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── task.py
│ │ │ │ │ ├── use_task.py
│ │ │ │ │ ├── input_time.py
│ │ │ │ │ ├── input_date.py
│ │ │ │ │ ├── menu.py
│ │ │ │ │ └── tab.py
│ │ │ │ ├── page
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── head.py
│ │ │ │ │ └── title.py
│ │ │ │ ├── viz
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── matplotlib.py
│ │ │ │ │ ├── altair.py
│ │ │ │ │ └── plotly_express.py
│ │ │ │ ├── advanced
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── meta.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ └── style.py
│ │ │ │ ├── enterprise
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── avatar.py
│ │ │ │ │ └── avatar_menu.py
│ │ │ │ ├── layout
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── details.py
│ │ │ │ │ ├── card.py
│ │ │ │ │ ├── app_bar.py
│ │ │ │ │ ├── app_bar_title.py
│ │ │ │ │ ├── card_actions.py
│ │ │ │ │ ├── gridfixed.py
│ │ │ │ │ ├── hbox.py
│ │ │ │ │ ├── vbox.py
│ │ │ │ │ ├── app_layout.py
│ │ │ │ │ ├── sidebar.py
│ │ │ │ │ ├── column.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ └── row.py
│ │ │ │ ├── output
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── image.py
│ │ │ │ │ ├── tooltip.py
│ │ │ │ │ ├── file_download.py
│ │ │ │ │ └── html.py
│ │ │ │ ├── status
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── info.py
│ │ │ │ │ └── error.py
│ │ │ │ ├── common.py
│ │ │ │ └── __init__.py
│ │ │ └── faq
│ │ │ │ └── __init__.py
│ │ ├── about
│ │ │ ├── __init__.py
│ │ │ └── about.md
│ │ ├── changelog
│ │ │ └── __init__.py
│ │ ├── roadmap
│ │ │ └── __init__.py
│ │ ├── apps
│ │ │ ├── __init__.py
│ │ │ ├── authorization
│ │ │ │ ├── users.py
│ │ │ │ └── admin.py
│ │ │ ├── tutorial-streamlit.py
│ │ │ └── multipage
│ │ │ │ └── page1.py
│ │ ├── showcase
│ │ │ ├── planeto_tessa.py
│ │ │ ├── solarathon_2023_team_4.py
│ │ │ └── solarathon_2023_team_2.py
│ │ └── docutils.py
│ ├── public
│ │ ├── beach.jpeg
│ │ ├── social
│ │ │ ├── twitter.svg
│ │ │ ├── discord.svg
│ │ │ └── github.svg
│ │ ├── success.html
│ │ └── logo.svg
│ ├── assets
│ │ ├── images
│ │ │ └── logo-small.png
│ │ └── theme.js
│ ├── components
│ │ ├── algolia.py
│ │ ├── mailchimp.py
│ │ ├── __init__.py
│ │ ├── algolia.vue
│ │ ├── markdown_nav.vue
│ │ └── breadcrumbs.py
│ └── utils.py
├── widgets
│ ├── __init__.py
│ └── vue
│ │ └── html.vue
├── template
│ ├── portal
│ │ ├── mypy.ini
│ │ ├── solara_portal
│ │ │ ├── components
│ │ │ │ ├── __init__.py
│ │ │ │ ├── header.py
│ │ │ │ ├── layout.py
│ │ │ │ ├── data.py
│ │ │ │ └── article.py
│ │ │ ├── __init__.py
│ │ │ └── pages
│ │ │ │ ├── viz
│ │ │ │ └── overview.py
│ │ │ │ ├── article
│ │ │ │ └── __init__.py
│ │ │ │ └── tabular.py
│ │ ├── .flake8
│ │ ├── Procfile
│ │ ├── pyproject.toml
│ │ ├── .pre-commit-config.yaml
│ │ └── LICENSE
│ └── button.py
├── hooks
│ └── __init__.py
├── alias.py
├── kitchensink.py
├── components
│ ├── code_highlight_css.py
│ ├── head.py
│ ├── markdown_editor.py
│ ├── select.vue
│ ├── title.vue
│ ├── tab_navigation.py
│ └── download.vue
└── comm.py
├── tests
├── __init__.py
├── unit
│ ├── __init__.py
│ ├── lab
│ │ └── __init__.py
│ ├── component_vue_test.vue
│ ├── solara_test_apps
│ │ ├── __init__.py
│ │ ├── food
│ │ │ ├── __init__.py
│ │ │ ├── food.py
│ │ │ └── index.py
│ │ ├── multipage
│ │ │ ├── 99-some_other_python_script.py
│ │ │ ├── some_other_file.txt
│ │ │ ├── 04-a_directory
│ │ │ │ ├── 00-another-markdown.md
│ │ │ │ ├── 01-not-an-app.py
│ │ │ │ └── __init__.py
│ │ │ ├── 10-single-file-directory
│ │ │ │ └── single-file.md
│ │ │ ├── 01-home.py
│ │ │ ├── 02-my_fruit.py
│ │ │ ├── 06-custom-routes.py
│ │ │ ├── 05-and-notebooks.ipynb
│ │ │ └── 03-some-markdown.md
│ │ ├── single_file.py
│ │ ├── kernel_start.py
│ │ ├── multipage-widgets
│ │ │ ├── 00-overview.md
│ │ │ ├── 01-views.py
│ │ │ ├── 02-likes.py
│ │ │ └── 03-volume.py
│ │ ├── single_file_multiple_routes.py
│ │ ├── single_file_routes.py
│ │ ├── notebookapp_element.ipynb
│ │ ├── notebookapp_widget.ipynb
│ │ └── notebookapp_component.ipynb
│ ├── toestand_computed_reload.py
│ ├── switch_test.py
│ ├── no_solara_test.py
│ ├── express_test.py
│ ├── conftest.py
│ ├── shell_test.py
│ ├── chat_test.py
│ ├── telemetry_tests.py
│ └── checkbox_test.py
├── integration
│ ├── __init__.py
│ ├── enterprise
│ │ └── __init__.py
│ ├── apps
│ │ ├── public
│ │ │ └── test.txt
│ │ ├── not-allowed
│ │ └── secure
│ │ │ └── app.py
│ ├── assets
│ │ ├── assets1
│ │ │ ├── common.js
│ │ │ └── unique1.js
│ │ └── assets2
│ │ │ ├── common.js
│ │ │ ├── custom.js
│ │ │ ├── unique2.js
│ │ │ └── custom.css
│ ├── test.vue
│ ├── app_widget.py
│ ├── reload
│ │ └── apps.py
│ ├── error_test.py
│ ├── async_test.py
│ ├── testapp.py
│ └── file_download_test.py
├── pyinstaller
│ ├── __init__.py
│ └── pyinstaller_test.py
├── ui
│ └── snapshots
│ │ └── tests
│ │ └── integration
│ │ ├── widget_test.py
│ │ ├── test_widget_button_solara-flask-chromium-linux-reference.png
│ │ ├── test_widget_button_solara-flask-chromium-win32-reference.png
│ │ ├── test_solara_button_all-flask-voila-chromium-linux-reference.png
│ │ ├── test_solara_button_all-flask-voila-chromium-win32-reference.png
│ │ ├── test_solara_button_all-flask-solara-chromium-linux-reference.png
│ │ ├── test_solara_button_all-flask-solara-chromium-win32-reference.png
│ │ ├── test_widget_button_solara-starlette-chromium-linux-reference.png
│ │ ├── test_widget_button_solara-starlette-chromium-win32-reference.png
│ │ ├── test_solara_button_all-starlette-solara-chromium-linux-reference.png
│ │ ├── test_solara_button_all-starlette-solara-chromium-win32-reference.png
│ │ ├── test_slider_all-flask-solara-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-solara-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_slider_all-flask-solara-chromium-win32-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-solara-chromium-win32-ipywidgets-8-reference.png
│ │ ├── test_slider_all-flask-voila-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-voila-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_slider_all-flask-voila-chromium-win32-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-voila-chromium-win32-ipywidgets-8-reference.png
│ │ ├── test_solara_button_all-flask-jupyter_lab-chromium-linux-reference.png
│ │ ├── test_solara_button_all-flask-jupyter_lab-chromium-win32-reference.png
│ │ ├── test_widget_button_solara-flask-chromium-linux-ipyvuetify3-reference.png
│ │ ├── test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-8-reference.png
│ │ ├── test_slider_all-starlette-solara-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_slider_all-starlette-solara-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_slider_all-starlette-solara-chromium-win32-ipywidgets-7-reference.png
│ │ ├── test_slider_all-starlette-solara-chromium-win32-ipywidgets-8-reference.png
│ │ ├── test_solara_button_all-flask-jupyter_notebook-chromium-linux-reference.png
│ │ ├── test_solara_button_all-flask-jupyter_notebook-chromium-win32-reference.png
│ │ ├── test_widget_button_solara-starlette-chromium-linux-ipyvuetify3-reference.png
│ │ ├── test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-7-reference.png
│ │ └── test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-8-reference.png
│ │ └── latex_test.py
│ │ ├── test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-changed-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-changed-reference.png
│ │ ├── test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-changed-reference.png
│ │ └── test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-changed-reference.png
├── docs
│ ├── docs_howto_no_browser_testing_test.py
│ └── docs_howto_no_browser_threaded_test.py
└── conftest.py
├── runtime.txt
├── packages
├── solara-enterprise
│ ├── solara_enterprise
│ │ ├── search
│ │ │ ├── __init__.py
│ │ │ └── search.py
│ │ ├── cache
│ │ │ ├── __init__.py
│ │ │ ├── multi_level.py
│ │ │ ├── redis.py
│ │ │ └── memory_size.py
│ │ ├── __init__.py
│ │ ├── license.py
│ │ └── auth
│ │ │ └── __init__.py
│ ├── LICENSE
│ ├── RELEASE.md
│ └── pyproject.toml
├── solara-widget-manager8
│ ├── src
│ ├── style
│ ├── tsconfig.json
│ └── patches
│ │ ├── @jupyterlab+outputarea+3.6.4.patch
│ │ └── @jupyterlab+rendermime+3.6.4.patch
├── solara-vuetify-app
│ ├── src
│ │ ├── empty.js
│ │ ├── fonts.js
│ │ ├── solara.js
│ │ └── solara-vuetify-app.js
│ ├── README.md
│ ├── release.sh
│ └── .bumpversion.cfg
├── solara-widget-manager
│ ├── style
│ │ └── index.css
│ ├── src
│ │ ├── typings.d.ts
│ │ └── index.ts
│ └── tsconfig.json
├── solara-assets
│ ├── solara_assets
│ │ └── __init__.py
│ ├── .gitignore
│ ├── download_cdn_test.py
│ ├── RELEASE.md
│ ├── pyproject.toml
│ └── LICENSE
├── solara-vuetify3-app
│ ├── src
│ │ ├── fonts.js
│ │ ├── solara.js
│ │ └── solara-vuetify-app.js
│ ├── README.md
│ ├── release.sh
│ ├── .bumpversion.cfg
│ └── package.json
├── solara-meta
│ ├── README.md
│ └── LICENSE
├── solara-server
│ ├── README.md
│ └── LICENSE
├── solara-milkdown
│ ├── src
│ │ └── index.js
│ ├── package.json
│ └── webpack.config.js
└── pytest-ipywidgets
│ └── LICENSE
├── pyinstaller
├── solara.icns
├── minimal
│ ├── sample_app.py
│ └── solara-app-entrypoint.py
└── entitlements.plist
├── CONTRIBUTING.md
├── requirements.txt
├── SECURITY.md
├── mypy.ini
├── .flake8
├── requirements-dev.txt
├── prefix
└── etc
│ └── jupyter
│ ├── jupyter_server_config.d
│ └── solara.json
│ └── jupyter_notebook_config.d
│ └── solara.json
├── .github
├── dependabot.yml
├── ISSUE_TEMPLATE
│ ├── bug.md
│ └── feature_request.md
├── workflows
│ └── pycafe.yml
└── pull_request_template.md
├── .ci-package-locks
└── code-quality
│ ├── python3.12.txt
│ └── python3.9.txt
├── release.md
├── tsconfigbase.json
├── Procfile
├── .bumpversion.cfg
└── LICENSE
/solara/py.typed:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/lab/hooks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/server/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/website/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/lab/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.9.13
2 |
--------------------------------------------------------------------------------
/tests/integration/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/pyinstaller/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/component_vue_test.vue:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/integration/enterprise/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/integration/apps/public/test.txt:
--------------------------------------------------------------------------------
1 | test
2 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/food/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/server/assets/custom.css:
--------------------------------------------------------------------------------
1 | /* not empty *
2 |
--------------------------------------------------------------------------------
/solara/server/assets/custom.js:
--------------------------------------------------------------------------------
1 | /* not empty */
2 |
--------------------------------------------------------------------------------
/tests/integration/apps/not-allowed:
--------------------------------------------------------------------------------
1 | not accessible
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets1/common.js:
--------------------------------------------------------------------------------
1 | content1
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets1/unique1.js:
--------------------------------------------------------------------------------
1 | unique1
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets2/common.js:
--------------------------------------------------------------------------------
1 | content2
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets2/custom.js:
--------------------------------------------------------------------------------
1 | var a = 1;
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets2/unique2.js:
--------------------------------------------------------------------------------
1 | unique2
2 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/search/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager8/src:
--------------------------------------------------------------------------------
1 | ../solara-widget-manager/src
--------------------------------------------------------------------------------
/solara/server/assets/theme.js:
--------------------------------------------------------------------------------
1 | vuetifyThemes = {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/food/food.py:
--------------------------------------------------------------------------------
1 | title = "Foods"
2 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager8/style:
--------------------------------------------------------------------------------
1 | ../solara-widget-manager/style
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/99-some_other_python_script.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/solara/server/templates/index.html.j2:
--------------------------------------------------------------------------------
1 | {% extends "solara.html.j2" %}
2 |
--------------------------------------------------------------------------------
/solara/widgets/__init__.py:
--------------------------------------------------------------------------------
1 | from .widgets import * # noqa: F401, F403
2 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager8/tsconfig.json:
--------------------------------------------------------------------------------
1 | ../solara-widget-manager/tsconfig.json
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/40-development/00-overview.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/integration/test.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ value }}
3 |
4 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/src/empty.js:
--------------------------------------------------------------------------------
1 | // used as alias to avoid bundling unused code
2 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/some_other_file.txt:
--------------------------------------------------------------------------------
1 | we should do nothing with this
2 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/LICENSE:
--------------------------------------------------------------------------------
1 | Not open source, contact contact@solara.dev for licencing.
2 |
--------------------------------------------------------------------------------
/tests/integration/assets/assets2/custom.css:
--------------------------------------------------------------------------------
1 | .v-btn {
2 | color: #ff0000 !important;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/04-a_directory/00-another-markdown.md:
--------------------------------------------------------------------------------
1 | # Just a title
2 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/10-single-file-directory/single-file.md:
--------------------------------------------------------------------------------
1 | # single file
2 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager/style/index.css:
--------------------------------------------------------------------------------
1 | @import "../node_modules/katex/dist/katex.min.css";
2 |
--------------------------------------------------------------------------------
/pyinstaller/solara.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/pyinstaller/solara.icns
--------------------------------------------------------------------------------
/tests/integration/apps/secure/app.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | page = solara.Button("Click me")
5 |
--------------------------------------------------------------------------------
/packages/solara-assets/solara_assets/__init__.py:
--------------------------------------------------------------------------------
1 | "CDN assets for Solara"
2 |
3 | __version__ = "1.56.0"
4 |
--------------------------------------------------------------------------------
/solara/template/portal/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 | check_untyped_defs = True
3 | ignore_missing_imports = True
4 |
--------------------------------------------------------------------------------
/solara/server/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/solara/server/assets/favicon.png
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/scatter.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/scatter"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/solara/website/public/beach.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/solara/website/public/beach.jpeg
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Please go to https://solara.dev/documentation/advanced/development/contribute for more information.
2 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/cache/__init__.py:
--------------------------------------------------------------------------------
1 | from .. import license
2 |
3 | license.check("cache")
4 |
--------------------------------------------------------------------------------
/solara/lab/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .cookies import cookies # noqa: F401
2 | from .headers import headers # noqa: F401
3 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/multipage.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/multipage"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/scrolling.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/scrolling"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/__init__.py:
--------------------------------------------------------------------------------
1 | "Enterprise features for Solara"
2 |
3 | __version__ = "1.56.0"
4 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/layout_demo.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/layout-demo"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/packages/solara-assets/.gitignore:
--------------------------------------------------------------------------------
1 | # unignore build and dist, so hatch includes these dirs in shared-data
2 | !build
3 | !dist/
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | .[all]
2 | ./packages/solara-server[all]
3 | ./packages/solara-enterprise[all]
4 | ./packages/solara-meta[all]
5 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/authorization.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/authorization"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/solara/server/fastapi.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 |
3 | from . import starlette
4 |
5 | app = FastAPI(routes=starlette.routes)
6 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .header import Header # noqa
2 | from .layout import Layout # noqa
3 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/components/header.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Header():
6 | pass
7 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting a Vulnerability
4 |
5 | Please contact security@widgetti to report vulnerabilities
6 |
--------------------------------------------------------------------------------
/solara/website/assets/images/logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/solara/website/assets/images/logo-small.png
--------------------------------------------------------------------------------
/solara/website/components/algolia.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component_vue("algolia_api.vue")
5 | def Algolia():
6 | pass
7 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py:
--------------------------------------------------------------------------------
1 | redirect = "/apps/tutorial-streamlit"
2 |
3 | Page = True
4 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/01-home.py:
--------------------------------------------------------------------------------
1 | import solara.website.pages.documentation.components.input.button as mod
2 |
3 | Page = mod.Page
4 |
--------------------------------------------------------------------------------
/solara/widgets/vue/html.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 | check_untyped_defs = True
3 | ignore_missing_imports = True
4 | exclude=04-a_directory|nogit|^pyinstaller
5 | no_implicit_optional = False
6 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore = E203 W503
3 | max-line-length = 160
4 | per-file-ignores =
5 | # line too long (170 > 160 characters)
6 | ipywidgets.py: E501
7 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/__init__.py:
--------------------------------------------------------------------------------
1 | """Example Solara app as python packages"""
2 |
3 | __title__ = "Solara example app"
4 | __version__ = "0.0.1"
5 |
--------------------------------------------------------------------------------
/solara/lab/hooks/dataframe.py:
--------------------------------------------------------------------------------
1 | from ..utils.dataframe import df_columns as use_df_column_names # noqa: F401
2 | from ..utils.dataframe import df_row_names as df_row_names
3 |
--------------------------------------------------------------------------------
/solara/server/jupyter/__init__.py:
--------------------------------------------------------------------------------
1 | from .server_extension import _load_jupyter_server_extension # noqa
2 | from .server_extension import load_jupyter_server_extension # noqa
3 |
--------------------------------------------------------------------------------
/solara/website/assets/theme.js:
--------------------------------------------------------------------------------
1 | vuetifyThemes = {
2 | light: {
3 | primary: '#ff991f',
4 | },
5 | dark: {
6 | primary: '#f77e14',
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/food/index.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | title = "Fruit home"
4 |
5 |
6 | @solara.component
7 | def Page():
8 | return solara.Success("Yay")
9 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/02-my_fruit.py:
--------------------------------------------------------------------------------
1 | import solara.website.pages.documentation.api.routing.use_route as mod
2 |
3 | routes = mod.routes
4 | Page = mod.Page
5 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/components/layout.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Layout(children=[]):
6 | return solara.VBox(children=children)
7 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/04-a_directory/01-not-an-app.py:
--------------------------------------------------------------------------------
1 | import solara.website.pages.documentation.components.layout.griddraggable as mod
2 |
3 | Page = mod.Page
4 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | -e .[all]
2 | -e ./packages/solara-server[all]
3 | -e ./packages/solara-enterprise[all]
4 | -e ./packages/pytest-ipywidgets[all]
5 | -e ./packages/solara-meta[all]
6 |
--------------------------------------------------------------------------------
/solara/template/portal/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore = E203 W503
3 | max-line-length = 160
4 | per-file-ignores =
5 | # line too long (170 > 160 characters)
6 | ipywidgets.py: E501
7 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/src/fonts.js:
--------------------------------------------------------------------------------
1 | import 'typeface-roboto';
2 | import 'material-design-icons-iconfont/dist/material-design-icons.css';
3 | import '@mdi/font/css/materialdesignicons.css';
4 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/naming-convention
2 | declare interface Window {
3 | define: any;
4 | requirejs: any;
5 | }
6 |
--------------------------------------------------------------------------------
/prefix/etc/jupyter/jupyter_server_config.d/solara.json:
--------------------------------------------------------------------------------
1 | {
2 | "ServerApp": {
3 | "jpserver_extensions": {
4 | "solara.server.jupyter.server_extension": true
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/15-reference/00-overview.md:
--------------------------------------------------------------------------------
1 | # Reference documentation
2 |
3 | Our reference documentation informs you about how certain parts in Solara work.
4 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/visualization/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | return solara.Markdown("Click an example on the left")
7 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/src/fonts.js:
--------------------------------------------------------------------------------
1 | import '@mdi/font/css/materialdesignicons.css';
2 | import 'material-design-icons-iconfont/dist/material-design-icons.css';
3 | import 'typeface-roboto';
4 |
--------------------------------------------------------------------------------
/prefix/etc/jupyter/jupyter_notebook_config.d/solara.json:
--------------------------------------------------------------------------------
1 | {
2 | "NotebookApp": {
3 | "nbserver_extensions": {
4 | "solara.server.jupyter.server_extension": true
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Maintain dependencies for GitHub Actions
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 |
--------------------------------------------------------------------------------
/solara/server/pyinstaller/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 |
4 | HERE = Path(__file__).parent
5 |
6 |
7 | def get_hook_dirs():
8 | # used for pyinstaller
9 | return [str(HERE)]
10 |
--------------------------------------------------------------------------------
/packages/solara-meta/README.md:
--------------------------------------------------------------------------------
1 | A meta packages that installs all the necessary dependencies to get started with Solara.
2 |
3 | See https://solara.dev/documentation/getting_started/installing for more information.
4 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/src/solara.js:
--------------------------------------------------------------------------------
1 | export { RenderMimeRegistry, WidgetManager, connectKernel, extendedRendererFactories, KatexTypesetter, renderKatex, shutdownKernel } from '@widgetti/solara-widget-manager';
2 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/src/solara.js:
--------------------------------------------------------------------------------
1 | export { RenderMimeRegistry, WidgetManager, connectKernel, extendedRendererFactories, KatexTypesetter, renderKatex, shutdownKernel } from '@widgetti/solara-widget-manager';
2 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/single_file.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | with solara.Sidebar():
7 | solara.SliderInt(label="in sidebar")
8 | solara.Markdown("Home")
9 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/00-overview.md:
--------------------------------------------------------------------------------
1 | The entries are meant as deeper dives into specific topics. Although we try to write each as a standalone document, some parts may build on previous ones.
2 |
--------------------------------------------------------------------------------
/solara/lab/toestand.py:
--------------------------------------------------------------------------------
1 | # for backwards compatibility
2 | from solara.toestand import KernelStoreValue as ConnectionStore # noqa: F401
3 | from solara.toestand import Reactive, Ref, State, use_sync_external_store # noqa: F401
4 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/general/__init__.py:
--------------------------------------------------------------------------------
1 | """"""
2 |
3 | import solara
4 |
5 | redirect = None
6 |
7 |
8 | @solara.component
9 | def Page():
10 | return solara.Markdown("Should not see me")
11 |
--------------------------------------------------------------------------------
/solara/hooks/__init__.py:
--------------------------------------------------------------------------------
1 | from .dataframe import * # noqa: F401 F403
2 | from .misc import * # noqa: F401 F403
3 | from .use_reactive import use_reactive # noqa: F401 F403
4 | from .use_thread import use_thread # noqa: F401 F403
5 |
--------------------------------------------------------------------------------
/.ci-package-locks/code-quality/python3.12.txt:
--------------------------------------------------------------------------------
1 | cfgv==3.4.0
2 | distlib==0.4.0
3 | filelock==3.20.0
4 | identify==2.6.15
5 | nodeenv==1.9.1
6 | platformdirs==4.5.0
7 | pre_commit==4.4.0
8 | PyYAML==6.0.3
9 | virtualenv==20.35.4
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz
--------------------------------------------------------------------------------
/solara/lab/utils/cookies.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Optional, cast
2 |
3 | from solara.toestand import Reactive
4 |
5 | cookies: Reactive[Optional[Dict[str, str]]] = Reactive(cast(Optional[Dict[str, str]], None), key="solara.lab.cookies")
6 |
--------------------------------------------------------------------------------
/solara/lab/components/cross_filter.py:
--------------------------------------------------------------------------------
1 | # for backwards compatibility
2 | from solara.components.cross_filter import ( # noqa: F401
3 | CrossFilterDataFrame,
4 | CrossFilterReport,
5 | CrossFilterSelect,
6 | CrossFilterSlider,
7 | )
8 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/04-a_directory/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Layout(children=[]):
6 | with solara.VBox(children=children) as main:
7 | solara.Info("Footer")
8 | return main
9 |
--------------------------------------------------------------------------------
/solara/alias.py:
--------------------------------------------------------------------------------
1 | import reacton # noqa: F401
2 | from reacton import ipyvue as rvue # noqa: F401
3 | from reacton import ipyvuetify as rv # noqa: F401
4 | from reacton import ipywidgets as rw # noqa: F401
5 |
6 | import solara as sol # noqa: F401
7 |
--------------------------------------------------------------------------------
/solara/lab/utils/headers.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Optional, cast
2 |
3 | from solara.toestand import Reactive
4 |
5 | headers: Reactive[Optional[Dict[str, List[str]]]] = Reactive(cast(Optional[Dict[str, List[str]]], None), key="solara.lab.headers")
6 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/fullscreen/__init__.py:
--------------------------------------------------------------------------------
1 | """Apps that run fullscreen"""
2 |
3 | import solara
4 |
5 | redirect = None
6 |
7 |
8 | @solara.component
9 | def Page():
10 | return solara.Markdown("Should not see me")
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/libraries/__init__.py:
--------------------------------------------------------------------------------
1 | """ipywidget library example"""
2 |
3 | import solara
4 |
5 | redirect = None
6 |
7 |
8 | @solara.component
9 | def Page():
10 | return solara.Markdown("Should not see me")
11 |
--------------------------------------------------------------------------------
/.ci-package-locks/code-quality/python3.9.txt:
--------------------------------------------------------------------------------
1 | cfgv==3.4.0
2 | distlib==0.4.0
3 | filelock==3.19.1
4 | identify==2.6.15
5 | nodeenv==1.9.1
6 | platformdirs==4.4.0
7 | pre_commit==4.3.0
8 | PyYAML==6.0.3
9 | typing_extensions==4.15.0
10 | virtualenv==20.35.4
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/basics/__init__.py:
--------------------------------------------------------------------------------
1 | """Demonstrates very basic usage of Solara."""
2 |
3 | import solara
4 |
5 | redirect = None
6 |
7 |
8 | @solara.component
9 | def Page():
10 | return solara.Markdown("Should not see me")
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/utilities/__init__.py:
--------------------------------------------------------------------------------
1 | """Utility apps, slightly more complex."""
2 |
3 | import solara
4 |
5 | redirect = None
6 |
7 |
8 | @solara.component
9 | def Page():
10 | return solara.Markdown("Should not see me")
11 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-win32-reference.png
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_memo.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.website.components import NoPage
4 |
5 | HERE = Path(__file__).parent
6 | __doc__ = open(HERE / "use_memo.md").read()
7 |
8 | Page = NoPage
9 | title = "use_memo"
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/routing/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-voila-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-voila-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-voila-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-voila-chromium-win32-reference.png
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/cross_filter/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_effect.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.website.components import NoPage
4 |
5 | HERE = Path(__file__).parent
6 | __doc__ = open(HERE / "use_effect.md").read()
7 |
8 | Page = NoPage
9 | title = "use_effect"
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/data/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/page/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/viz/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-solara-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-solara-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-solara-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-solara-chromium-win32-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-win32-reference.png
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/kernel_start.py:
--------------------------------------------------------------------------------
1 | import solara
2 | import solara.lab
3 |
4 |
5 | def test_callback():
6 | pass
7 |
8 |
9 | solara.lab.on_kernel_start(test_callback)
10 |
11 |
12 | @solara.component
13 | def Page():
14 | solara.Text("Hello, World!")
15 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/advanced/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/enterprise/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/output/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/status/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import NoPage, SubCategoryLayout
3 |
4 | Page = NoPage
5 |
6 |
7 | @solara.component
8 | def Layout(children=[]):
9 | SubCategoryLayout(children=children)
10 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-starlette-solara-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-starlette-solara-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-starlette-solara-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-starlette-solara-chromium-win32-reference.png
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage-widgets/00-overview.md:
--------------------------------------------------------------------------------
1 | # Multi page app using regular ipywidget
2 |
3 | * [Record views (widget based)](/views)
4 | * [Record likes (widget based)](/likes)
5 | * [Volume (uses component)](/volume)
6 | * [Color (uses widget in notebook)](/color)
7 |
--------------------------------------------------------------------------------
/solara/website/components/mailchimp.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import solara
4 |
5 | HERE = Path(__file__).parent
6 |
7 | # html = Path(HERE / "mailchimp.v").read_text()
8 |
9 |
10 | @solara.component_vue("mailchimp.vue")
11 | def MailChimp(location: str):
12 | pass
13 |
--------------------------------------------------------------------------------
/solara/website/pages/about/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.website.components.markdown import MarkdownWithMetadata
4 |
5 |
6 | title = "About Us"
7 | HERE = Path(__file__)
8 |
9 | Page = MarkdownWithMetadata(Path(HERE.parent / "about.md").read_text())
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/switch.py:
--------------------------------------------------------------------------------
1 | """# Switch"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 |
9 |
10 | __doc__ += apidoc(solara.Switch.f) # type: ignore
11 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-solara-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-voila-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_lab-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_lab-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_lab-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_lab-chromium-win32-reference.png
--------------------------------------------------------------------------------
/solara/kitchensink.py:
--------------------------------------------------------------------------------
1 | import reacton # noqa: F401
2 | from reacton import ipyvue as vue # noqa: F401
3 | from reacton import ipyvuetify as v # noqa: F401
4 | from reacton import ipywidgets as w # noqa: F401
5 |
6 | import solara as sol # noqa: F401
7 |
8 | from . import layout # noqa: F401
9 |
--------------------------------------------------------------------------------
/solara/server/templates/loader-plain.css:
--------------------------------------------------------------------------------
1 | #loader-container {
2 | width: 100vw;
3 | height: 100vh;
4 | position: absolute;
5 | margin: 0;
6 | padding: 0;
7 | z-index: 998;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | }
12 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/checkbox.py:
--------------------------------------------------------------------------------
1 | """# Checkbox"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 |
9 |
10 | __doc__ += apidoc(solara.Checkbox.f) # type: ignore
11 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-linux-ipyvuetify3-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-flask-chromium-linux-ipyvuetify3-reference.png
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/README.md:
--------------------------------------------------------------------------------
1 | A bundle that is used for solara-server that includes all static assets we need.
2 |
3 | For a dev install, use something like so that the Solara CDN proxy picks up the bundle locally:
4 |
5 | $ npm install
6 | $ npm run build
7 | $ npm run devlink
8 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/ai/__init__.py:
--------------------------------------------------------------------------------
1 | """Large Language Models and Generative AI examples."""
2 |
3 | import solara
4 |
5 | title = "AI"
6 | redirect = None
7 |
8 |
9 | @solara.component
10 | def Page():
11 | return solara.Markdown("Click an example on the left")
12 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_lab-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-starlette-solara-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_notebook-chromium-linux-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_notebook-chromium-linux-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_notebook-chromium-win32-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_solara_button_all-flask-jupyter_notebook-chromium-win32-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-linux-ipyvuetify3-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_widget_button_solara-starlette-chromium-linux-ipyvuetify3-reference.png
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/output/image.py:
--------------------------------------------------------------------------------
1 | """# Image"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 | title = "Image"
9 |
10 |
11 | __doc__ += apidoc(solara.Image.f) # type: ignore
12 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/status/progress.py:
--------------------------------------------------------------------------------
1 | """# ProgressLinear"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 |
9 |
10 | __doc__ += apidoc(solara.ProgressLinear.f) # type: ignore
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/status/spinner.py:
--------------------------------------------------------------------------------
1 | """
2 | # SpinnerSolara
3 | """
4 |
5 | import solara
6 | from solara.website.components import NoPage
7 | from solara.website.utils import apidoc
8 |
9 | Page = NoPage
10 |
11 | __doc__ += apidoc(solara.SpinnerSolara.f) # type: ignore
12 |
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-changed-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-7-changed-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-changed-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-linux-ipywidgets-8-changed-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-changed-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-7-changed-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-changed-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/latex_test.py/test_widget_latex_solara-flask-chromium-win32-ipywidgets-8-changed-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-linux-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-7-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-7-reference.png
--------------------------------------------------------------------------------
/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-8-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widgetti/solara/master/tests/ui/snapshots/tests/integration/widget_test.py/test_slider_all-flask-jupyter_notebook-chromium-win32-ipywidgets-8-reference.png
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/output/tooltip.py:
--------------------------------------------------------------------------------
1 | """# Tooltip"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 | title = "Tooltip"
9 |
10 |
11 | __doc__ += apidoc(solara.Tooltip.f) # type: ignore
12 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/README.md:
--------------------------------------------------------------------------------
1 | A bundle that is used for solara-server that includes all static assets we need (for vue/vuetify 3).
2 |
3 | For a dev install, use something like so that the Solara CDN proxy picks up the bundle locally:
4 |
5 | $ npm install
6 | $ npm run build
7 | $ npm run devlink
8 |
--------------------------------------------------------------------------------
/solara/server/pyinstaller/hook-ipyreact.py:
--------------------------------------------------------------------------------
1 | from PyInstaller.utils.hooks import collect_data_files, copy_metadata, collect_submodules
2 |
3 | hiddenimports = collect_submodules("ipyreact")
4 | datas = collect_data_files("ipyreact") # codespell:ignore datas
5 | datas += copy_metadata("ipyreact") # codespell:ignore datas
6 |
--------------------------------------------------------------------------------
/solara/components/code_highlight_css.py:
--------------------------------------------------------------------------------
1 | import ipyvuetify as vy
2 | import solara
3 |
4 |
5 | class CodeHighlightCssWidget(vy.VuetifyTemplate):
6 | template_file = (__file__, "code_highlight_css.vue")
7 |
8 |
9 | @solara.component
10 | def CodeHighlightCss():
11 | return CodeHighlightCssWidget.element()
12 |
--------------------------------------------------------------------------------
/solara/website/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .docs import CategoryLayout, Gallery, NoPage, SubCategoryLayout, WithCode # noqa
2 | from .header import Header
3 | from .markdown import MarkdownWithMetadata
4 |
5 | __all__ = ["Header", "MarkdownWithMetadata", "CategoryLayout", "Gallery", "NoPage", "SubCategoryLayout", "WithCode"]
6 |
--------------------------------------------------------------------------------
/tests/integration/app_widget.py:
--------------------------------------------------------------------------------
1 | import ipywidgets as widgets
2 |
3 | clicks = 0
4 |
5 |
6 | def on_click(button):
7 | global clicks
8 | clicks += 1
9 | button.description = f"Clicked {clicks} times"
10 |
11 |
12 | button = widgets.Button(description="Clicked 0 times")
13 | button.on_click(on_click)
14 |
--------------------------------------------------------------------------------
/solara/server/pyinstaller/hook-ipyvuetify.py:
--------------------------------------------------------------------------------
1 | from PyInstaller.utils.hooks import collect_data_files, copy_metadata, collect_submodules
2 |
3 | hiddenimports = collect_submodules("ipyvuetify")
4 | datas = collect_data_files("ipyvuetify") # codespell:ignore datas
5 | datas += copy_metadata("ipyvuetify") # codespell:ignore datas
6 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/common.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.alias import rv
3 |
4 |
5 | @solara.component
6 | def ColorCard(title, color):
7 | with rv.Card(style_=f"background-color: {color}; width: 100%; height: 100%") as main:
8 | rv.CardTitle(children=[title])
9 | return main
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/details.py:
--------------------------------------------------------------------------------
1 | """
2 | # Details
3 | """
4 |
5 | import solara
6 | from solara.website.components import NoPage
7 | from solara.website.utils import apidoc
8 |
9 | title = "Details"
10 |
11 | Page = NoPage
12 |
13 | __doc__ += apidoc(solara.Details.f) # type: ignore
14 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_state.py:
--------------------------------------------------------------------------------
1 | """# use_state"""
2 |
3 | import solara
4 | import solara.autorouting
5 | from solara.website.components import NoPage
6 | from solara.website.utils import apidoc
7 |
8 | title = "use_state"
9 | Page = NoPage
10 | __doc__ += apidoc(solara.use_state) # type: ignore
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/output/file_download.py:
--------------------------------------------------------------------------------
1 | """# FileDownload"""
2 |
3 | import solara
4 | from solara.website.components import NoPage
5 | from solara.website.utils import apidoc
6 |
7 | Page = NoPage
8 | title = "FileDownload"
9 |
10 |
11 | __doc__ += apidoc(solara.FileDownload.f) # type: ignore
12 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/display.py:
--------------------------------------------------------------------------------
1 | """
2 | # display
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "display"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.display) # type: ignore
17 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e -o pipefail
3 | # usage: ./release minor -n
4 | version=$(bump2version --dry-run --list $* | grep new_version= | sed -r s,"^.*=",,)
5 | echo Version tag @widgetti/solara-vuetify-app@$version
6 | bumpversion $* --verbose && git push upstream master @widgetti/solara-vuetify-app@$version
7 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/reactive.py:
--------------------------------------------------------------------------------
1 | """
2 | # reactive
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "reactive"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.reactive) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/task.py:
--------------------------------------------------------------------------------
1 | """# Task"""
2 |
3 | import solara
4 | import solara.autorouting
5 | import solara.lab
6 | from solara.website.components import NoPage
7 | from solara.website.utils import apidoc
8 |
9 | title = "Task"
10 | Page = NoPage
11 | __doc__ += apidoc(solara.lab.task) # type: ignore
12 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/card.py:
--------------------------------------------------------------------------------
1 | """
2 | # Card
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.components import NoPage
9 | from solara.website.utils import apidoc
10 |
11 | title = "Card"
12 |
13 | Page = NoPage
14 |
15 | __doc__ += apidoc(solara.Card.f) # type: ignore
16 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Stable
2 |
3 | Version of solara-enterprise is locked to solara, and released in CI.
4 |
5 | # Test a release
6 |
7 | e.g. to manually make a release with a new solara-enterprise
8 |
9 |
10 | ```
11 | $ cd packages/solara-enterprise
12 | $ bump2version --verbose major
13 | $ hatch build
14 | ```
15 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e -o pipefail
3 | # usage: ./release minor -n
4 | version=$(bump2version --dry-run --list $* | grep new_version= | sed -r s,"^.*=",,)
5 | echo Version tag @widgetti/solara-vuetify3-app@$version
6 | bumpversion $* --verbose && git push upstream master @widgetti/solara-vuetify3-app@$version
7 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/routing/use_router.py:
--------------------------------------------------------------------------------
1 | """
2 | # use_router
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "use_router"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.use_router) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/computed.py:
--------------------------------------------------------------------------------
1 | """
2 | # computed
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "computed"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.lab.computed) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.website.components import CategoryLayout, Gallery
3 |
4 |
5 | @solara.component
6 | def Page(route_external=None):
7 | Gallery(route_external)
8 |
9 |
10 | @solara.component
11 | def Layout(children=[]):
12 | CategoryLayout(children=children)
13 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_reactive.py:
--------------------------------------------------------------------------------
1 | """
2 | # use_reactive
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "use_reactive"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.use_reactive) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/component_vue.py:
--------------------------------------------------------------------------------
1 | """# component_vue"""
2 |
3 | import solara
4 | import solara.autorouting
5 | from solara.website.components import NoPage
6 | from solara.website.utils import apidoc
7 |
8 | title = "component_vue"
9 | Page = NoPage
10 | __doc__ += apidoc(solara.component_vue) # type: ignore
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/use_task.py:
--------------------------------------------------------------------------------
1 | """# use_task"""
2 |
3 | import solara
4 | import solara.autorouting
5 | import solara.lab
6 | from solara.website.components import NoPage
7 | from solara.website.utils import apidoc
8 |
9 | title = "use_task"
10 | Page = NoPage
11 | __doc__ += apidoc(solara.lab.use_task) # type: ignore
12 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/app_bar.py:
--------------------------------------------------------------------------------
1 | """
2 | # AppBar
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.components import NoPage
9 | from solara.website.utils import apidoc
10 |
11 | title = "AppBar"
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.AppBar.f) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/changelog/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.website.components.sidebar import Sidebar
4 | from solara.website.components import MarkdownWithMetadata
5 |
6 | title = "Changelog"
7 | HERE = Path(__file__)
8 |
9 | Page = MarkdownWithMetadata(Path(HERE.parent / "changelog.md").read_text())
10 | Sidebar = Sidebar
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/get_kernel_id.py:
--------------------------------------------------------------------------------
1 | """
2 | # get_kernel_id
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "get_kernel_id"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.get_kernel_id) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_trait_observe.py:
--------------------------------------------------------------------------------
1 | """# use_trait_observe"""
2 |
3 | import solara
4 | import solara.autorouting
5 | import solara.lab
6 | from solara.website.utils import apidoc
7 |
8 | from . import NoPage
9 |
10 | title = "use_trait_observe"
11 | Page = NoPage
12 | __doc__ += apidoc(solara.use_trait_observe) # type: ignore
13 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/routing/generate_routes.py:
--------------------------------------------------------------------------------
1 | """# generate_routes"""
2 |
3 | import solara
4 | import solara.autorouting
5 | from solara.website.components import NoPage
6 | from solara.website.utils import apidoc
7 |
8 | title = "generate_routes"
9 | Page = NoPage
10 | __doc__ += apidoc(solara.autorouting.generate_routes) # type: ignore
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/get_session_id.py:
--------------------------------------------------------------------------------
1 | """
2 | # get_session_id
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.components import NoPage
8 | from solara.website.utils import apidoc
9 |
10 | title = "get_session_id"
11 |
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.get_session_id) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/input_time.py:
--------------------------------------------------------------------------------
1 | """
2 | # InputTime
3 | """
4 |
5 | import solara
6 | from solara.website.components import NoPage
7 | from solara.website.utils import apidoc
8 |
9 | title = "InputTime"
10 |
11 |
12 | __doc__ += apidoc(solara.lab.components.input_time.InputTime.f) # type: ignore
13 |
14 |
15 | Page = NoPage
16 |
--------------------------------------------------------------------------------
/tests/pyinstaller/pyinstaller_test.py:
--------------------------------------------------------------------------------
1 | import os
2 | import playwright.sync_api
3 |
4 | TEST_PORT = int(os.environ.get("PORT", "18765"))
5 |
6 |
7 | def test_pyinstaller_basics(page: playwright.sync_api.Page):
8 | page.goto(f"http://localhost:{TEST_PORT}")
9 | page.locator("text=Clicked: 0").click()
10 | page.locator("text=Clicked: 1").wait_for()
11 |
--------------------------------------------------------------------------------
/solara/website/pages/roadmap/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.website.components.markdown import MarkdownWithMetadata
4 | from solara.website.components.sidebar import Sidebar
5 |
6 |
7 | title = "Roadmap"
8 | HERE = Path(__file__)
9 | Sidebar = Sidebar
10 |
11 | Page = MarkdownWithMetadata(Path(HERE.parent / "roadmap.md").read_text())
12 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es2015",
5 | "declaration": true,
6 | "outDir": "./lib",
7 | "rootDir": "src",
8 | "sourceMap": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true
11 | },
12 | "include": [
13 | "src/**/*"
14 | ],
15 | }
16 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_dark_effective.py:
--------------------------------------------------------------------------------
1 | """# use_dark_effective"""
2 |
3 | import solara
4 | import solara.autorouting
5 | import solara.lab
6 | from solara.website.utils import apidoc
7 |
8 | from . import NoPage
9 |
10 | title = "use_dark_effective"
11 | Page = NoPage
12 | __doc__ += apidoc(solara.lab.use_dark_effective) # type: ignore
13 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/app_bar_title.py:
--------------------------------------------------------------------------------
1 | """
2 | # AppBarTitle
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.components import NoPage
9 | from solara.website.utils import apidoc
10 |
11 | title = "AppBarTitle"
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.AppBarTitle.f) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/card_actions.py:
--------------------------------------------------------------------------------
1 | """
2 | # CardActions
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.components import NoPage
9 | from solara.website.utils import apidoc
10 |
11 | title = "CardActions"
12 |
13 | Page = NoPage
14 |
15 |
16 | __doc__ += apidoc(solara.CardActions.f) # type: ignore
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/faq/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import solara
4 | from solara.website.components.markdown import MarkdownWithMetadata
5 |
6 | title = "FAQ"
7 | HERE = Path(__file__)
8 |
9 |
10 | @solara.component
11 | def Page(route_external=None):
12 | MarkdownWithMetadata(Path(HERE.parent / "content" / "99-faq.md").read_text())
13 |
--------------------------------------------------------------------------------
/solara/website/pages/apps/__init__.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | solara.Markdown(
7 | """
8 | Hi there 👋! All fullscreen apps are linked from [the examples page](/examples).
9 | """
10 | )
11 |
12 |
13 | @solara.component
14 | def Layout(children):
15 | route, routes = solara.use_route()
16 | return children[0]
17 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/06-custom-routes.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page1():
6 | solara.Button("hi1")
7 |
8 |
9 | @solara.component
10 | def Page2():
11 | solara.Button("hi2")
12 |
13 |
14 | routes = [
15 | solara.Route(path="/", component=Page1, label="Hi1"),
16 | solara.Route(path="page2", component=Page2, label="Hi2"),
17 | ]
18 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/content/80-what-is-lab.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: What is Solara.lab?
3 | description: Solara lab is a subpackage in solara containing Components, hooks and parts of Solara that are slightly experimental.
4 | ---
5 | # What is Solara lab?
6 |
7 | Solara lab is a subpackage in solara containing Components, hooks and parts of Solara that are slightly experimental.
8 |
--------------------------------------------------------------------------------
/solara/template/button.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | clicks = solara.reactive(0)
4 |
5 |
6 | @solara.component
7 | def Page():
8 | color = "green"
9 | if clicks.value >= 5:
10 | color = "red"
11 |
12 | def increment():
13 | clicks.value += 1
14 | print("clicks", clicks) # noqa
15 |
16 | solara.Button(label=f"Clicked: {clicks}", on_click=increment, color=color)
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/routing/generate_routes_directory.py:
--------------------------------------------------------------------------------
1 | """# generate_routes_directory"""
2 |
3 | import solara
4 | import solara.autorouting
5 | from solara.website.components import NoPage
6 | from solara.website.utils import apidoc
7 |
8 | title = "generate_routes_directory"
9 | Page = NoPage
10 | __doc__ += apidoc(solara.autorouting.generate_routes_directory) # type: ignore
11 |
--------------------------------------------------------------------------------
/tests/unit/toestand_computed_reload.py:
--------------------------------------------------------------------------------
1 | import solara
2 | import solara.lab
3 |
4 | value_reactive = solara.reactive(1.0)
5 |
6 |
7 | @solara.lab.computed
8 | def computed_reactive():
9 | return value_reactive.value + 1.0
10 |
11 |
12 | @solara.component
13 | def Page():
14 | solara.FloatSlider("test", value=value_reactive)
15 | solara.InputFloat("test", value=computed_reactive.value)
16 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/src/solara-vuetify-app.js:
--------------------------------------------------------------------------------
1 |
2 | import Vue from 'vue';
3 | import Vuetify from 'vuetify';
4 | import 'vuetify/dist/vuetify.min.css';
5 | import { addCompiler } from '@mariobuikhuizen/vue-compiler-addon';
6 |
7 | addCompiler(Vue);
8 |
9 | Vue.use(Vuetify);
10 |
11 | import * as solara from './solara';
12 | export { solara };
13 |
14 | export { Vue };
15 | export { Vuetify };
16 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/10-howto/00-overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview of how-to articles
3 | description: The how-tos are meant as deeper dives into specific topics from various perspectives
4 | ---
5 |
6 | The how-tos are meant as deeper dives into specific topics. Although we try to write each how-to as a standalone document, some parts of a how-to may build on top of a previous one.
7 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import solara
4 | import solara.components.applayout
5 | from solara.website.components.notebook import Notebook
6 |
7 | HERE = Path(__file__).parent
8 |
9 |
10 | @solara.component
11 | def Page():
12 | # only execute once, other
13 | Notebook(HERE / "_data_science.ipynb")
14 |
--------------------------------------------------------------------------------
/pyinstaller/minimal/sample_app.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | clicks = solara.reactive(0)
4 |
5 |
6 | @solara.component
7 | def Page():
8 | color = "green"
9 | if clicks.value >= 5:
10 | color = "red"
11 |
12 | def increment():
13 | clicks.value += 1
14 | print("clicks", clicks) # noqa
15 |
16 | solara.Button(label=f"Clicked: {clicks}", on_click=increment, color=color)
17 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/output/html.py:
--------------------------------------------------------------------------------
1 | """# HTML"""
2 |
3 | import solara
4 | from solara.website.utils import apidoc
5 |
6 |
7 | @solara.component
8 | def Page():
9 | html = """
10 |
Custom html
11 |
12 | Item 1
13 | Item 2
14 |
15 | """
16 | solara.HTML(tag="div", unsafe_innerHTML=html)
17 |
18 |
19 | __doc__ += apidoc(solara.HTML.f) # type: ignore
20 |
--------------------------------------------------------------------------------
/tests/integration/reload/apps.py:
--------------------------------------------------------------------------------
1 | import dataclasses
2 |
3 | import solara
4 | from solara.alias import rw
5 |
6 |
7 | @dataclasses.dataclass
8 | class Clicks:
9 | value: int
10 |
11 |
12 | @solara.component
13 | def ButtonClick():
14 | clicks, set_clicks = solara.use_state(Clicks(0))
15 | return rw.Button(description=f"Clicked {clicks.value} times", on_click=lambda: set_clicks(Clicks(clicks.value + 1)))
16 |
--------------------------------------------------------------------------------
/solara/website/pages/apps/authorization/users.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | from . import user
4 |
5 | github_url = solara.util.github_url(__file__)
6 |
7 |
8 | @solara.component
9 | def Page():
10 | assert user.value is not None
11 | solara.Markdown(f"Hi {user.value.username}!")
12 | solara.Button(label="View source", icon_name="mdi-github-circle", attributes={"href": github_url, "target": "_blank"}, text=True, outlined=True)
13 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | # Overview
3 | Click on one of the items on the left.
4 | """
5 |
6 | import solara
7 | from solara.website.components import CategoryLayout, Gallery
8 |
9 | _title = "API"
10 |
11 |
12 | @solara.component
13 | def Page(route_external=None):
14 | Gallery(route_external)
15 |
16 |
17 | @solara.component
18 | def Layout(children=[]):
19 | CategoryLayout(children=children)
20 |
--------------------------------------------------------------------------------
/solara/server/pyinstaller/hook-solara.py:
--------------------------------------------------------------------------------
1 | from PyInstaller.utils.hooks import collect_data_files, collect_submodules
2 |
3 | hiddenimports = collect_submodules("solara")
4 | datas = collect_data_files("solara") # codespell:ignore datas
5 | datas += collect_data_files("solara-ui") # codespell:ignore datas
6 |
7 | # this makes sure that inspect.getfile works, which is used for the
8 | # vue component decorator
9 | module_collection_mode = "pyz+py"
10 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage-widgets/01-views.py:
--------------------------------------------------------------------------------
1 | import ipywidgets as widgets
2 |
3 | clicks = 0
4 |
5 | print("View button: I get run at startup, and for every page request") # noqa
6 |
7 |
8 | def on_click(button):
9 | global clicks
10 | clicks += 1
11 | button.description = f"Viewed {clicks} times"
12 |
13 |
14 | button = widgets.Button(description="Never viewed")
15 | button.on_click(on_click)
16 |
17 | page = button
18 |
--------------------------------------------------------------------------------
/solara/template/portal/Procfile:
--------------------------------------------------------------------------------
1 | # heroku by default sets WEB_CONCURRENCY=2
2 | # see: https://devcenter.heroku.com/changelog-items/618
3 | # which uvicorn picks up, unless we explicitly set --workers --1
4 | # see https://www.uvicorn.org/deployment/
5 | # we do not support multiple workers yet
6 | # we also need to bind to 0.0.0.0 otherwise heroku cannot route to our server
7 | web: solara run solara_portal.pages --port=$PORT --no-open --host=0.0.0.0 --workers 1
8 |
--------------------------------------------------------------------------------
/solara/website/pages/apps/authorization/admin.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | from . import user
4 |
5 | github_url = solara.util.github_url(__file__)
6 |
7 |
8 | @solara.component
9 | def Page():
10 | assert user.value is not None
11 | solara.Markdown(f"Hi {user.value.username}, you are an admin")
12 | solara.Button(label="View source", icon_name="mdi-github-circle", attributes={"href": github_url, "target": "_blank"}, text=True, outlined=True)
13 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage-widgets/02-likes.py:
--------------------------------------------------------------------------------
1 | import ipywidgets as widgets
2 |
3 | clicks = 0
4 |
5 | print("Like button: I get run at startup, and for every page request") # noqa
6 |
7 |
8 | def on_click(button):
9 | global clicks
10 | clicks += 1
11 | button.description = f"Liked {clicks} times"
12 |
13 |
14 | button = widgets.Button(description="No likes recorded")
15 | button.on_click(on_click)
16 |
17 | page = button
18 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview of how to deploy your Solara application or dashboard
3 | description: Solara apps can be easily either self hosted, or hosted on a variety of cloud platforms.
4 | ---
5 | # Deploying a solara app
6 |
7 | A Solara app can be [self hosted](/documentation/getting_started/deploying/self-hosted) or [cloud hosted](/documentation/getting_started/deploying/cloud-hosted).
8 |
--------------------------------------------------------------------------------
/solara/website/public/social/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage-widgets/03-volume.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | volume, set_volume = solara.use_state(5)
7 | with solara.VBox() as main:
8 | solara.Markdown("# Choose your volume")
9 | solara.IntSlider("Volume", value=volume, on_value=set_volume, min=0, max=11)
10 | if volume == 11:
11 | solara.Markdown(f"Yeah! {volume} is the best volume!")
12 | return main
13 |
--------------------------------------------------------------------------------
/solara/lab/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .chat import ChatBox, ChatInput, ChatMessage # noqa: F401
2 | from .confirmation_dialog import ConfirmationDialog # noqa: F401
3 | from .input_date import InputDate, InputDateRange # noqa: F401
4 | from .input_time import InputTime as InputTime
5 | from .menu import ClickMenu, ContextMenu, Menu # noqa: F401 F403
6 | from .tabs import Tab, Tabs # noqa: F401
7 | from .theming import ThemeToggle, theme, use_dark_effective # noqa: F401
8 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md:
--------------------------------------------------------------------------------
1 | # Solara enterprise
2 |
3 | Solara enterprise is a not Open Source, but the source code is visible, is free for non-commercial use and installable from pypi.
4 |
5 | For commercial use, you require a license. Please see [pricing](/pricing) for more information.
6 |
7 | Solara-enterprise will stay free for non-commercial use and features that are in solara will **not be moved to solara-enterprise**.
8 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/pages/viz/overview.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | from ... import data
4 | from ...components import Layout
5 |
6 |
7 | @solara.component
8 | def Page(name: str, page: int = 0, page_size=100):
9 | if name not in data.dfs:
10 | return solara.Error(f"No such dataframe: {name!r}")
11 | df = data.dfs[name]
12 | with Layout() as main:
13 | solara.DataTable(df=df, page=page, items_per_page=page_size)
14 | return main
15 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/gridfixed.py:
--------------------------------------------------------------------------------
1 | """
2 | # GridFixed
3 |
4 | Lays out children in a grid with a fixed number of columns.
5 | """
6 |
7 | import solara
8 |
9 | from ..common import ColorCard
10 |
11 | title = "GridFixed"
12 |
13 |
14 | @solara.component
15 | def Page():
16 | colors = "green red orange brown yellow pink".split()
17 | with solara.GridFixed(columns=3):
18 | for color in colors:
19 | ColorCard(color, color)
20 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/hbox.py:
--------------------------------------------------------------------------------
1 | """
2 | # HBox
3 | Lays out children in horizontal direction.
4 | """
5 |
6 | import solara
7 |
8 | from ..common import ColorCard
9 |
10 |
11 | @solara.component
12 | def Page():
13 | with solara.VBox() as main:
14 | colors = "green red orange brown yellow pink".split()
15 | with solara.HBox():
16 | for color in colors:
17 | ColorCard(color, color)
18 | return main
19 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/single_file_multiple_routes.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Home():
6 | with solara.Sidebar():
7 | solara.SliderInt(label="in sidebar")
8 | solara.Markdown("Home")
9 |
10 |
11 | @solara.component
12 | def About():
13 | solara.Markdown("About")
14 |
15 |
16 | routes = [
17 | solara.Route(path="/", component=Home, label="Home"),
18 | solara.Route(path="about", component=About, label="About"),
19 | ]
20 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/vbox.py:
--------------------------------------------------------------------------------
1 | """
2 | # VBox
3 |
4 | Lays out children in a vertical direction.
5 | """
6 |
7 | import solara
8 |
9 | from ..common import ColorCard
10 |
11 |
12 | @solara.component
13 | def Page():
14 | with solara.VBox() as main:
15 | colors = "green red orange brown yellow pink".split()
16 | with solara.VBox():
17 | for color in colors:
18 | ColorCard(color, color)
19 | return main
20 |
--------------------------------------------------------------------------------
/packages/solara-server/README.md:
--------------------------------------------------------------------------------
1 | The solara server enables running ipywidgets based applications without a real Jupyter kernel, allowing multiple "Virtual kernels" to share the same process for better performance and scalability.
2 |
3 | See https://solara.dev/documentation/advanced/understanding/solara-server for more details.
4 |
5 | ## Installation
6 |
7 | ```bash
8 | pip install solara-server[starlette,dev]
9 | ```
10 |
11 | ## Usage
12 |
13 | ```bash
14 | $ solara run myapp.py
15 | ```
16 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.autorouting import generate_routes_directory
4 | from solara.website.components.markdown import MarkdownWithMetadata
5 |
6 | HERE = Path(__file__)
7 | # if we didn't put the content in the subdirectory, but pointed to the current file
8 | # we would include the current file recursively, causing an infinite loop
9 | routes = generate_routes_directory(HERE.parent / "content", MarkdownWithMetadata)
10 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from solara.autorouting import generate_routes_directory
4 | from solara.website.components.markdown import MarkdownWithMetadata
5 |
6 | HERE = Path(__file__)
7 | # if we didn't put the content in the subdirectory, but pointed to the current file
8 | # we would include the current file recursively, causing an infinite loop
9 | routes = generate_routes_directory(HERE.parent / "content", MarkdownWithMetadata)
10 |
--------------------------------------------------------------------------------
/packages/solara-milkdown/src/index.js:
--------------------------------------------------------------------------------
1 | export { defaultValueCtx, Editor, hex2rgb, rootCtx, ThemeColor, themeFactory, ThemeGlobal, ThemeIcon, ThemeSize } from '@milkdown/core';
2 | export { history } from '@milkdown/plugin-history';
3 | export { listener, listenerCtx } from '@milkdown/plugin-listener';
4 | export { menu, menuPlugin } from '@milkdown/plugin-menu';
5 | export { commonmark } from '@milkdown/preset-commonmark';
6 | export { gfm } from '@milkdown/preset-gfm';
7 | export { nord } from '@milkdown/theme-nord';
8 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/src/solara-vuetify-app.js:
--------------------------------------------------------------------------------
1 | import * as Vue from 'vue';
2 | import * as Vuetify from 'vuetify';
3 | import 'vuetify/dist/vuetify.min.css';
4 |
5 | import * as components from 'vuetify/components';
6 | import * as directives from 'vuetify/directives';
7 |
8 | const vuetifyPlugin = Vuetify.createVuetify({
9 | components,
10 | directives,
11 | });
12 |
13 |
14 | import * as solara from './solara';
15 | export { solara };
16 |
17 | export { Vue, Vuetify, vuetifyPlugin };
18 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/page/head.py:
--------------------------------------------------------------------------------
1 | """# Head"""
2 |
3 | import solara
4 | from solara.website.utils import apidoc
5 |
6 |
7 | @solara.component
8 | def Page():
9 | solara.Info("A Head component does not render somesome visual on the page, but it is used to avoid duplicate tags, such as titles.")
10 | with solara.Head():
11 | # title should always occur inside a Head component
12 | solara.Title("Custom title")
13 |
14 |
15 | __doc__ += apidoc(solara.Head.f) # type: ignore
16 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/license.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from typing import Dict
3 |
4 | from rich import print
5 |
6 | warned: Dict[str, bool] = {}
7 |
8 |
9 | def check(name):
10 | if name in warned:
11 | return
12 | warned[name] = True
13 | print( # noqa: T201
14 | f"[bold yellow]Using the enterprise {name} feature requires a license, unless used for non-commerical use. "
15 | "Please contact us at contact@solara.dev to get a license.",
16 | file=sys.stderr,
17 | )
18 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Using Solara within notebooks
3 | description: Solara can be used to generate an interactive app directly using your notebook file by running just one command.
4 | ---
5 | # Notebook support
6 |
7 | We also support notebooks, simply assign to the `Page` variable in a code cell, save your notebook, and run `$ solara run myapp.ipynb`. If you widget or component is called differently, run like `$ solara run myapp.ipynb:myobject.nested_widget`.
8 |
--------------------------------------------------------------------------------
/packages/solara-assets/download_cdn_test.py:
--------------------------------------------------------------------------------
1 | from packages.assets.hatch_build import npm_pack
2 |
3 |
4 | def test_npm_pack(tmp_path_factory):
5 | base_cache_dir = tmp_path_factory.mktemp("cdn")
6 |
7 | package = "@widgetti/solara-vuetify-app"
8 | version = "0.0.1-alpha.1"
9 | npm_pack(base_cache_dir, package, version)
10 |
11 | some_file = base_cache_dir / f"{package}@{version}" / "dist" / "037d830416495def72b7881024c14b7b.woff2"
12 | assert some_file.is_file()
13 | assert len(some_file.read_bytes()) == 15436
14 |
--------------------------------------------------------------------------------
/solara/website/pages/apps/tutorial-streamlit.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | x, set_x = solara.use_state(2)
7 | x_squared = x**2
8 |
9 | with solara.Sidebar():
10 | solara.Markdown("## My First Solara app ☀️")
11 | solara.SliderInt(label="x", value=x, on_value=set_x)
12 | solara.Markdown(f"{x} squared = {x_squared}")
13 |
14 |
15 | @solara.component
16 | def Layout(children):
17 | route, routes = solara.use_route()
18 | return solara.AppLayout(children=children)
19 |
--------------------------------------------------------------------------------
/tests/integration/error_test.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import playwright
4 | import playwright.sync_api
5 |
6 | app_path = Path(__file__).parent / "testapp.py"
7 |
8 |
9 | def test_error_in_render(page_session: playwright.sync_api.Page, solara_server, solara_app, extra_include_path):
10 | with extra_include_path(app_path.parent), solara_app("testapp:clickboom"):
11 | page_session.goto(solara_server.base_url)
12 | page_session.locator("text=Boom").click()
13 | page_session.locator("text=I crash on 1").wait_for()
14 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/cross_filter/cross_filter_select.py:
--------------------------------------------------------------------------------
1 | """# CrossFilterSelect"""
2 |
3 | import plotly
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | df = plotly.data.tips()
10 |
11 |
12 | @solara.component
13 | def Page():
14 | solara.provide_cross_filter()
15 | solara.CrossFilterReport(df, classes=["py-2"])
16 | solara.CrossFilterSelect(df, "sex")
17 | solara.CrossFilterSelect(df, "time")
18 |
19 |
20 | __doc__ += apidoc(solara.CrossFilterSelect.f) # type: ignore
21 |
--------------------------------------------------------------------------------
/packages/solara-vuetify-app/.bumpversion.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 10.0.3
3 | commit = True
4 | tag = True
5 | tag_name = @widgetti/solara-vuetify-app@{new_version}
6 | tag_message = Bump version solara-vuetify-app: {current_version} → {new_version}
7 | message = Bump version solara-vuetify-app: {current_version} → {new_version}
8 |
9 | [bumpversion:file:package.json]
10 |
11 | [bumpversion:file:../../solara/server/templates/solara.html.j2]
12 |
13 | [bumpversion:file:../../release.sh]
14 |
15 | [bumpversion:file:../solara-assets/hatch_build.py]
16 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/.bumpversion.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 5.0.2
3 | commit = True
4 | tag = True
5 | tag_name = @widgetti/solara-vuetify3-app@{new_version}
6 | tag_message = Bump version solara-vuetify3-app: {current_version} → {new_version}
7 | message = Bump version solara-vuetify3-app: {current_version} → {new_version}
8 |
9 | [bumpversion:file:package.json]
10 |
11 | [bumpversion:file:../../solara/server/templates/solara.html.j2]
12 |
13 | [bumpversion:file:../../release.sh]
14 |
15 | [bumpversion:file:../solara-assets/hatch_build.py]
16 |
--------------------------------------------------------------------------------
/pyinstaller/entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.apple.security.cs.allow-jit
7 |
8 | com.apple.security.cs.allow-unsigned-executable-memory
9 |
10 | com.apple.security.cs.disable-library-validation
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/cross_filter/cross_filter_report.py:
--------------------------------------------------------------------------------
1 | """# CrossFilterReport"""
2 |
3 | import plotly
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | df = plotly.data.gapminder()
10 |
11 |
12 | @solara.component
13 | def Page():
14 | solara.provide_cross_filter()
15 | solara.CrossFilterReport(df, classes=["py-2"])
16 | solara.CrossFilterSelect(df, "country")
17 | solara.CrossFilterSlider(df, "gdpPercap", mode=">")
18 |
19 |
20 | __doc__ += apidoc(solara.CrossFilterReport.f) # type: ignore
21 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/input_date.py:
--------------------------------------------------------------------------------
1 | """
2 | # InputDate
3 |
4 | This page contains the two variants of datepickers available in solara
5 |
6 | # InputDate
7 | """
8 |
9 | import solara
10 | from solara.website.components import NoPage
11 | from solara.website.utils import apidoc
12 |
13 | title = "InputDate"
14 |
15 |
16 | __doc__ += apidoc(solara.lab.components.input_date.InputDate.f) # type: ignore
17 | __doc__ += "# InputDateRange"
18 | __doc__ += apidoc(solara.lab.components.input_date.InputDateRange.f) # type: ignore
19 |
20 | Page = NoPage
21 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/single_file_routes.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page1():
6 | solara.Text("Page 1")
7 |
8 |
9 | @solara.component
10 | def Page2():
11 | solara.Text("Page 2")
12 |
13 |
14 | @solara.component
15 | def Layout(children):
16 | with solara.AppLayout():
17 | with solara.Column():
18 | solara.Text("Custom layout")
19 | solara.display(*children)
20 |
21 |
22 | routes = [
23 | solara.Route("/", component=Page1, layout=Layout),
24 | solara.Route("page2", component=Page2),
25 | ]
26 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py:
--------------------------------------------------------------------------------
1 | """# CrossFilterSlider"""
2 |
3 | import plotly
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | df = plotly.data.gapminder()
10 |
11 |
12 | @solara.component
13 | def Page():
14 | solara.provide_cross_filter()
15 | solara.CrossFilterReport(df, classes=["py-2"])
16 | solara.CrossFilterSlider(df, "pop", mode=">")
17 | solara.CrossFilterSlider(df, "gdpPercap", mode="<")
18 |
19 |
20 | __doc__ += apidoc(solara.CrossFilterSlider.f) # type: ignore
21 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/enterprise/avatar.py:
--------------------------------------------------------------------------------
1 | """
2 | # Avatar
3 |
4 | """
5 |
6 | from types import ModuleType
7 | from typing import Optional
8 |
9 | auth: Optional[ModuleType]
10 | try:
11 | from solara_enterprise import auth
12 | except ImportError:
13 | auth = None
14 | from solara.website.components import NoPage
15 | from solara.website.utils import apidoc
16 |
17 | title = "Avatar"
18 |
19 | Page = NoPage
20 |
21 | if auth:
22 | __doc__ += apidoc(auth.Avatar.f) # type: ignore
23 | else:
24 | __doc__ += "solara-enterprise not installed."
25 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Fundamentals of Solara
3 | description: These articles dive deeper into the fundamental aspects of Soalra, like using components, hooks, and managing state.
4 | ---
5 | # Fundamentals
6 |
7 | If you want to dive deeper into Solara, this section is for you. We will cover the following topics:
8 |
9 | * [Components](/documentation/getting_started/fundamentals/components)
10 | * Hooks (soon)
11 | * [State management](/documentation/getting_started/fundamentals/state-management)
12 |
--------------------------------------------------------------------------------
/release.md:
--------------------------------------------------------------------------------
1 |
2 | # Fully automated
3 |
4 | $ ./release.sh patch
5 |
6 |
7 | ## Making an alpha release
8 |
9 |
10 | $ ./release.sh patch --new-version 1.56.0a1
11 |
12 |
13 | # semi automated
14 | To make a new release
15 | ```
16 | # update solara/__init__.py
17 | $ git add -u && git commit -m 'Release v1.56.0' && git tag v1.56.0 && git push upstream master v1.56.0
18 | ```
19 |
20 |
21 | If a problem happens, and you want to keep the history clean
22 | ```
23 | # do fix
24 | $ git rebase -i HEAD~3
25 | $ git tag v1.56.0 -f && git push upstream master v1.56.0 -f
26 | ```
27 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/button.py:
--------------------------------------------------------------------------------
1 | """
2 | # Button
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.utils import apidoc
8 |
9 |
10 | @solara.component
11 | def Page():
12 | count, set_count = solara.use_state(0)
13 |
14 | def increment():
15 | set_count(count + 1)
16 |
17 | with solara.VBox() as main:
18 | with solara.HBox():
19 | solara.Button(label=f"Clicked {count} times", on_click=increment, icon_name="mdi-thumb-up")
20 | return main
21 |
22 |
23 | __doc__ += apidoc(solara.Button.f) # type: ignore
24 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/select.py:
--------------------------------------------------------------------------------
1 | """
2 | # Select components
3 |
4 | Select comes in two flavours:
5 |
6 | * `Select` for a singular selection
7 | * `SelectMultiple` which allows for multiple selections
8 |
9 |
10 | """
11 |
12 | import solara
13 | from solara.website.components import NoPage
14 | from solara.website.utils import apidoc
15 |
16 | Page = NoPage
17 |
18 |
19 | __doc__ += "# Select"
20 | __doc__ += apidoc(solara.Select.f) # type: ignore
21 | __doc__ += "# SelectMultiple"
22 | __doc__ += apidoc(solara.SelectMultiple.f) # type: ignore
23 |
--------------------------------------------------------------------------------
/solara/website/components/algolia.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
25 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/togglebuttons.py:
--------------------------------------------------------------------------------
1 | """
2 | # ToggleButtons
3 |
4 | ToggleButtons are in two flavours, for single, and for multiple selections.
5 |
6 |
7 | """
8 |
9 | import solara
10 | from solara.website.components import NoPage
11 | from solara.website.utils import apidoc
12 |
13 | title = "ToggleButtons"
14 |
15 | Page = NoPage
16 |
17 |
18 | __doc__ += "# ToggleButtonsSingle"
19 | __doc__ += apidoc(solara.ToggleButtonsSingle.f) # type: ignore
20 | __doc__ += "# ToggleButtonsMultiple"
21 | __doc__ += apidoc(solara.ToggleButtonsMultiple.f) # type: ignore
22 |
--------------------------------------------------------------------------------
/tests/unit/switch_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import MagicMock
2 |
3 | import ipyvuetify as vw
4 |
5 | import solara
6 |
7 |
8 | def test_switch():
9 | on_value = MagicMock()
10 | el = solara.Switch(label="label", value=True, on_value=on_value)
11 | _, rc = solara.render(el, handle_error=False)
12 | switch = rc.find(vw.Switch)
13 | switch.widget.v_model = False
14 | assert on_value.call_count == 1
15 | switch.widget.v_model = False
16 | assert on_value.call_count == 1
17 | switch.widget.v_model = True
18 | assert on_value.call_count == 2
19 | rc.close()
20 |
--------------------------------------------------------------------------------
/solara/template/portal/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling==1.26.3"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "solara-portal"
7 | license = {file = "LICENSE"}
8 | classifiers = ["License :: OSI Approved :: MIT License"]
9 | dynamic = ["version", "description"]
10 | dependencies = [
11 | "solara",
12 | ]
13 |
14 | [tool.hatch.version]
15 | path = "solara_portal/__init__.py"
16 |
17 |
18 |
19 | [project.urls]
20 | Home = "https://www.github.com/widgetti/solara"
21 |
22 | [tool.black]
23 | line-length = 160
24 |
25 | [tool.isort]
26 | profile = "black"
27 |
--------------------------------------------------------------------------------
/tests/unit/no_solara_test.py:
--------------------------------------------------------------------------------
1 | import ipywidgets as widgets
2 | from IPython.display import display
3 |
4 | import solara.components.file_download
5 |
6 | # test if normal widget code works with no app context
7 |
8 |
9 | def test_create_widget(no_kernel_context):
10 | button = widgets.Button(description="Click me")
11 | button.layout.close()
12 | button.close()
13 |
14 |
15 | def test_vue_template(no_kernel_context):
16 | widget = solara.components.file_download.FileDownloadWidget()
17 | widget.close()
18 |
19 |
20 | def test_display(no_kernel_context):
21 | display("test")
22 |
--------------------------------------------------------------------------------
/packages/solara-assets/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Stable
2 |
3 | Version of solara-assets is locked to solara, and released in CI.
4 |
5 | # Test a release
6 |
7 | e.g. to manually make a release with a new solara-vuetify-app
8 |
9 |
10 | ```
11 | $ cd packages/solara-vuetify-app
12 | $ bump2version --verbose major
13 | $ cd ../assets
14 | $ batch build
15 | # will fail downloading from cdn, so we fill the directory manually
16 | $ tar zxfv ../solara-vuetify-app/widgetti-solara-vuetify-app-2.0.0.tgz --strip-components=1 --directory cdn/@widgetti/solara-vuetify-app@2.0.0/
17 | # build again
18 | $ batch build
19 | ```
20 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py:
--------------------------------------------------------------------------------
1 | """# CrossFilterDataFrame"""
2 |
3 | import plotly
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | title = "CrossFilterDataFrame"
10 | df = plotly.data.gapminder()
11 |
12 |
13 | @solara.component
14 | def Page():
15 | solara.provide_cross_filter()
16 |
17 | solara.CrossFilterReport(df, classes=["py-2"])
18 | solara.CrossFilterSelect(df, "country")
19 | solara.CrossFilterDataFrame(df)
20 |
21 |
22 | __doc__ += apidoc(solara.CrossFilterDataFrame.f) # type: ignore
23 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_cross_filter.py:
--------------------------------------------------------------------------------
1 | """# use_cross_filter"""
2 |
3 | import plotly
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | title = "use_cross_filter"
10 |
11 |
12 | df = plotly.data.gapminder()
13 |
14 |
15 | @solara.component
16 | def Page():
17 | solara.provide_cross_filter()
18 | solara.CrossFilterReport(df, classes=["py-2"])
19 | solara.CrossFilterSelect(df, "continent")
20 | solara.CrossFilterSlider(df, "gdpPercap", mode=">")
21 |
22 |
23 | __doc__ += apidoc(solara.use_cross_filter) # type: ignore
24 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/enterprise/avatar_menu.py:
--------------------------------------------------------------------------------
1 | """
2 | # AvatarMenu
3 |
4 | """
5 |
6 | from types import ModuleType
7 | from typing import Optional
8 |
9 | auth: Optional[ModuleType]
10 | try:
11 | from solara_enterprise import auth
12 | except ImportError:
13 | auth = None
14 | from solara.website.components import NoPage
15 | from solara.website.utils import apidoc
16 |
17 | title = "AvatarMenu"
18 |
19 | Page = NoPage
20 |
21 |
22 | if auth:
23 | __doc__ += apidoc(auth.AvatarMenu.f) # type: ignore
24 | else:
25 | __doc__ += "solara-enterprise not installed."
26 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/05-and-notebooks.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import reacton.ipyvuetify as v\n",
10 | "import solara\n",
11 | "\n",
12 | "\n",
13 | "@solara.component\n",
14 | "def Page():\n",
15 | " return v.Slider(label=\"Language\")"
16 | ]
17 | }
18 | ],
19 | "metadata": {
20 | "language_info": {
21 | "name": "python"
22 | },
23 | "orig_nbformat": 4
24 | },
25 | "nbformat": 4,
26 | "nbformat_minor": 2
27 | }
28 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/auth/__init__.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Optional, cast
2 |
3 | from solara.lab import Reactive
4 |
5 | from .components import Avatar, AvatarMenu
6 | from .utils import get_login_url, get_logout_url
7 |
8 | __all__ = ["user", "get_login_url", "get_logout_url", "Avatar", "AvatarMenu"]
9 |
10 | # the current way of generating a key is based in the default value
11 | # which may collide after a hot reload, since solara itself is not reloaded
12 | # if we give a fixed key, we can avoid this
13 | user = Reactive(cast(Optional[Dict], None), key="solara-enterprise.auth.user")
14 |
--------------------------------------------------------------------------------
/tsconfigbase.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "composite": true,
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "incremental": true,
8 | "jsx": "react",
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "noEmitOnError": true,
12 | "noImplicitAny": true,
13 | "noUnusedLocals": true,
14 | "preserveWatchOutput": true,
15 | "resolveJsonModule": true,
16 | "strict": true,
17 | "skipLibCheck": true,
18 | "strictNullChecks": true,
19 | "target": "es2017",
20 | "types": []
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/solara/website/pages/about/about.md:
--------------------------------------------------------------------------------
1 | # About Us
2 |
3 | Solara is a framework created by Maarten Breddels, and developed by [Widgetti](https://widgetti.io). Widgetti is a small company based in the Netherlands, focusing on developing tools for the Jupyter ecosystem. We combine ipywidgets and python experience with expertise in front-end development to help data scientists and python app developers make the most of their time. If you could use our years of diverse industry experience, reach out [here](/contact). You can find out more about Solara [here](/documentation/getting_started/introduction), or get to know our team [here](/our_team).
4 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/advanced/meta.py:
--------------------------------------------------------------------------------
1 | """# Meta"""
2 |
3 | import solara
4 | from solara.website.utils import apidoc
5 |
6 |
7 | @solara.component
8 | def Page():
9 | solara.Info("Nothing to see here, only in this page's source code, or by looking at the google search results for this page.")
10 | with solara.Head():
11 | solara.Meta(
12 | name="description",
13 | content="The Meta component can be used to set the description of a page. This is useful for SEO, or crawlers that index your page.",
14 | )
15 |
16 |
17 | __doc__ += apidoc(solara.Meta.f) # type: ignore
18 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | # heroku by default sets WEB_CONCURRENCY=2
2 | # see: https://devcenter.heroku.com/changelog-items/618
3 | # which uvicorn picks up, unless we explicitly set --workers --1
4 | # see https://www.uvicorn.org/deployment/
5 | # we also need to bind to 0.0.0.0 otherwise heroku cannot route to our server
6 | # for playwright: run $ heroku buildpacks:add https://github.com/mxschmitt/heroku-playwright-buildpack --app solara-dem
7 | # also add PLAYWRIGHT_BUILDPACK_BROWSERS chromium to your env vars in the Settings in heroku
8 | web: (playwright install && solara run solara.website.pages --port=$PORT --no-open --host=0.0.0.0 --workers 1 --ssg --production)
9 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/app_layout.py:
--------------------------------------------------------------------------------
1 | """
2 | # AppLayout
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.utils import apidoc
9 |
10 | title = "AppLayout"
11 |
12 |
13 | @solara.component
14 | def Page():
15 | return solara.Markdown(
16 | """
17 | An example cannot be shown embedded in this page, Visit the [AppLayout page](/apps/scatter) to see an example.
18 |
19 | [](/apps/scatter)
20 | """
21 | )
22 |
23 |
24 | __doc__ += apidoc(solara.AppLayout.f) # type: ignore
25 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/menu.py:
--------------------------------------------------------------------------------
1 | """
2 | # Menus
3 |
4 | This page contains the various kinds of menu elements available to use in solara
5 |
6 | # Menu
7 | """
8 |
9 | import solara
10 | from solara.website.components import NoPage
11 | from solara.website.utils import apidoc
12 |
13 | title = "Menus"
14 |
15 |
16 | __doc__ += apidoc(solara.lab.components.menu.Menu.f) # type: ignore
17 | __doc__ += "# ClickMenu"
18 | __doc__ += apidoc(solara.lab.components.menu.ClickMenu.f) # type: ignore
19 | __doc__ += "# ContextMenu"
20 | __doc__ += apidoc(solara.lab.components.menu.ContextMenu.f) # type: ignore
21 |
22 | Page = NoPage
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "Report a Bug \U0001F41B"
3 | about: "Is Solara not working the way you expect it to?"
4 | ---
5 |
6 |
7 |
8 | ## Expected Behavior
9 |
10 |
11 | ## Current Behavior
12 |
13 |
14 | ## Steps to Reproduce the Problem
15 |
16 |
17 |
18 | 1.
19 | 2.
20 | 3.
21 |
22 | ## Specifications
23 |
24 | - Solara Version:
25 | - Platform:
26 | - Affected Python Versions:
27 |
--------------------------------------------------------------------------------
/.github/workflows/pycafe.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: PyCafe Playground Link
3 | on:
4 | workflow_run:
5 | workflows: [Test]
6 | types:
7 | - completed
8 |
9 | jobs:
10 | create-status:
11 | if: github.event.repository.fork == false
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v4
16 | - name: Create PyCafe status link
17 | run: |
18 | pip install PyGithub
19 | python .github/pycafe-create-status.py ${{ github.event.workflow_run.head_sha }} ${{ github.event.workflow_run.id }}
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/sidebar.py:
--------------------------------------------------------------------------------
1 | """
2 | # Sidebar
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.utils import apidoc
9 |
10 |
11 | @solara.component
12 | def Page():
13 | return solara.Markdown(
14 | """
15 |
16 | The sidebar can only be shown in embedded mode on this page.
17 | Visit the [Scatter app demo](/apps/scatter) to see an example of a full sidebar used in Soalra server.
18 |
19 | [](/apps/scatter)
20 | """
21 | )
22 |
23 |
24 | __doc__ += apidoc(solara.Sidebar.f) # type: ignore
25 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_previous.py:
--------------------------------------------------------------------------------
1 | """
2 | # use_previous
3 |
4 | ```python
5 | def use_previous(value: T) -> T:
6 | ...
7 | ```
8 |
9 | Returns the value from a previous render phase, or the current value on the first render.
10 |
11 |
12 | """
13 |
14 | import solara
15 |
16 | title = "use_previous"
17 |
18 |
19 | @solara.component
20 | def Page():
21 | value, set_value = solara.use_state(4)
22 | value_previous = solara.use_previous(value)
23 | solara.IntSlider("value", value=value, on_value=set_value)
24 | solara.Markdown(
25 | f"""
26 | **Current**: `{value}`
27 |
28 | **Previous**: `{value_previous}`
29 | """
30 | )
31 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Understanding Solara's functionality
3 | description: Solara builds on existing technologies. If you are new to Solara or some of the underlying technologies, you may feel lost at times.
4 | These 'understanding' guides are meant to help you understand topics at a deeper level and how they connect to Solara.
5 | ---
6 |
7 | # Introduction
8 |
9 | Solara builds on existing technologies. If you are new to Solara or some of the underlying technologies, you may feel lost at times.
10 | These 'understanding' guides are meant to help you understand topics at a deeper level and how they connect to Solara.
11 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/basics/sine.py:
--------------------------------------------------------------------------------
1 | """# Interactive sine wave
2 |
3 |
4 | This example shows how to have two slider control a visualization.
5 |
6 | """
7 |
8 | import numpy as np
9 | import plotly.express as px
10 |
11 | import solara
12 |
13 | x = np.linspace(0, 2, 100)
14 |
15 | title = "Interactive sine wave"
16 | freq = solara.reactive(2.0)
17 | phase = solara.reactive(0.1)
18 |
19 |
20 | @solara.component
21 | def Page():
22 | y = np.sin(x * freq.value + phase.value)
23 |
24 | solara.FloatSlider("Frequency", value=freq, min=0, max=10)
25 | solara.FloatSlider("Phase", value=phase, min=0, max=np.pi, step=0.1)
26 |
27 | fig = px.line(x=x, y=y)
28 | solara.FigurePlotly(fig)
29 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/lab/tab.py:
--------------------------------------------------------------------------------
1 | """
2 | # Tab
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.utils import apidoc
9 |
10 | disabled = solara.reactive(False)
11 | icon = solara.reactive(True)
12 |
13 |
14 | @solara.component
15 | def Page():
16 | solara.Checkbox(label="Disable Tab 2", value=disabled)
17 | solara.Checkbox(label="Show icon", value=icon)
18 | with solara.lab.Tabs():
19 | with solara.lab.Tab("Tab 1"):
20 | solara.Markdown("Hello")
21 | with solara.lab.Tab("Tab 2", disabled=disabled.value, icon_name="mdi-home" if icon.value else None):
22 | solara.Markdown("World")
23 |
24 |
25 | __doc__ += apidoc(solara.lab.Tab.f) # type: ignore
26 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/multipage/03-some-markdown.md:
--------------------------------------------------------------------------------
1 | # This title is not used
2 |
3 | We use the filename for the title.
4 |
5 | ```python
6 | this = "renders to highlighted Python code
7 | ```
8 |
9 |
10 | ## Embed a solara example
11 |
12 | This renders highlighted Python code, and shows app.
13 | ```solara
14 | import solara
15 |
16 |
17 | @solara.component
18 | def ClickButton():
19 | clicks, set_clicks = solara.use_state(0)
20 |
21 | color = "green"
22 | if clicks >= 5:
23 | color = "red"
24 |
25 | def on_click():
26 | set_clicks(clicks + 1)
27 | print("clicks", clicks)
28 |
29 | return solara.Button(label=f"Clicked: {clicks}", on_click=on_click, color=color)
30 |
31 |
32 | app = ClickButton()
33 |
--------------------------------------------------------------------------------
/solara/website/public/social/discord.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/docs/docs_howto_no_browser_testing_test.py:
--------------------------------------------------------------------------------
1 | import solara
2 | import ipyvuetify as v
3 |
4 |
5 | def test_docs_no_browser_simple():
6 | clicks = solara.reactive(0)
7 |
8 | @solara.component
9 | def ClickButton():
10 | def increment():
11 | clicks.value += 1
12 |
13 | solara.Button(label=f"Clicked: {clicks}", on_click=increment)
14 |
15 | # rc is short for render context
16 | box, rc = solara.render(ClickButton(), handle_error=False)
17 | button = box.children[0]
18 | assert isinstance(button, v.Btn)
19 | assert button.children[0] == "Clicked: 0"
20 | # trigger the click event handler without a browser
21 | button.click()
22 | assert clicks.value == 1
23 | assert button.children[0] == "Clicked: 1"
24 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager8/patches/@jupyterlab+outputarea+3.6.4.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/@jupyterlab/outputarea/lib/widget.js b/node_modules/@jupyterlab/outputarea/lib/widget.js
2 | index b3fb52a..8497376 100644
3 | --- a/node_modules/@jupyterlab/outputarea/lib/widget.js
4 | +++ b/node_modules/@jupyterlab/outputarea/lib/widget.js
5 | @@ -1,6 +1,6 @@
6 | // Copyright (c) Jupyter Development Team.
7 | // Distributed under the terms of the Modified BSD License.
8 | -import { WidgetTracker } from '@jupyterlab/apputils';
9 | +import { WidgetTracker } from '@jupyterlab/apputils/lib/widgettracker';
10 | import { KernelMessage } from '@jupyterlab/services';
11 | import { PromiseDelegate, UUID } from '@lumino/coreutils';
12 | import { AttachedProperty } from '@lumino/properties';
13 |
--------------------------------------------------------------------------------
/solara/components/head.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | import reacton
4 | import solara
5 |
6 |
7 | @reacton.component
8 | def Head(children: List[reacton.core.Element] = []):
9 | """A component that manager the "head" tag of the page to avoid duplicate tags, such as titles.
10 |
11 | Currently only supports the [title](/documentation/components/page/title) tag as child, e.g.:
12 |
13 | ```python
14 | import solara
15 |
16 | @solara.component
17 | def Page():
18 | with solara.VBox() as main:
19 | MyAwesomeComponent()
20 | with solara.Head():
21 | solara.Title("My page title")
22 | return main
23 |
24 | ```
25 |
26 | """
27 | return solara.Div(children=children, style="display; none")
28 |
--------------------------------------------------------------------------------
/solara/website/pages/showcase/planeto_tessa.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | with solara.Link("/showcase"):
7 | solara.Text("« Back to Showcases")
8 | with solara.ColumnsResponsive(12, medium=6):
9 | solara.Markdown(
10 | """
11 | # TESSA by Planeto
12 |
13 | [Planeto](https://planeto-energy.ch/) developed a tool called TESSA for district heating & cooling planning.
14 |
15 | TESSA was prototyped in the Jupyter notebook using ipywidgets. Using solara, they are able to bring TESSA into production using the
16 | same technology stack.
17 | """
18 | )
19 | solara.Image("https://dxhl76zpt6fap.cloudfront.net/public/showcase/tessa/thumbnail.png", width="100%", classes=["pt-12"])
20 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### All Submissions:
2 |
3 |
4 |
5 | * [ ] I installed `pre-commit` prior to committing my changes (see [development setup docs](https://solara.dev/documentation/advanced/development/setup#contributing)).
6 | * [ ] My commit messages conform to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).
7 | * [ ] My PR title conforms to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).
8 | * [ ] I linked to any relevant issues.
9 |
10 | ### Changes to / New Features:
11 |
12 | * [ ] I included docs for (the changes to) my feature.
13 | * [ ] I wrote tests for (the changes to) my feature.
14 |
15 | ### Description of changes
16 |
17 |
18 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/advanced/link.py:
--------------------------------------------------------------------------------
1 | """# Link"""
2 |
3 | import solara
4 | from solara.website.utils import apidoc
5 |
6 | routes = [
7 | solara.Route(path="/"),
8 | solara.Route(path="kiwi"),
9 | solara.Route(path="banana"),
10 | solara.Route(path="apple"),
11 | ]
12 |
13 |
14 | @solara.component
15 | def Page():
16 | route_current, routes = solara.use_route()
17 | solara.Info("Note the address bar in the browser. It should change to the path of the link.")
18 | with solara.Row():
19 | for route in routes:
20 | with solara.Link(route):
21 | current = route_current is route
22 | solara.Button(f"Go to {route.path}", color="red" if current else None)
23 |
24 |
25 | __doc__ += apidoc(solara.Link.f) # type: ignore
26 |
--------------------------------------------------------------------------------
/solara/server/templates/loader-plain.html:
--------------------------------------------------------------------------------
1 | {% raw -%}
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 | {{ loading_text }}
11 |
12 |
13 |
14 |
15 |
16 | A widget with mount-id="solara-main" should go here
17 |
18 |
19 |
20 | {% endraw -%}
21 |
--------------------------------------------------------------------------------
/tests/unit/express_test.py:
--------------------------------------------------------------------------------
1 | import plotly.express as px
2 |
3 | import solara
4 | import solara.express
5 |
6 | df = px.data.iris()
7 |
8 |
9 | def test_cross_filter():
10 | filter, set_filter = None, None
11 |
12 | @solara.component
13 | def Test():
14 | nonlocal filter, set_filter
15 | solara.provide_cross_filter()
16 | filter, set_filter = solara.use_cross_filter(id(df))
17 |
18 | with solara.HBox() as main:
19 | solara.express.scatter(df, x="sepal_length", y="sepal_width")
20 | solara.express.scatter(df, x="sepal_length", y="sepal_width", size=[10 for ea in df.sepal_length], log_x=True)
21 | return main
22 |
23 | box, rc = solara.render(Test(), handle_error=False)
24 | assert set_filter is not None
25 | set_filter(df["sepal_length"] > 5)
26 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/notebookapp_element.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import solara\n",
10 | "\n",
11 | "app = solara.Button(\"Click me\")"
12 | ]
13 | }
14 | ],
15 | "metadata": {
16 | "kernelspec": {
17 | "display_name": "dev",
18 | "language": "python",
19 | "name": "python3"
20 | },
21 | "language_info": {
22 | "name": "python",
23 | "version": "3.9.10 | packaged by conda-forge | (main, Feb 1 2022, 21:27:43) \n[Clang 11.1.0 ]"
24 | },
25 | "orig_nbformat": 4,
26 | "vscode": {
27 | "interpreter": {
28 | "hash": "3f54047370d637df4a365f9bae65e296d7b1c0737aca7baed81d825616d991e7"
29 | }
30 | }
31 | },
32 | "nbformat": 4,
33 | "nbformat_minor": 2
34 | }
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "Feature Request \U0001F680"
3 | about: Suggest an improvement!
4 | title: 'Feature Request:'
5 | labels: 'enhancement'
6 | assignees: ''
7 | ---
8 |
9 | ## Feature Request
10 |
11 | - [ ] The requested feature would break current behaviour
12 | - [ ] I would be interested in opening a PR for this feature
13 |
14 | ### What problem would this feature solve? Please describe.
15 | A clear and concise description of what the problem is. Ex. I have an issue when [...]
16 |
17 | ### Describe the solution you'd like
18 | A clear and concise description of the feature, and how it would solve the problem. Add any considered drawbacks.
19 |
20 | ### Documentation, Migration Strategy
21 | If you can, explain how users will be able to use this and possibly write a draft version for related documentation.
22 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/search/search.py:
--------------------------------------------------------------------------------
1 | import ipyvue
2 | import solara
3 | import traitlets
4 |
5 |
6 | class SearchWidget(ipyvue.VueTemplate):
7 | template_file = (__file__, "search.vue")
8 | forceUpdateList = traitlets.Int(0).tag(sync=True)
9 | item = traitlets.Any().tag(sync=True)
10 | query = traitlets.Unicode("", allow_none=True).tag(sync=True)
11 | search_open = traitlets.Bool(False).tag(sync=True)
12 | failed = traitlets.Bool(False).tag(sync=True)
13 | cdn = traitlets.Unicode(None, allow_none=True).tag(sync=True)
14 |
15 | @traitlets.default("cdn")
16 | def _cdn(self):
17 | import solara.settings
18 |
19 | if not solara.settings.assets.proxy:
20 | return solara.settings.assets.cdn
21 |
22 |
23 | @solara.component
24 | def Search():
25 | return SearchWidget.element()
26 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager8/patches/@jupyterlab+rendermime+3.6.4.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/@jupyterlab/rendermime/lib/registry.js b/node_modules/@jupyterlab/rendermime/lib/registry.js
2 | index 2ee4d74..acf0615 100644
3 | --- a/node_modules/@jupyterlab/rendermime/lib/registry.js
4 | +++ b/node_modules/@jupyterlab/rendermime/lib/registry.js
5 | @@ -2,7 +2,7 @@
6 | | Copyright (c) Jupyter Development Team.
7 | | Distributed under the terms of the Modified BSD License.
8 | |----------------------------------------------------------------------------*/
9 | -import { defaultSanitizer } from '@jupyterlab/apputils';
10 | +import { defaultSanitizer } from '@jupyterlab/apputils/lib/sanitizer';
11 | import { PathExt, URLExt } from '@jupyterlab/coreutils';
12 | import { nullTranslator } from '@jupyterlab/translation';
13 | import { MimeModel } from './mimemodel';
14 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/notebookapp_widget.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import ipywidgets\n",
10 | "\n",
11 | "app = ipywidgets.Button(description=\"Click me\")"
12 | ]
13 | }
14 | ],
15 | "metadata": {
16 | "kernelspec": {
17 | "display_name": "dev",
18 | "language": "python",
19 | "name": "python3"
20 | },
21 | "language_info": {
22 | "name": "python",
23 | "version": "3.9.10 | packaged by conda-forge | (main, Feb 1 2022, 21:27:43) \n[Clang 11.1.0 ]"
24 | },
25 | "orig_nbformat": 4,
26 | "vscode": {
27 | "interpreter": {
28 | "hash": "3f54047370d637df4a365f9bae65e296d7b1c0737aca7baed81d825616d991e7"
29 | }
30 | }
31 | },
32 | "nbformat": 4,
33 | "nbformat_minor": 2
34 | }
35 |
--------------------------------------------------------------------------------
/packages/solara-assets/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling==1.26.3"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "solara-assets"
7 | authors = [{name = "Maarten A. Breddels", email = "maartenbreddels@gmail.com"}]
8 | license = {file = "LICENSE"}
9 | requires-python = ">=3.8"
10 |
11 | classifiers = ["License :: OSI Approved :: MIT License"]
12 | dynamic = ["version", "description"]
13 | dependencies = [
14 | "solara",
15 | ]
16 |
17 | [project.urls]
18 | Home = "https://www.github.com/widgetti/solara"
19 |
20 | [tool.hatch.version]
21 | path = "solara_assets/__init__.py"
22 |
23 | # Used to call hatch_build.py
24 | [tool.hatch.build.hooks.custom]
25 |
26 | [tool.hatch.build.targets.wheel.shared-data]
27 | "cdn" = "share/solara/cdn"
28 |
29 | [tool.black]
30 | line-length = 160
31 |
32 | [tool.isort]
33 | profile = "black"
34 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/cache/multi_level.py:
--------------------------------------------------------------------------------
1 | from typing import ChainMap
2 |
3 |
4 | class MultiLevel(ChainMap):
5 | """Use multiple caches, where we assume the first is the fastest"""
6 |
7 | def __getitem__(self, key):
8 | for level, mapping in enumerate(self.maps):
9 | try:
10 | value = mapping[key]
11 | # write back to lower levels
12 | for i in range(level):
13 | self.maps[i][key] = value
14 | return value
15 | except KeyError:
16 | pass
17 | return self.__missing__(key)
18 |
19 | def __setitem__(self, key, value):
20 | for cache in self.maps:
21 | cache[key] = value
22 |
23 | def __delitem__(self, key):
24 | for cache in self.maps:
25 | del cache[key]
26 |
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import contextlib
2 | import sys
3 |
4 | import pytest
5 | from dotenv import load_dotenv
6 |
7 | import solara.server.reload
8 | import solara.server.settings
9 |
10 | load_dotenv() # take environment variables from .env. should be in os.environ for the whole test
11 |
12 | solara.server.settings.telemetry.mixpanel_token = "adbf863d17cba80db608788e7fce9843"
13 | solara.server.settings.main.mode = "development"
14 | solara.server.reload.reloader.watcher = solara.server.reload.WatcherType([], solara.server.reload.reloader._on_change)
15 |
16 |
17 | @pytest.fixture
18 | def extra_include_path():
19 | @contextlib.contextmanager
20 | def extra_include_path(path):
21 | sys.path.insert(0, str(path))
22 | try:
23 | yield
24 | finally:
25 | sys.path[:] = sys.path[1:]
26 |
27 | return extra_include_path
28 |
--------------------------------------------------------------------------------
/tests/unit/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | import solara.server.app
4 | import solara.server.kernel_context
5 | from solara.server import kernel
6 | from solara.server.kernel_context import VirtualKernelContext
7 |
8 |
9 | @pytest.fixture(autouse=True)
10 | def kernel_context():
11 | kernel_shared = kernel.Kernel()
12 | context = VirtualKernelContext(id="1", kernel=kernel_shared, session_id="session-1")
13 | try:
14 | with context:
15 | yield context
16 | finally:
17 | with context:
18 | context.close()
19 |
20 |
21 | @pytest.fixture()
22 | def no_kernel_context(kernel_context):
23 | context = solara.server.kernel_context.get_current_context()
24 | solara.server.kernel_context.set_current_context(None)
25 | try:
26 | yield
27 | finally:
28 | solara.server.kernel_context.set_current_context(context)
29 |
--------------------------------------------------------------------------------
/solara/comm.py:
--------------------------------------------------------------------------------
1 | import traceback
2 | from typing import Any, Dict
3 |
4 | try:
5 | import comm
6 | except ImportError:
7 | comm = None # type: ignore
8 |
9 | orphan_comm_stacks: Dict[Any, str] = {}
10 |
11 |
12 | if comm is not None and comm.create_comm is comm._create_comm:
13 | # only when nobody else has monkey-patched comm.create_comm
14 | class DummyComm(comm.base_comm.BaseComm): # type: ignore
15 | def publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):
16 | pass
17 |
18 | def create_dummy_comm(*args, **kwargs):
19 | comm = DummyComm(*args, **kwargs)
20 | stacktrace = "".join(traceback.format_stack())
21 | orphan_comm_stacks[comm] = stacktrace
22 | return comm
23 |
24 | comm.create_comm = create_dummy_comm
25 | else:
26 |
27 | class DummyComm: # type: ignore
28 | pass
29 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Understanding different parts of Solara
3 | description: Solara is made of two main components, the bulk of the Solara package with UI elements that can be used together with Jupyter, and Solara server, which
4 | allows for these UI elements to be used in standalone apps and dashboards
5 | ---
6 | # Solara
7 |
8 | Solara combines [ipywidgets](./ipywidgets), [reacton](./reacton) and puts it into a opinionated framework to make web apps with a focus on data (data apps for short).
9 |
10 | Solara consists of two main parts
11 |
12 | ## Solara-ui
13 |
14 | A set of opinionated react components and hooks that allow you to build web apps and data apps faster.
15 |
16 | ## Solara-server
17 |
18 | A web framework for deploying web apps or data apps in production. Opinionated about pages and routing.
19 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/input/slider.py:
--------------------------------------------------------------------------------
1 | """
2 | # Sliders
3 |
4 | To support proper typechecks, we have multiple slider (all wrapping the ipyvuetify sliders).
5 |
6 |
7 | """
8 |
9 | import solara
10 | from solara.website.components import NoPage
11 | from solara.website.utils import apidoc
12 |
13 | Page = NoPage
14 |
15 | __doc__ += "# SliderInt"
16 | __doc__ += apidoc(solara.SliderInt.f) # type: ignore
17 | __doc__ += "# SliderRangeInt"
18 | __doc__ += apidoc(solara.SliderRangeInt.f) # type: ignore
19 |
20 | __doc__ += "# SliderFloat"
21 | __doc__ += apidoc(solara.SliderFloat.f) # type: ignore
22 | __doc__ += "# SliderRangeFloat"
23 | __doc__ += apidoc(solara.SliderRangeFloat.f) # type: ignore
24 |
25 | __doc__ += "# SliderValue"
26 | __doc__ += apidoc(solara.SliderValue.f) # type: ignore
27 |
28 | __doc__ += "# SliderDate"
29 | __doc__ += apidoc(solara.SliderDate.f) # type: ignore
30 |
--------------------------------------------------------------------------------
/tests/unit/shell_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import Mock
2 |
3 | import IPython.display
4 |
5 | from solara.server import kernel, kernel_context
6 |
7 |
8 | def test_shell(no_kernel_context):
9 | ws1 = Mock()
10 | ws2 = Mock()
11 | kernel1 = kernel.Kernel()
12 | kernel2 = kernel.Kernel()
13 | kernel1.session.websockets.add(ws1)
14 | kernel2.session.websockets.add(ws2)
15 | context1 = kernel_context.VirtualKernelContext(id="1", kernel=kernel1, session_id="session-1")
16 | context2 = kernel_context.VirtualKernelContext(id="2", kernel=kernel2, session_id="session-2")
17 |
18 | with context1:
19 | IPython.display.display("test1")
20 | assert ws1.send.call_count == 1
21 | assert ws2.send.call_count == 0
22 | with context2:
23 | IPython.display.display("test1")
24 | assert ws1.send.call_count == 1
25 | assert ws2.send.call_count == 1
26 |
--------------------------------------------------------------------------------
/solara/website/public/success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 | Used to detect failed Jupyter and Solara installations.
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/unit/chat_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import MagicMock
2 |
3 | import ipyvuetify as vw
4 |
5 | import solara
6 |
7 |
8 | def test_chatinput():
9 | send_callback = MagicMock()
10 | el = solara.lab.ChatInput(send_callback=send_callback)
11 | box, rc = solara.render(el, handle_error=False)
12 | input = rc.find(vw.TextField)
13 | button = rc.find(vw.Btn)
14 |
15 | input.widget.v_model = "hello"
16 | assert send_callback.call_count == 0
17 | input.widget.fire_event("keyup.enter")
18 | assert send_callback.call_count == 1
19 | assert send_callback.call_args[0][0] == "hello"
20 | assert input.widget.v_model == ""
21 | input.widget.v_model = "hello"
22 | assert send_callback.call_count == 1
23 | button.widget.fire_event("click")
24 | assert send_callback.call_count == 2
25 | assert send_callback.call_args[0][0] == "hello"
26 | assert input.widget.v_model == ""
27 |
--------------------------------------------------------------------------------
/tests/unit/solara_test_apps/notebookapp_component.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import solara\n",
10 | "\n",
11 | "\n",
12 | "@solara.component\n",
13 | "def Page():\n",
14 | " return solara.Button(\"Click me\")"
15 | ]
16 | }
17 | ],
18 | "metadata": {
19 | "kernelspec": {
20 | "display_name": "dev",
21 | "language": "python",
22 | "name": "python3"
23 | },
24 | "language_info": {
25 | "name": "python",
26 | "version": "3.9.10 | packaged by conda-forge | (main, Feb 1 2022, 21:27:43) \n[Clang 11.1.0 ]"
27 | },
28 | "orig_nbformat": 4,
29 | "vscode": {
30 | "interpreter": {
31 | "hash": "3f54047370d637df4a365f9bae65e296d7b1c0737aca7baed81d825616d991e7"
32 | }
33 | }
34 | },
35 | "nbformat": 4,
36 | "nbformat_minor": 2
37 | }
38 |
--------------------------------------------------------------------------------
/solara/website/pages/docutils.py:
--------------------------------------------------------------------------------
1 | import inspect
2 |
3 | import solara
4 | from solara.alias import rw
5 | from solara.components import Markdown
6 |
7 |
8 | @solara.component
9 | def Sample(code, component):
10 | locals = globals().copy()
11 | exec(code, locals)
12 | c = locals[component]
13 | with rw.VBox() as main:
14 | Markdown(
15 | f"""
16 | ```python
17 | {code}
18 | ```
19 | """
20 | )
21 | c()
22 | return main
23 |
24 |
25 | @solara.component
26 | def IncludeComponent(component, pre="", highlight=[], **kwargs):
27 | code = inspect.getsource(component.f)
28 | with rw.VBox(layout={"padding": "20px", "max_width": "1024px", "border": "1px #333 solid"}) as main:
29 | Markdown(
30 | f"""
31 | ```python
32 | {pre}{code}
33 | ```
34 | """,
35 | highlight=highlight,
36 | )
37 | component(**kwargs)
38 | return main
39 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/cache/redis.py:
--------------------------------------------------------------------------------
1 | from typing import Any, Callable, Optional
2 |
3 | import redis
4 | import solara.settings
5 |
6 | from solara_enterprise.cache.base import Base, make_key
7 |
8 |
9 | class Redis(Base):
10 | """Wraps a client such that the values are pickled/unpickled"""
11 |
12 | def __init__(
13 | self, client: Optional[redis.Redis] = None, clear=solara.settings.cache.clear, prefix=b"solara:cache:", make_key: Callable[[Any], bytes] = make_key
14 | ):
15 | self.client = client or redis.Redis()
16 | super().__init__(self.client, prefix=prefix, clear=clear, make_key=make_key)
17 |
18 | def clear(self):
19 | with self.client.lock(b"lock:" + self.prefix):
20 | keys = self.keys()
21 | for key in keys:
22 | del self[key]
23 |
24 | def keys(self):
25 | return self.client.keys(self.prefix + b"*")
26 |
--------------------------------------------------------------------------------
/tests/integration/async_test.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from pathlib import Path
3 |
4 | import playwright.sync_api
5 |
6 | import solara
7 | import solara.server.starlette
8 |
9 | HERE = Path(__file__).parent
10 |
11 |
12 | @solara.component
13 | def Page():
14 | def run_async():
15 | async def some_task():
16 | await asyncio.sleep(0.01)
17 | label.value = "asyncio run"
18 |
19 | asyncio.create_task(some_task())
20 |
21 | label = solara.use_reactive("initial")
22 | solara.Button(label.value, on_click=run_async)
23 |
24 |
25 | def test_async_callback(page_session: playwright.sync_api.Page, solara_app, extra_include_path, solara_server):
26 | with extra_include_path(HERE), solara_app("async_test"):
27 | page_session.goto(solara_server.base_url + "/")
28 | page_session.locator("text=initial").click()
29 | page_session.locator("text=asyncio run").wait_for()
30 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/page/title.py:
--------------------------------------------------------------------------------
1 | """# Title"""
2 |
3 | from typing import Optional, cast
4 |
5 | import solara
6 | from solara.website.utils import apidoc
7 |
8 |
9 | @solara.component
10 | def Page():
11 | title = solara.use_reactive(cast(Optional[str], "Custom title!"))
12 |
13 | solara.ToggleButtonsSingle(value=title, values=[None, "Custom title!", "Different custom title"])
14 |
15 | if title is not None:
16 | # if the title is not set in a child component, the parent's title will be used
17 | with solara.Head():
18 | # title should always occur inside a Head component
19 | solara.Title(title)
20 | solara.Info(f"Your browser tab title should say {title}", classes=["mt-4"])
21 | else:
22 | solara.Warning("If no title is set, the parent title is used.", classes=["mt-4"])
23 |
24 |
25 | __doc__ += apidoc(solara.Title.f) # type: ignore
26 |
--------------------------------------------------------------------------------
/solara/template/portal/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v2.3.0
4 | hooks:
5 | - id: check-yaml
6 | - id: end-of-file-fixer
7 | - id: trailing-whitespace
8 | - repo: https://github.com/psf/black
9 | rev: 22.3.0
10 | hooks:
11 | - id: black
12 | language_version: python3.8
13 | - repo: https://gitlab.com/pycqa/flake8
14 | rev: 4.0.1
15 | hooks:
16 | - id: flake8
17 | - repo: https://github.com/PyCQA/isort
18 | rev: 5.10.1
19 | hooks:
20 | - id: isort
21 | files: \.py$
22 | args: [--profile=black]
23 | - repo: https://github.com/pre-commit/mirrors-mypy
24 | rev: "v0.942" # Use the sha / tag you want to point at
25 | hooks:
26 | - id: mypy
27 | args: [--no-strict-optional, --ignore-missing-imports]
28 | additional_dependencies: [types-requests, types-markdown]
29 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/viz/matplotlib.py:
--------------------------------------------------------------------------------
1 | """# Matplotlib"""
2 |
3 | import numpy as np
4 | from matplotlib.figure import Figure
5 |
6 | import solara
7 | from solara.website.utils import apidoc
8 |
9 | x = np.linspace(0, 2, 100)
10 |
11 |
12 | @solara.component
13 | def Page():
14 | freq, set_freq = solara.use_state(2.0)
15 | phase, set_phase = solara.use_state(0.1)
16 | y = np.sin(x * freq + phase)
17 |
18 | fig = Figure()
19 | ax = fig.subplots()
20 | ax.plot(x, y)
21 | ax.set_ylim(-1.2, 1.2)
22 |
23 | with solara.VBox() as main:
24 | solara.FloatSlider("Frequency", value=freq, on_value=set_freq, min=0, max=10)
25 | solara.FloatSlider("Phase", value=phase, on_value=set_phase, min=0, max=np.pi, step=0.1)
26 | solara.FigureMatplotlib(fig, dependencies=[freq, phase])
27 | return main
28 |
29 |
30 | __doc__ += apidoc(solara.FigureMatplotlib.f) # type: ignore
31 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_memo.md:
--------------------------------------------------------------------------------
1 | # use_memo
2 |
3 | ```python
4 | def use_memo(
5 | f: Any,
6 | dependencies: Any | None = None,
7 | debug_name: str = None
8 | ) -> Any:
9 | ...
10 | ```
11 |
12 | `use_memo` stores ([memoize](https://en.wikipedia.org/wiki/Memoization)) the function return on first render, and then excludes it from being re-executed, except when one of the `dependencies` changes. `dependencies` can take the value `None`, in which case dependencies are automatically obtained from nonlocal variables. If an empty list is passed as `dependencies` instead, the function is only executed once over the entire lifetime of the component.
13 |
14 | Not to be confused with [memorize](https://solara.dev/documentation/api/utilities/memoize) which can cache multiple return values and which can be used outside of component.
15 |
16 | See also the [Reacton docs](https://reacton.solara.dev/en/latest/api/#use_memo).
17 |
--------------------------------------------------------------------------------
/pyinstaller/minimal/solara-app-entrypoint.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | # make sure pyinstaller picks it up
4 | import sample_app # noqa: F401
5 | import os
6 |
7 |
8 | @click.command()
9 | @click.option(
10 | "--port",
11 | default=int(os.environ.get("PORT", 0)),
12 | help="Port to run the server on, 0 for a random free port",
13 | )
14 | @click.option(
15 | "--webview",
16 | default=False,
17 | is_flag=True,
18 | help="Run the app in a webview window",
19 | )
20 | def run(port: int, webview: bool = False):
21 | if "SOLARA_APP" not in os.environ:
22 | os.environ["SOLARA_APP"] = "sample_app"
23 |
24 | import solara.server.starlette
25 |
26 | server = solara.server.starlette.ServerStarlette(host="localhost", port=port)
27 | print(f"Starting server on {server.base_url}")
28 | server.serve_threaded()
29 | server.wait_until_serving()
30 | server.join()
31 |
32 |
33 | if __name__ == "__main__":
34 | run()
35 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/pages/article/__init__.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | import solara
4 |
5 | from ... import data
6 | from ...components.article import Overview
7 |
8 |
9 | @solara.component
10 | def Page(name: Optional[str] = None, page: int = 0, page_size=100):
11 | if name is None:
12 | with solara.Column() as main:
13 | solara.Title("Solara demo » Articles")
14 | Overview()
15 | return main
16 | if name not in data.articles:
17 | return solara.Error(f"No such article: {name!r}")
18 | article = data.articles[name]
19 | with solara.ColumnsResponsive(12) as main:
20 | solara.Title("Solara demo » Article » " + article.title)
21 | with solara.Link("/article"):
22 | solara.Text("« Back to overview")
23 | with solara.Card():
24 | pre = f"# {article.title}\n\n"
25 | solara.Markdown(pre + article.markdown)
26 | return main
27 |
--------------------------------------------------------------------------------
/solara/website/public/social/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/unit/telemetry_tests.py:
--------------------------------------------------------------------------------
1 | import json
2 | import unittest.mock
3 | from urllib.parse import unquote
4 |
5 | import requests
6 |
7 | import solara.server.telemetry
8 |
9 |
10 | def test_telemetry_basic(mocker):
11 | post: unittest.mock.MagicMock = mocker.spy(requests, "post")
12 | solara.server.telemetry.track("test_event", {"test_prop": "test_value"})
13 | post.assert_called_once()
14 | data = json.loads(unquote(post.call_args[1]["data"])[5:])[0] # type: ignore
15 | assert data["event"] == "test_event"
16 |
17 |
18 | def test_telemetry_server_start_stopc(mocker):
19 | post: unittest.mock.MagicMock = mocker.spy(requests, "post")
20 | solara.server.telemetry.server_start()
21 | solara.server.telemetry.server_stop()
22 | post.assert_called()
23 | data = json.loads(unquote(post.call_args[1]["data"])[5:])[0] # type: ignore
24 | assert data["event"] == "Solara server stop"
25 | assert data["properties"]["duration_seconds"] > 0
26 |
--------------------------------------------------------------------------------
/solara/server/jupyter/cdn_handler.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import mimetypes
3 |
4 | import tornado.web
5 | from jupyter_server.base.handlers import JupyterHandler
6 |
7 | from solara.server import settings
8 | from solara.server.cdn_helper import get_data
9 |
10 | logger = logging.getLogger("Solara.cdn")
11 |
12 |
13 | class CdnHandler(JupyterHandler):
14 | def initialize(self, cache_directory=settings.assets.proxy_cache_dir):
15 | self.cache_directory = cache_directory
16 | logging.info("Using %r as cache directory", self.cache_directory)
17 |
18 | async def get(self, path=None):
19 | try:
20 | content = get_data(self.cache_directory, path)
21 | except Exception as e:
22 | logger.warning(e)
23 | raise tornado.web.HTTPError(500)
24 |
25 | mime = mimetypes.guess_type(path)
26 | if mime[0] is not None:
27 | self.set_header("Content-Type", mime[0])
28 | self.write(content)
29 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/solara_enterprise/cache/memory_size.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import pickle
3 | from typing import Any, Callable, MutableMapping
4 |
5 | import solara.settings
6 | import solara.util
7 | from cachetools import LRUCache
8 |
9 | from solara_enterprise.cache.base import Base, make_key
10 |
11 | logger = logging.getLogger("solara-enterprise.cache.memory")
12 |
13 |
14 | def sizeof(obj):
15 | size = len(pickle.dumps(obj))
16 | logger.debug("size of %s: %s", obj, size)
17 | return size
18 |
19 |
20 | class MemorySize(Base):
21 | def __init__(
22 | self,
23 | max_size=solara.settings.cache.memory_max_size,
24 | make_key: Callable[[Any], bytes] = make_key,
25 | sizeof: Callable[[Any], int] = sizeof,
26 | ):
27 | maxsize = solara.util.parse_size(max_size)
28 | _wrapper_dict: MutableMapping[bytes, bytes] = LRUCache(maxsize=maxsize, getsizeof=sizeof)
29 | super().__init__(_wrapper_dict, make_key=make_key)
30 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/components/data.py:
--------------------------------------------------------------------------------
1 | import reacton.ipyvuetify as rv
2 | import solara
3 |
4 | from ..data import dfs
5 |
6 |
7 | @solara.component
8 | def DataCard(name):
9 | df = dfs[name].df
10 | with rv.Card(max_width="400px") as main:
11 | with solara.Link(f"/tabular/{name}"):
12 | rv.Img(height="250", src=dfs[name].image_url)
13 | rv.CardTitle(children=[dfs[name].title])
14 | with rv.CardText():
15 | solara.Markdown(f"*{len(df):,} rows*")
16 | with solara.Link(f"/tabular/{name}"):
17 | solara.Button("Open table view", text=True, icon_name="mdi-table")
18 | return main
19 |
20 |
21 | @solara.component
22 | def Overview():
23 | with solara.ColumnsResponsive(12) as main:
24 | with solara.Card("Datasets"):
25 | with solara.ColumnsResponsive(12, small=6, large=4):
26 | for name in dfs:
27 | DataCard(name)
28 | return main
29 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/hooks/use_exception.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | title = "use_exception"
4 | set_fail = None
5 | clear = None
6 |
7 |
8 | @solara.component
9 | def UnstableComponent(number: int):
10 | if number == 3:
11 | raise Exception("I do not like 3")
12 | return solara.Text(f"You picked {number}")
13 |
14 |
15 | @solara.component
16 | def Page():
17 | value, set_value = solara.use_state(1)
18 | value_previous = solara.use_previous(value)
19 | exception, clear_exception = solara.use_exception()
20 | # print(exception)
21 | if exception:
22 |
23 | def reset():
24 | set_value(value_previous)
25 | clear_exception()
26 |
27 | solara.Text("Exception: " + str(exception))
28 | solara.Button(label="Go to previous state", on_click=reset)
29 | else:
30 | solara.IntSlider(value=value, min=0, max=10, on_value=set_value, label="Pick a number, except 3")
31 | UnstableComponent(value)
32 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/routing/route.py:
--------------------------------------------------------------------------------
1 | """# Route"""
2 |
3 | import solara
4 | from solara.website.utils import apidoc
5 |
6 | routes = [
7 | solara.Route(path="/"),
8 | solara.Route(path="kiwi"),
9 | solara.Route(path="banana"),
10 | solara.Route(path="apple"),
11 | ]
12 |
13 |
14 | @solara.component
15 | def Page():
16 | route_current, routes = solara.use_route()
17 |
18 | solara.Markdown("*Click on one of the links below to change the route and see the url in your browser change, and match the route.*")
19 | with solara.VBox():
20 | for route in routes:
21 | with solara.Link(route):
22 | current = route_current is route
23 | if current:
24 | solara.Success(f"You are at solara.Route(path={route.path!r})")
25 | else:
26 | solara.Info(f"Go to solara.Route(path={route.path!r})")
27 |
28 |
29 | __doc__ += apidoc(solara.Route, full=True) # type: ignore
30 |
--------------------------------------------------------------------------------
/solara/website/pages/apps/multipage/page1.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 | from . import SharedComponent
4 |
5 | github_url = solara.util.github_url(__file__)
6 |
7 |
8 | @solara.component
9 | def Sub():
10 | with solara.Card("Sub component", margin=0, classes=["my-2"]):
11 | solara.Markdown("This sub component is the best")
12 | with solara.Sidebar():
13 | with solara.Card("Sidebar of sub component", margin=0, elevation=0):
14 | solara.Markdown("*Markdown* **is** 👍")
15 | SharedComponent()
16 |
17 |
18 | @solara.component
19 | def Page():
20 | with solara.Sidebar():
21 | with solara.Card("Sidebar of page 1", margin=0, elevation=0):
22 | solara.Markdown("Hi there 👋!")
23 | solara.Button(label="View source", icon_name="mdi-github-circle", attributes={"href": github_url, "target": "_blank"}, text=True, outlined=True)
24 | with solara.Card("Page 1"):
25 | Sub()
26 | solara.Markdown("Page 1 is the best")
27 |
--------------------------------------------------------------------------------
/tests/unit/checkbox_test.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import MagicMock
2 |
3 | import ipyvuetify as vw
4 |
5 | import solara
6 |
7 |
8 | def test_checkbox():
9 | on_value = MagicMock()
10 | el = solara.Checkbox(label="label", value=True, on_value=on_value)
11 | box, rc = solara.render(el, handle_error=False)
12 | checkbox = rc.find(vw.Checkbox)
13 | checkbox.widget.v_model = False
14 | assert on_value.call_count == 1
15 | checkbox.widget.v_model = False
16 | assert on_value.call_count == 1
17 | rc.close()
18 |
19 |
20 | def test_checkbox_no_callback_on_managed():
21 | on_value = MagicMock()
22 | el = solara.Checkbox(label="label", value=True, on_value=on_value)
23 | box, rc = solara.render(el, handle_error=False)
24 | assert on_value.call_count == 0
25 |
26 | # changing the value externally should *not* call the callback
27 | el2 = solara.Checkbox(label="label", value=False, on_value=on_value)
28 | rc.render(el2)
29 | assert on_value.call_count == 0
30 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/components/article.py:
--------------------------------------------------------------------------------
1 | import reacton.ipyvuetify as rv
2 | import solara
3 |
4 | from ..data import articles
5 |
6 |
7 | @solara.component
8 | def ArticleCard(name):
9 | article = articles[name]
10 | with rv.Card(max_width="400px") as main:
11 | with solara.Link(f"/article/{name}"):
12 | rv.Img(height="250", src=article.image_url)
13 | rv.CardTitle(children=[article.title])
14 | with rv.CardText():
15 | solara.Markdown(article.description)
16 | with solara.Link(f"/article/{name}"):
17 | solara.Button("Read article", text=True, icon_name="mdi-book-open")
18 | return main
19 |
20 |
21 | @solara.component
22 | def Overview():
23 | with solara.ColumnsResponsive(12) as main:
24 | with solara.Card("Company articles"):
25 | with solara.ColumnsResponsive(12, small=6, large=4):
26 | for name in articles:
27 | ArticleCard(name)
28 | return main
29 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/viz/altair.py:
--------------------------------------------------------------------------------
1 | """# FigureAltair"""
2 |
3 | import altair as alt
4 | import pandas as pd
5 |
6 | import solara
7 | from solara.website.utils import apidoc
8 |
9 | title = "FigureAltair"
10 |
11 | df = pd.DataFrame({"a": ["A", "B", "C", "D", "E", "F", "G", "H", "I"], "b": [28, 55, 43, 91, 81, 53, 19, 87, 52]})
12 |
13 |
14 | @solara.component
15 | def Page():
16 | click_data, set_click_data = solara.use_state(None)
17 | hover_data, set_hover_data = solara.use_state(None)
18 |
19 | chart = alt.Chart(df).mark_bar().encode(x="a", y="b")
20 |
21 | with solara.Div() as main:
22 | solara.AltairChart(chart, on_click=set_click_data, on_hover=set_hover_data)
23 |
24 | solara.Markdown(
25 | f"""
26 | Click data:
27 |
28 | ```
29 | {click_data}
30 | ```
31 |
32 | Hover data:
33 | ```
34 | {hover_data}
35 | ```
36 | """
37 | )
38 |
39 | return main
40 |
41 |
42 | __doc__ += apidoc(solara.FigureAltair.f) # type: ignore
43 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/column.py:
--------------------------------------------------------------------------------
1 | """
2 | # Column
3 | """
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | gap_size = solara.reactive("12px")
10 | align = solara.reactive("stretch")
11 |
12 |
13 | @solara.component
14 | def Page():
15 | with solara.Card("Column demo") as main:
16 | with solara.Column():
17 | solara.Text("Align:")
18 | solara.ToggleButtonsSingle(align, values=["start", "center", "end", "stretch"])
19 | solara.Select(
20 | label="Gap size",
21 | values=["0px", "4px", "8px", "12px", "16px", "20px", "24px"],
22 | ).connect(gap_size)
23 | with solara.Column(gap=gap_size.value, align=align.value):
24 | colors = "green red orange brown yellow pink".split()
25 | for color in colors:
26 | solara.Button("Solara", color=color)
27 | return main
28 |
29 |
30 | __doc__ += apidoc(solara.Column.f) # type: ignore
31 |
--------------------------------------------------------------------------------
/solara/components/markdown_editor.py:
--------------------------------------------------------------------------------
1 | from typing import Callable
2 |
3 | import ipyvuetify
4 | import traitlets
5 |
6 | import solara
7 |
8 |
9 | class MarkdownEditorWidget(ipyvuetify.VuetifyTemplate):
10 | template_file = (__file__, "markdown_editor.vue")
11 |
12 | value = traitlets.Unicode("").tag(sync=True)
13 | height = traitlets.Unicode("180px").tag(sync=True)
14 | cdn = traitlets.Unicode(None, allow_none=True).tag(sync=True)
15 |
16 | @traitlets.default("cdn")
17 | def _cdn(self):
18 | import solara.settings
19 |
20 | if not solara.settings.assets.proxy:
21 | return solara.settings.assets.cdn
22 |
23 |
24 | @solara.component
25 | def MarkdownEditor(value: str = "", on_value: Callable[[str], None] = None):
26 | """WYSIWYG (visual) Markdown editor.
27 |
28 | ## Arguments
29 |
30 | * value: Markdown text
31 | * on_value: Callback function that is called when the text is changed
32 | """
33 | return MarkdownEditorWidget.element(value=value, on_value=on_value)
34 |
--------------------------------------------------------------------------------
/.bumpversion.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 1.56.0
3 | commit = True
4 | tag = True
5 | parse = (?P\d+)(\.(?P\d+))(\.(?P\d+))((?P.)(?P\d+))?
6 | serialize =
7 | {major}.{minor}.{patch}{release}{build}
8 | {major}.{minor}.{patch}
9 |
10 | [bumpversion:part:release]
11 | optional_value = g
12 | first_value = g
13 | values =
14 | a
15 | b
16 | g
17 |
18 | [bumpversion:file:.github/pycafe-create-status.py]
19 |
20 | [bumpversion:file:solara/__init__.py]
21 |
22 | [bumpversion:file:packages/solara-assets/solara_assets/__init__.py]
23 |
24 | [bumpversion:file:packages/solara-enterprise/solara_enterprise/__init__.py]
25 |
26 | [bumpversion:file:packages/solara-enterprise/pyproject.toml]
27 |
28 | [bumpversion:file:packages/solara-server/pyproject.toml]
29 |
30 | [bumpversion:file:packages/solara-meta/pyproject.toml]
31 |
32 | [bumpversion:file:packages/pytest-ipywidgets/pyproject.toml]
33 |
34 | [bumpversion:file:solara/server/static/solara_bootstrap.py]
35 |
36 | [bumpversion:file:release.md]
37 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/columns.py:
--------------------------------------------------------------------------------
1 | """
2 | # Columns
3 |
4 | """
5 |
6 | import solara
7 | import solara.lab
8 | from solara.website.utils import apidoc
9 |
10 | gutters = solara.reactive(True)
11 | gutters_dense = solara.reactive(True)
12 |
13 |
14 | @solara.component
15 | def Page():
16 | with solara.Columns([1, 2, 1], gutters=gutters.value, gutters_dense=gutters_dense.value) as main:
17 | with solara.Card("Left", margin=0):
18 | solara.Checkbox(label="Gutters").connect(gutters)
19 | solara.Checkbox(label="Dense gutters").connect(gutters_dense)
20 | with solara.Card("Middle", margin=0):
21 | solara.Markdown("This column has a relative width of 2, the columns to the left and right have a relative width of 1.")
22 | with solara.Card("Right", margin=0):
23 | solara.Markdown("This column has a relative width of 1, the columns to the left has a relative width of 2.")
24 | return main
25 |
26 |
27 | __doc__ += apidoc(solara.Columns.f) # type: ignore
28 |
--------------------------------------------------------------------------------
/packages/solara-widget-manager/src/index.ts:
--------------------------------------------------------------------------------
1 | /***************************************************************************
2 | * Copyright (c) 2018, Voilà contributors *
3 | * Copyright (c) 2018, QuantStack *
4 | * *
5 | * Distributed under the terms of the BSD 3-Clause License. *
6 | * *
7 | * The full license is in the file LICENSE, distributed with this software. *
8 | ****************************************************************************/
9 |
10 | import '../style/index.css';
11 |
12 | export {
13 | RenderMimeRegistry,
14 | standardRendererFactories
15 | } from '@jupyterlab/rendermime';
16 | export { connectKernel, shutdownKernel } from './kernel';
17 | export { WidgetManager } from './manager';
18 | export { KatexTypesetter, renderKatex } from './katex';
19 | export { extendedRendererFactories } from './rendermime';
20 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/layout/row.py:
--------------------------------------------------------------------------------
1 | """
2 | # Row
3 | """
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | gap_size = solara.reactive("12px")
10 | justify = solara.reactive("space-around")
11 |
12 |
13 | @solara.component
14 | def Page():
15 | with solara.Card("Row demo") as main:
16 | with solara.Column():
17 | solara.Text("Justify:")
18 | solara.ToggleButtonsSingle(justify, values=["start", "center", "end", "space-around", "space-between", "space-evenly"])
19 | solara.Select(
20 | label="Gap size",
21 | values=["0px", "4px", "8px", "12px", "16px", "20px", "24px"],
22 | ).connect(gap_size)
23 | with solara.Row(gap=gap_size.value, justify=justify.value):
24 | colors = "green red orange brown yellow pink".split()
25 | for color in colors:
26 | solara.Button(label="Solara", color=color)
27 | return main
28 |
29 |
30 | __doc__ += apidoc(solara.Row.f) # type: ignore
31 |
--------------------------------------------------------------------------------
/packages/solara-milkdown/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@widgetti/solara-milkdown",
3 | "version": "6.3.0",
4 | "description": "Milkdown bundle for use with Solara",
5 | "main": "dist/index.min.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "webpack"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "css-loader": "^2.1.1",
15 | "file-loader": "^3.0.1",
16 | "html-webpack-plugin": "^5.5.0",
17 | "style-loader": "^0.23.1",
18 | "webpack": "^5.73.0",
19 | "webpack-cli": "^4.10.0",
20 | "webpack-dev-server": "^4.9.3"
21 | },
22 | "dependencies": {
23 | "@babel/core": "^7.18.5",
24 | "@milkdown/core": "^6.3.0",
25 | "@milkdown/plugin-menu": "^6.3.0",
26 | "@milkdown/preset-commonmark": "^6.3.0",
27 | "@milkdown/prose": "^6.3.0",
28 | "@milkdown/theme-nord": "^6.3.0",
29 | "@milkdown/plugin-listener": "^6.3.0",
30 | "@milkdown/preset-gfm": "^6.3.0",
31 | "@milkdown/plugin-history": "^6.3.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/solara/components/select.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ ((item.count / count) * 100).toFixed(1) }}%
19 |
20 | {{ item.count }} of {{ count }} after filtering
21 | {{ item.count_max }} of {{ count }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/solara/components/title.vue:
--------------------------------------------------------------------------------
1 | {{ title }}
2 |
3 |
39 |
--------------------------------------------------------------------------------
/solara/template/portal/solara_portal/pages/tabular.py:
--------------------------------------------------------------------------------
1 | """This Page takes an extra argument, meaning that it can cache urls like /tabular/titanic
2 | and pass the last part of the url as argument to the Page component, so we can render content
3 | dynamically.
4 | """
5 |
6 | from typing import Optional
7 |
8 | import solara
9 |
10 | from .. import data
11 | from ..components import data as data_components
12 |
13 |
14 | @solara.component
15 | def Page(name: Optional[str] = None, page: int = 0, page_size=100):
16 | if name is None or name not in data.dfs:
17 | with solara.Column() as main:
18 | solara.Title("Solara demo » table view")
19 | data_components.Overview()
20 | return main
21 |
22 | df = data.dfs[name].df
23 | with solara.ColumnsResponsive(12) as main:
24 | with solara.Link("/tabular"):
25 | solara.Text("« Back to overview")
26 | solara.DataTable(df=df, page=page, items_per_page=page_size)
27 | with solara.Head():
28 | solara.Title(f"Solara demo » table view » {name}")
29 | return main
30 |
--------------------------------------------------------------------------------
/solara/website/utils.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | import textwrap
3 |
4 |
5 | def sig(f):
6 | lines = inspect.getsourcelines(f)[0]
7 | end = [k.endswith(":\n") for k in lines].index(True)
8 | lines = lines[: end + 1]
9 | return "".join(lines)
10 |
11 |
12 | def code(f):
13 | lines = inspect.getsourcelines(f)[0]
14 | def_end = [k.endswith(":\n") for k in lines].index(True)
15 | doc_lines = len(f.__doc__.split("\n"))
16 | lines = lines[: def_end + 1] + lines[def_end + 1 + doc_lines :]
17 |
18 | return "".join(lines)
19 |
20 |
21 | def apidoc(f, full=False):
22 | if not f.__doc__:
23 | return "no docstring"
24 |
25 | doclines = f.__doc__.split("\n")
26 | first = doclines[0].strip()
27 | rest = "\n".join(doclines[1:]) # .strip()
28 | if full:
29 | return f"""
30 | {first}
31 |
32 | ```python
33 | {code(f)}
34 | ...
35 | ```
36 |
37 |
38 | {textwrap.dedent(rest)}
39 | """
40 | else:
41 | return f"""
42 | {first}
43 |
44 | ```python
45 | {sig(f)}
46 | ...
47 | ```
48 |
49 |
50 | {textwrap.dedent(rest)}
51 | """
52 |
--------------------------------------------------------------------------------
/tests/integration/testapp.py:
--------------------------------------------------------------------------------
1 | import dataclasses
2 | import os
3 |
4 | import ipyvue
5 | import traitlets
6 |
7 | import solara
8 | from solara.alias import rw
9 |
10 |
11 | @dataclasses.dataclass
12 | class Clicks:
13 | value: int
14 |
15 |
16 | @solara.component
17 | def ButtonClick():
18 | clicks, set_clicks = solara.use_state(Clicks(0))
19 | return rw.Button(description=f"Clicked {clicks.value} times", on_click=lambda: set_clicks(Clicks(clicks.value + 1)))
20 |
21 |
22 | app = ButtonClick()
23 |
24 |
25 | @solara.component
26 | def ClickBoom():
27 | count, set_count = solara.use_state(0)
28 | if count == 1:
29 | raise ValueError("I crash on 1")
30 | return solara.Button("Boom", on_click=lambda: set_count(count + 1))
31 |
32 |
33 | clickboom = ClickBoom()
34 |
35 |
36 | class TestWidget(ipyvue.VueTemplate):
37 | template_file = os.path.realpath(os.path.join(os.path.dirname(__file__), "test.vue"))
38 |
39 | value = traitlets.Any(0).tag(sync=True)
40 |
41 |
42 | @solara.component
43 | def VueTestApp():
44 | return TestWidget.element(value="foobar")
45 |
46 |
47 | vue_test_app = VueTestApp()
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Maarten A. Breddels
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/solara/template/portal/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/solara/website/components/markdown_nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 | {{ element.innerText }}
12 |
13 |
14 |
15 |
16 |
17 |
35 |
--------------------------------------------------------------------------------
/packages/solara-assets/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Maarten A. Breddels
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/solara-meta/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Maarten A. Breddels
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/solara-server/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Maarten A. Breddels
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/pytest-ipywidgets/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Maarten A. Breddels
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/api/utilities/memoize.py:
--------------------------------------------------------------------------------
1 | """#Memoize"""
2 |
3 | import time
4 |
5 | import solara
6 | import solara.lab
7 | from solara.website.utils import apidoc
8 |
9 | # make sure the cache is only created once
10 | storage = solara.cache.Memory(max_items=2)
11 |
12 |
13 | @solara.component
14 | def Page():
15 | x, set_x = solara.use_state(5)
16 |
17 | @solara.memoize(storage=storage)
18 | def long_running_function(x: int) -> int:
19 | """This function takes a long time to run."""
20 | time.sleep(3)
21 | return x**2
22 |
23 | result = long_running_function.use_thread(x)
24 |
25 | with solara.Card("Expensive computation") as main:
26 | solara.Markdown("We cache 2 values. Each computation takes 3 seconds. If you go back to a cached value, you will see the result immediately.")
27 | solara.IntSlider("x", value=x, on_value=set_x)
28 | if result.state == solara.ResultState.FINISHED:
29 | solara.Markdown(f"Square of {x} is {result.value}")
30 | else:
31 | solara.Markdown("Running...")
32 | return main
33 |
34 |
35 | __doc__ += apidoc(solara.memoize) # type: ignore
36 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/advanced/style.py:
--------------------------------------------------------------------------------
1 | """
2 | # Style
3 |
4 | """
5 |
6 | import solara
7 | from solara.website.utils import apidoc
8 |
9 |
10 | @solara.component
11 | def Page():
12 | insert_css, set_insert_css = solara.use_state(True)
13 |
14 | css = """
15 | .mybutton {
16 | font-family: Serif;
17 | }
18 |
19 | /* this selector has to be very specific to override the vuetify style */
20 | .v-btn.mybutton {
21 | color: #4CAF50; /* Green */
22 | }
23 | /* vuetify's background color css has very high CSS-specificity, so we use !important */
24 | .mybutton {
25 | background-color: #FF9800 !important; /* Orange */
26 | }
27 | """
28 |
29 | solara.Checkbox(label="Use CSS", value=insert_css, on_value=set_insert_css)
30 | solara.Markdown(
31 | f"""
32 | ## CSS Example that styles the button below
33 | ```css
34 | {css}
35 | ```
36 | """
37 | )
38 | if insert_css:
39 | solara.Style(css)
40 | solara.Button(label="Advanced users might want to style this", icon_name="mdi-thumb-up", classes=["mybutton"])
41 |
42 |
43 | __doc__ += apidoc(solara.Style.f) # type: ignore
44 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/viz/plotly_express.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Wraps plotly express function and adds cross filtering support.
4 |
5 | Instead of `plotly.express' you can use `solara.express` instead.
6 |
7 | ```python
8 | # import plotly.express as px
9 | import solara.express as px
10 |
11 | df = px.data.iris()
12 | px.histogram(df, "species")
13 | px.scatter(df, x="sepal_width", y="sepal_length", color="species")
14 | ```
15 |
16 |
17 | Click the lasso icon in the top scatter plot to select points, which should then be filtered out in the other
18 | plots.
19 |
20 |
21 | """
22 |
23 | import plotly.express as px
24 |
25 | import solara
26 | import solara.express as spx
27 |
28 | df = px.data.iris()
29 |
30 |
31 | @solara.component
32 | def Page():
33 | solara.provide_cross_filter()
34 | fig = px.histogram(df, "species")
35 | fig.update_layout(dragmode="select", selectdirection="h")
36 |
37 | with solara.VBox() as main:
38 | spx.scatter(df, x="sepal_width", y="sepal_length", color="species")
39 | spx.scatter_3d(df, x="sepal_width", y="sepal_length", z="petal_width")
40 | spx.CrossFilteredFigurePlotly(fig)
41 | return main
42 |
--------------------------------------------------------------------------------
/tests/docs/docs_howto_no_browser_threaded_test.py:
--------------------------------------------------------------------------------
1 | import solara
2 | import solara.lab
3 | import ipyvuetify as v
4 | import time
5 |
6 |
7 | def test_docs_no_browser_api_thread():
8 | clicks = solara.reactive(0)
9 |
10 | @solara.component
11 | def ClickButton():
12 | @solara.lab.task
13 | def increment():
14 | # now we will wait for 0.3 seconds before updating the UI
15 | time.sleep(0.3)
16 | clicks.value += 1
17 |
18 | with solara.Card("Button in a card"):
19 | with solara.Column():
20 | solara.Button(label=f"Clicked: {clicks}", on_click=increment)
21 |
22 | # rc is short for render context
23 | box, rc = solara.render(ClickButton(), handle_error=False)
24 | finder = rc.find(v.Btn)
25 | button = finder.widget
26 | finder.assert_single()
27 | finder.assert_not_empty()
28 | assert button.children[0] == "Clicked: 0"
29 |
30 | # clicking will now start a thread, so we have to wait/poll for the UI to update
31 | button.click()
32 |
33 | button_after_delayed_click = rc.find(v.Btn, children=["Clicked: 1"])
34 | button_after_delayed_click.wait_for(timeout=2.5)
35 |
--------------------------------------------------------------------------------
/solara/website/pages/showcase/solarathon_2023_team_4.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | with solara.Link("/showcase"):
7 | solara.Text("« Back to Showcases")
8 | with solara.ColumnsResponsive(12, medium=6):
9 | with solara.Column(align="end", style={"height": "100%", "justify-content": "center"}):
10 | solara.Markdown(
11 | """
12 | Team 4 built a live cryptocurrency dashboard, which displayed the latest prices for various cryptocurrencies, and versatile
13 | analysis tools to help users make informed decisions.
14 |
15 | Note: The dashboard is no longer live on Ploomber, but you can see a preview of it in the video, or run it by cloning the GitHub repository.
16 | """
17 | )
18 | with solara.v.Html(tag="video", attributes={"controls": "controls", "autoplay": "autoplay"}, style_="width:100%;"):
19 | solara.v.Html(
20 | tag="source",
21 | attributes={"src": "https://dxhl76zpt6fap.cloudfront.net/public/showcase/solarathon_2023_team_4/preview.webm", "type": "video/webm"},
22 | )
23 |
--------------------------------------------------------------------------------
/solara/website/pages/showcase/solarathon_2023_team_2.py:
--------------------------------------------------------------------------------
1 | import solara
2 |
3 |
4 | @solara.component
5 | def Page():
6 | with solara.Link("/showcase"):
7 | solara.Text("« Back to Showcases")
8 | with solara.ColumnsResponsive(12, medium=6):
9 | with solara.Column(align="end", style={"height": "100%", "justify-content": "center"}):
10 | solara.Markdown(
11 | """
12 | Team 2 built a travel assistant, which utilized various third party APIs to display rich information about the desired destination
13 | during the dates selected for a visit. The assistant also provided a list of recommended activities, and a map of the area.
14 |
15 | Take a look at the project on [Ploomber](https://jolly-moon-5966.ploomberapp.io/)
16 | """
17 | )
18 | with solara.v.Html(tag="video", attributes={"controls": "controls", "autoplay": "autoplay"}, style_="width:100%;"):
19 | solara.v.Html(
20 | tag="source",
21 | attributes={"src": "https://dxhl76zpt6fap.cloudfront.net/public/showcase/solarathon_2023_team_2/preview.webm", "type": "video/webm"},
22 | )
23 |
--------------------------------------------------------------------------------
/solara/components/tab_navigation.py:
--------------------------------------------------------------------------------
1 | import solara
2 | from solara.alias import rv, rvue
3 |
4 |
5 | @solara.component
6 | def LinkTab(path, label):
7 | # both adding href to tab or adding Link makes vuetify buggy
8 | with rv.Tab() as tab:
9 | # with solara.Link(path):
10 | solara.Text(label)
11 | router = solara.use_router()
12 |
13 | def go(*ignore):
14 | router.push(path)
15 |
16 | rvue.use_event(tab, "click.prevent.stop", go)
17 | return tab
18 |
19 |
20 | @solara.component
21 | def TabNavigation(children=[], vertical=False, **kwargs):
22 | children = children or []
23 | route_current, all_routes = solara.use_route()
24 |
25 | tab_index = all_routes.index(route_current) if route_current is not None else 0
26 |
27 | with rv.Tabs(v_model=tab_index, vertical=vertical, **kwargs) as main:
28 | for i, route in enumerate(all_routes):
29 | path = solara.resolve_path(route)
30 | LinkTab(path, route.label or "No title")
31 | if route_current is None:
32 | return solara.Error("Page does not exist")
33 |
34 | with rv.TabsItems(v_model=tab_index, children=children):
35 | pass
36 |
37 | return main
38 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Working together with Voilà
3 | description: Voilà, together with `voila-vuetify` is an alternative to Solara server. The most significant difference is that Voilà will start one kernel/process
4 | per page request, while Solara server is more scalable.
5 | ---
6 | # Voilà
7 |
8 | [Voilà](https://voila.readthedocs.io/) allows you to convert a Jupyter Notebook into an interactive dashboard that allows you to share your work with others.
9 |
10 | Voilà is Jupyter notebook focused, meaning that it will render all output from your notebook. Using [`voila-vuetify`](https://github.com/voila-dashboards/voila-vuetify) Voilà allows for a more app like experience, showing only the output you want.
11 |
12 | Voilà, together with `voila-vuetify` is an alternative to [Solara server](./solara-server). The most significant difference is that Voilà will start one kernel/process per page request, while [Solara server](./solara-server) can serve many more users from a single process. Sharing the same process means Solara apps can share memory among users (e.g. a large dataset), which will usually lead to better performance and less resource usage.
13 |
--------------------------------------------------------------------------------
/packages/solara-milkdown/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin');
2 | var path = require('path');
3 |
4 | var rules = [
5 | { test: /\.css$/, use: ['style-loader', 'css-loader'] },
6 | {
7 | test: /\.(woff|woff2|eot|ttf|otf)$/,
8 | loader: 'file-loader',
9 | }
10 | ]
11 |
12 |
13 | module.exports = [
14 | {
15 | entry: './src/index.js',
16 | output: {
17 | filename: 'index.js',
18 | path: path.resolve(__dirname, 'dist'),
19 | libraryTarget: 'umd',
20 | devtoolModuleFilenameTemplate: `webpack://@widgetti/solara-milkdown`
21 | },
22 | module: {
23 | rules: rules
24 | },
25 | devtool: 'source-map',
26 | mode: 'development',
27 | },
28 | {
29 | entry: './src/index.js',
30 | output: {
31 | filename: 'index.min.js',
32 | path: path.resolve(__dirname, 'dist'),
33 | libraryTarget: 'umd',
34 | devtoolModuleFilenameTemplate: `webpack://@widgetti/solara-milkdown`
35 | },
36 | module: {
37 | rules: rules
38 | },
39 | mode: 'production',
40 | }
41 | ];
42 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/examples/general/live_update.py:
--------------------------------------------------------------------------------
1 | from typing import cast, Optional
2 | import httpx
3 | import asyncio
4 | import solara
5 | import solara.lab
6 |
7 |
8 | @solara.component
9 | def Page():
10 | btc = solara.use_reactive(cast(Optional[float], None))
11 |
12 | async def fetch_btc_price():
13 | while True:
14 | await asyncio.sleep(1)
15 | async with httpx.AsyncClient() as client:
16 | url = "https://api.binance.com/api/v1/ticker/price?symbol=BTCUSDT"
17 | response = await client.get(url)
18 | btc.value = float(response.json()["price"])
19 | print("btc.value", btc.value)
20 |
21 | fetch_result = solara.lab.use_task(fetch_btc_price, dependencies=[])
22 | # the task keeps running, so is always in the pending mode, so we combine it with the btc value being None
23 | if fetch_result.pending and btc.value is None:
24 | solara.Text("Fetching BTC price...")
25 | else:
26 | if fetch_result.error:
27 | solara.Error(f"Error fetching BTC price: {fetch_result.exception}")
28 | else:
29 | solara.Text(f"BTC price: ${btc.value}")
30 |
31 |
32 | Page()
33 |
--------------------------------------------------------------------------------
/solara/website/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/tests/integration/file_download_test.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | import pandas as pd
4 | import playwright
5 | import playwright.sync_api
6 |
7 |
8 | def test_download(browser: playwright.sync_api.Browser, page_session: playwright.sync_api.Page, solara_server, solara_app, tmpdir: Path):
9 | with solara_app("solara.website.pages"):
10 | page_session.goto(solara_server.base_url + "/documentation/components/output/file_download")
11 | with page_session.expect_download() as download_info:
12 | page_session.locator('button:has-text("Download file")').click()
13 | target = tmpdir / "downloaded.txt"
14 | download = download_info.value
15 | download.save_as(target)
16 | assert target.read_text(encoding="utf8") == "This is the content of the file"
17 |
18 | with page_session.expect_download() as download_info:
19 | page_session.locator('button:has-text("Download: users.csv")').click()
20 | target = tmpdir / "downloaded.csv"
21 | download = download_info.value
22 | download.save_as(target)
23 | df = pd.read_csv(target)
24 | assert df.to_dict() == {"id": {0: 1, 1: 2, 2: 3}, "name": {0: "John", 1: "Mary", 2: "Bob"}}
25 |
--------------------------------------------------------------------------------
/solara/components/download.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
30 |
31 |
36 |
--------------------------------------------------------------------------------
/solara/website/components/breadcrumbs.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 | import solara
3 |
4 |
5 | @solara.component
6 | def BreadCrumbs():
7 | router = solara.use_router()
8 | routes = router.path_routes
9 |
10 | with solara.Row(style={"align-items": "center", "flex-wrap": "wrap"}) as main:
11 | for i, route in enumerate(routes):
12 | if i == len(routes) - 1:
13 | solara.Text(route.label or route.path, style={"color": "var(--color-text-fade)"})
14 | else:
15 | with solara.Link(solara.resolve_path(route), style={"color": "var(--color-text-fade)"}):
16 | solara.Text(route.label or route.path)
17 | if i != len(routes) - 1:
18 | solara.Text("/", style={"font-size": "1.5rem", "color": "var(--color-text-fade)"})
19 | return main
20 |
21 |
22 | def _resolve_path_to_route(path_to_find: List[str], all_routes: List[solara.Route], routes: List[solara.Route] = []):
23 | if len(path_to_find) == 0:
24 | return routes
25 | for route in all_routes:
26 | if path_to_find[0] == route.path:
27 | routes += [route]
28 | return _resolve_path_to_route(path_to_find[1:], route.children, routes)
29 |
--------------------------------------------------------------------------------
/packages/solara-vuetify3-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@widgetti/solara-vuetify3-app",
3 | "version": "5.0.2",
4 | "description": "Solara Vuetify App",
5 | "main": "dist/solara-vuetify-app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "webpack",
9 | "watch": "webpack --watch --mode=development",
10 | "devlink": "TARGET_DIR=`python -c \"import sys; print(sys.prefix)\"`/share/solara/cdn/@widgetti/solara-vuetify3-app@5.0.2/; mkdir -p $TARGET_DIR && rm -rf $TARGET_DIR/dist && ln -sf $PWD/dist $TARGET_DIR/dist"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "dependencies": {
15 | "@mdi/font": "^4.9.95",
16 | "@widgetti/solara-widget-manager": "file:../solara-widget-manager",
17 | "@widgetti/solara-widget-manager8": "file:../solara-widget-manager8",
18 | "material-design-icons-iconfont": "^5.0.1",
19 | "typeface-roboto": "0.0.54",
20 | "vue": "^3.3.4",
21 | "vuetify": "~3.3.17"
22 | },
23 | "devDependencies": {
24 | "css-loader": "^6.9.1",
25 | "file-loader": "^6.2.0",
26 | "mini-css-extract-plugin": "^2.7.7",
27 | "style-loader": "^3.3.4",
28 | "webpack": "^5.90.0",
29 | "webpack-cli": "^5.1.4"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/solara/server/assets/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Using static files and resources in your Solara application
3 | description: When using Solara, you can host static files, like images, which will then be available at /static/public, in the ../public folder.
4 | ---
5 | # Static files
6 |
7 | Files located on your local filesystem at the `../public` directory will be served by the Solara server at `/static/public`. A typical directory layout looks like this:
8 |
9 | ```
10 | ├── pages
11 | │ ├── 01-landing-page.md
12 | │ ├── 02-some_app.py
13 | └── public
14 | └── beach.jpeg
15 | ```
16 |
17 | For instance, on this server, the `beach.jpeg` file will be available at `/static/public/beach.jpeg` and the full URL will be [`https://solara.dev/static/public/beach.jpeg`](https://solara.dev/static/public/beach.jpeg)
18 |
19 | Putting the `public` directory 1 level higher than the `pages` directory avoids name collision with pages.
20 |
21 | ```solara
22 | import solara
23 |
24 |
25 | @solara.component
26 | def Page():
27 | image_url = "/static/public/beach.jpeg"
28 | with solara.Card(title="The following image is served from the ../public directory"):
29 | solara.Image(image_url)
30 |
31 | ```
32 |
--------------------------------------------------------------------------------
/packages/solara-enterprise/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling==1.26.3"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "solara-enterprise"
7 | authors = [
8 | {name = "Maarten A. Breddels", email = "maartenbreddels@gmail.com"},
9 | {name = "Mario Buikhuizen", email = "mariobuikhuizen@gmail.com"}]
10 | license = {file = "LICENSE"}
11 | requires-python = ">=3.8"
12 | classifiers = ["License :: Free for non-commercial use"]
13 | dynamic = ["version", "description"]
14 | dependencies = [
15 | "solara-ui==1.56.0",
16 | "solara-server==1.56.0",
17 | ]
18 |
19 | [project.optional-dependencies]
20 | ssg = [
21 | "beautifulsoup4",
22 | "playwright",
23 | ]
24 |
25 | cache = [
26 | "diskcache",
27 | ]
28 |
29 | auth = [
30 | "authlib",
31 | "itsdangerous",
32 | "httpx",
33 | ]
34 |
35 | all = [
36 | "solara-enterprise[ssg]",
37 | "solara-enterprise[auth]",
38 | "solara-enterprise[cache]",
39 | ]
40 |
41 | [project.urls]
42 | Home = "https://www.github.com/widgetti/solara"
43 |
44 | [tool.hatch.version]
45 | path = "solara_enterprise/__init__.py"
46 |
47 | [tool.black]
48 | line-length = 160
49 |
50 | [tool.ruff]
51 | line-length = 160
52 |
53 | [tool.isort]
54 | profile = "black"
55 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/status/info.py:
--------------------------------------------------------------------------------
1 | """# Info
2 |
3 | Solara has 4 types of alerts:
4 |
5 | * [Success](/documentation/components/status/success)
6 | * Info (this page)
7 | * [Warning](/documentation/components/status/warning)
8 | * [Error](/documentation/components/status/error)
9 |
10 |
11 |
12 | """
13 |
14 | import solara
15 | from solara.website.utils import apidoc
16 |
17 |
18 | @solara.component
19 | def Page():
20 | icon = solara.use_reactive(True)
21 | dense = solara.use_reactive(False)
22 | outlined = solara.use_reactive(True)
23 | text = solara.use_reactive(True)
24 |
25 | with solara.GridFixed(4):
26 | solara.Checkbox(label="Use icon", value=icon)
27 | solara.Checkbox(label="Show dense", value=dense)
28 | solara.Checkbox(label="Show as text", value=text)
29 | solara.Checkbox(label="Show outlined", value=outlined)
30 | solara.Info(
31 | f"This is solara.Info(label='...', text={text.value}, dense={dense.value}, outlined={outlined.value}, icon={icon.value})",
32 | text=text.value,
33 | dense=dense.value,
34 | outlined=outlined.value,
35 | icon=icon.value,
36 | )
37 |
38 |
39 | __doc__ += apidoc(solara.Info.f) # type: ignore
40 |
--------------------------------------------------------------------------------
/solara/website/pages/documentation/components/status/error.py:
--------------------------------------------------------------------------------
1 | """# Error
2 |
3 | Solara has 4 types of alerts:
4 |
5 | * [Success](/documentation/components/status/success)
6 | * [Info](/documentation/components/status/info)
7 | * [Warning](/documentation/components/status/warning)
8 | * Error (this page)
9 |
10 |
11 |
12 | """
13 |
14 | import solara
15 | from solara.website.utils import apidoc
16 |
17 |
18 | @solara.component
19 | def Page():
20 | icon = solara.use_reactive(True)
21 | dense = solara.use_reactive(False)
22 | outlined = solara.use_reactive(True)
23 | text = solara.use_reactive(True)
24 |
25 | with solara.GridFixed(4):
26 | solara.Checkbox(label="Use icon", value=icon)
27 | solara.Checkbox(label="Show dense", value=dense)
28 | solara.Checkbox(label="Show as text", value=text)
29 | solara.Checkbox(label="Show outlined", value=outlined)
30 | solara.Error(
31 | f"This is solara.Error(label='...', text={text.value}, dense={dense.value}, outlined={outlined.value}, icon={icon.value})",
32 | text=text.value,
33 | dense=dense.value,
34 | outlined=outlined.value,
35 | icon=icon.value,
36 | )
37 |
38 |
39 | __doc__ += apidoc(solara.Error.f) # type: ignore
40 |
--------------------------------------------------------------------------------