Coder Social home page Coder Social logo

widgetti / solara Goto Github PK

View Code? Open in Web Editor NEW
1.6K 19.0 103.0 37.11 MB

A Pure Python, React-style Framework for Scaling Your Jupyter and Web Apps

Home Page: https://solara.dev

License: MIT License

Python 79.56% JavaScript 2.63% CSS 7.18% HTML 0.79% Vue 6.05% Procfile 0.08% Shell 0.19% Jinja 1.84% Jupyter Notebook 0.28% TypeScript 1.41%
dataapp fastapi flask ipywidgets jupyter starlette webapp

solara's People

Contributors

alisterburt avatar alonsosilvaallende avatar astrofrog avatar ben-epstein avatar blankscreen-exe avatar chaoses-ib avatar cyberqin avatar deeplook avatar dependabot[bot] avatar dorianux avatar edublancas avatar ewouth avatar giswqs avatar github-actions[bot] avatar hansnowak avatar hkayabilisim avatar iisakkirotko avatar itepifanio avatar jhsmit avatar koenvo avatar lp9052 avatar lundez avatar maartenbreddels avatar majortal avatar mariobuikhuizen avatar mostapharoudsari avatar naterush avatar nickcrews avatar salfaris avatar tylere avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solara's Issues

Quickstart example does not render correctly with solara run

I have a fresh conda environment with python 3.9 on windows. I've used poetry to install solara.

I have a myapp.py file with the following code:

import solara

@solara.component
def Page():
    clicks, set_clicks = solara.use_state(0)
    def increase_clicks():
        set_clicks(clicks+1)
    solara.Button(label=f"Clicked {clicks} times", on_click=increase_clicks)

And then run with:

solara run `myapp.py`

The webpage looks like this:
image

These are some of the errors in the console:

The stylesheet http://localhost:8765/_solara/cdn/[email protected]/css/font-awesome.min.css was not loaded because its MIME type, “text/plain”, is not “text/css”.
The script from “http://localhost:8765/_solara/cdn/[email protected]/dist/mermaid.min.js” was loaded even though its MIME type (“text/plain”) is not a valid JavaScript MIME type
The script from “http://localhost:8765/_solara/cdn/[email protected]/require.js” was loaded even though its MIME type (“text/plain”) is not a valid JavaScript MIME type.
The stylesheet http://localhost:8765/_solara/cdn/@widgetti/[email protected]/dist/main.css was not loaded because its MIME type, “text/plain”, is not “text/css”.

Widget failed with "Widget has no comm, you probably using a widget that was closed."

Step to reproduce:

  1. create new python environment.
  2. clone repo git clone https://github.com/aiidalab/aiidalab-qe.git && cd aiidalab-qe
  3. pip install .
  4. install solara
  5. start notebook: voila qe.ipynb and the exception manifested.
The AttributeError is also see from running notebook directly where the app showing just fine, so I assume it can be ignore and not critically make it not working.

However, the web page keep on loading and in the terminal shows the exception:

Traceback (most recent call last):
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/solara/server/app.py", line 497, in load_app_widget
    widget, render_context = _run_app(
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/solara/server/app.py", line 445, in _run_app
    main_object = app_script.run()
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/solara/server/app.py", line 255, in run
    return self._execute()
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/solara/server/app.py", line 143, in _execute
    exec(ast, local_scope)
  File "/home/jyu/Projects/WP-AiiDAlab/aiidalab-qe/qe.ipynb input cell 3", line 41, in <module>
  File "/home/jyu/Projects/WP-AiiDAlab/aiidalab-qe/aiidalab_qe/steps.py", line 310, in __init__
    self.workchain_settings = WorkChainSettings()
  File "/home/jyu/Projects/WP-AiiDAlab/aiidalab-qe/aiidalab_qe/steps.py", line 132, in __init__
    super().__init__(
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget_box.py", line 64, in __init__
    super(Box, self).__init__(**kwargs)
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 480, in __init__
    self.open()
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 493, in open
    state, buffer_paths, buffers = _remove_buffers(self.get_state())
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 591, in get_state
    value = to_json(getattr(self, k), self)
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 55, in _widget_to_json
    return [_widget_to_json(v, obj) for v in x]
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 55, in <listcomp>
    return [_widget_to_json(v, obj) for v in x]
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/ipywidgets/widgets/widget.py", line 57, in _widget_to_json
    return "IPY_MODEL_" + x.model_id
  File "/home/jyu/micromamba/envs/aiidalab-voila-00/lib/python3.9/site-packages/solara/server/patch.py", line 335, in model_id_debug
    raise RuntimeError("Widget has no comm, you are probably using a widget that was closed. The widget is:\n" + repr(self))
RuntimeError: Widget has no comm, you are probably using a widget that was closed. The widget is:
HTML(value='<div style="padding-top: 0px; padding-bottom: 0px">\n        <h4>Structure</h4></div>')

missing pandas requirement

I have a fresh conda environment with python 3.9 on windows. I've used poetry to install solara.

When running the quickstart example:

import solara

@solara.component
def Page():
    clicks, set_clicks = solara.use_state(0)
    def increase_clicks():
        set_clicks(clicks+1)
    solara.Button(label=f"Clicked {clicks} times", on_click=increase_clicks)

I get the error:

Traceback (most recent call last):
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\core.py", line 1457, in _render
    root_element = el.component.f(*el.args, **el.kwargs)
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\solara\autorouting.py", line 87, in RoutingProvider
    path, set_path = solara.use_state(pathname, key="solara-context-path")
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\core.py", line 722, in use_state
    return rc.use_state(initial, key, eq)
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\core.py", line 1093, in use_state
    elif utils.isinstance_lazy(initial, "pandas.DataFrame"):
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\utils.py", line 86, in isinstance_lazy
    types = [import_item(t) if isinstance(t, str) else t for t in types]
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\utils.py", line 86, in <listcomp>
    types = [import_item(t) if isinstance(t, str) else t for t in types]
  File "C:\Users\jhsmi\Miniconda3\envs\py39_solara\lib\site-packages\reacton\utils.py", line 79, in import_item
    module = __import__(".".join(parts[:-1]), fromlist=[parts[-1]])
ModuleNotFoundError: No module named 'pandas'

While I would expect pandas to be either optional (for this example) or listed as requirement

[Bug] Solara `FigurePlotly` seems to be broken

This code used to work, but now it hangs forever

Version info

solara 1.10.0
plotly 5.9.0

code

import pandas as pd
import solara as sl
import plotly.express as px

@sl.component
def Page():
    df = pd.read_csv("conv_intent.csv")
    df["text_length"] = df.text.str.len()
    df["id"] = list(range(len(df)))
    df["hovertext"] = df.text.str.wrap(30).str.replace("\n", "<br>")
    fig = px.scatter(
        df,
        x="x",
        y="y",
        custom_data=[df["id"]],
        hover_data=["hovertext"],
    )
    fig.update_layout(showlegend=False)
    fig.update_xaxes(visible=False)
    fig.update_yaxes(visible=False)
    fig.update_traces(marker_size=2)
    
    sl.FigurePlotly(fig)
    
Page()

The code outside of a component (plotly only) works

I've attached the file below
conv_intent.csv

sol.markdown() converts nested lists to a single html list

Example:

- [What it is?](#what-it-is?)
- [Example](#example)
- [Usage](#usage)
- [Deployment](#deployment)
  - [Flask](#flask)
  - [Starlette](#flask)
  - [FastAPI](#flask)
  - [Voila](#voila)
  - [Panel](#panel)
  - [Nginx](#nginx)
- [Installation](#installation)
- [Development](#development)
- [FAQ](#faq)

Converted to:

<div class="solara-markdown rendered_html jp-RenderedHTMLCommon">
    <ul>
        <li><a href="#what-it-is?">What it is?</a></li>
        <li><a href="#example">Example</a></li>
        <li><a href="#usage">Usage</a></li> 
        <li><a href="#deployment">Deployment</a></li> 
        <li><a href="#flask">Flask</a></li> 
        <li><a href="#flask">Starlette</a></li> 
        <li><a href="#flask">FastAPI</a></li> 
        <li><a href="#voila">Voila</a></li> 
        <li><a href="#panel">Panel</a></li> 
        <li><a href="#nginx">Nginx</a></li> 
        <li><a href="#installation">Installation</a></li> 
        <li><a href="#development">Development</a></li> 
        <li><a href="#faq">FAQ</a></li>
    </ul>
</div>

It should output a nested list. The issue exists for ordered list as well.

This online markdown converter can be used to see appropriate output https://markdowntohtml.com/

[Feature Request] solara DataFrame should handle pandas Styler

If you have a styled df = pandas.DataFrame().style, you can pass it as sdf = solara.DataFrame(df.data) but you loose the styling that was applied to df. So if columns were hidden by the styler, they are displayed again. It would be good for solara.DataFrame to reapply the style before when displaying sdf in a notebook for example.

Design question Reactive state class with mutable values / `default_factory` for Reactive classes

Suppose I'm making a solara component with several inputs/widgets, with a corresponding State class, and assuming the return of this component is a list of ints.

I would probably want to do something like this:

@dataclasses.dataclass
class State:
    my_reactive_numbers = Reactive[List[int]]([])

And in my app create an instance of State and pass to the component. This works fine, however if i create multiple pairs of the component/state there could be a problem because of the mutable default argument passed to Reactive (the list), as shown here:

s1 = State()
s2 = State()

s1.my_reactive_numbers.value = [1,2,3]
s2.my_reactive_numbers.value

>>> [1,2,3]

For non-mutable defaults such as str/int/float its not a problem.

A solution could be to instead to this:

class InitState():

    def __init__(self):
        self.my_reactive_numbers = Reactive([])

However, I would like to keep the possibility of using dataclasses. Perhaps Reactive variables should either optionally accept a default_factory kwarg (such as used for dataclasses; dataclasses.field(default_factory=list) ) or we should create a constructor which allows for passing of factory methods?

For example, in class Reactive:

    @classmethod
    def from_factory(cls, factory: Callable[[], S]) -> "Reactive[S]":
        return cls(factory())

Then you could define your State class as:

@dataclasses.dataclass
class State:
    my_reactive_numbers = Reactive[List[int]]([])

    my_reactive_factory_numbers = Reactive[List[int]].from_factory(list)

s1 = State()
s2 = State()

s1.my_reactive_factory_numbers = [4,5,6]
s2.my_reactive_factory_numbers.value
>>> []

Running solara app in a docker container with ipv6

Hi guys,

I am not able to run my solara app in a docker container. Running the docker container results in the following error:

ERROR: [Errno 99] error while attempting to bind on address ('::1', 8765, 0, 0): cannot assign requested address

Here is what my Dockerfile looks like

#
# Build image
#

FROM python:3.11-slim as builder

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1 \
    POETRY_HOME=/opt/poetry

WORKDIR /app
COPY . .

RUN apt update -y && apt upgrade -y && apt install curl -y
RUN curl -sSL https://install.python-poetry.org | python3 -
RUN ${POETRY_HOME}/bin/poetry config virtualenvs.create false 
RUN ${POETRY_HOME}/bin/poetry install --no-dev 
RUN ${POETRY_HOME}/bin/poetry export -f requirements.txt >> requirements.txt


#
# Prod image
#

FROM python:3.11-slim AS runtime


WORKDIR /app
COPY . .
COPY --from=builder /app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt


EXPOSE 8765
CMD ["solara", "run", "src/app.py"]

Solara App running on VM is not reachable

Hi guys,

thanks for this great lib. I´ve already used it some time in jupyter notebooks and running apps on my local machine. However, I am not able to access apps running on my VM (oracle cloud). All I see is a "solara" spinner and the message "Loading app". I think it´s problem with my firewall configuration. Which ports need to be open for running apps on a virtual machine?

Thanks,
legout

[Bug] In new jupyter notebook (7+), the fullscreen button is missing from app

In jupyter version 7+, when you run a Solara app in the notebook, there's no option to go fullscreen anymore.

simple app

import solara as sl

@sl.component
def Page():
    sl.Markdown("# Hi there!")
    sl.Markdown("This is my page")
    
Page()

image

Jupyter versions

Selected Jupyter core packages...
IPython          : 8.12.0
ipykernel        : 6.22.0
ipywidgets       : 8.0.6
jupyter_client   : 8.2.0
jupyter_core     : 5.3.0
jupyter_server   : 2.5.0
jupyterlab       : not installed
nbclient         : 0.7.3
nbconvert        : 7.3.1
nbformat         : 5.8.0
notebook         : 6.5.4
qtconsole        : 5.4.2
traitlets        : 5.9.0

Solara version: '1.10.0'

Slow duckdb queries

Hello,

i´ve tested duckdb with solara and found, that executing queries in a solara app is much slower (5-10x) than running the same query in a jupyter notebook.

Here is some code for reproduction:

import duckdb
import pandas as pd
import solara
import pyarrow.dataset as pds
from typing import cast, Optional
import os
import threading
from solara.alias import rv
import tempfile
import time

TEMP_PATH = tempfile.mkdtemp()


def download_dataset(name: str = "netflix_titles"):
    df = pd.read_csv(
        f"https://raw.githubusercontent.com/adamerose/datasets/master/{name}.csv"
    )
    pd.concat([df for i in range(3)]).to_parquet(
        f"{TEMP_PATH}/{name}.parquet", index=False
    )


def register_table(
    con: duckdb.DuckDBPyConnection,
    name: str,
    path: str,
):
    if not os.path.exists(path):
        download_dataset(name)

    if not con.sql("SHOW TABLES"):
        ds = pds.dataset(path)
        con.register(name, ds)
    else:
        if name not in con.sql("SHOW TABLES").df()["name"].tolist():
            ds = pds.dataset(path)
            con.register(name, ds)


ALL_DATASETS1 = [
    "country_indicators",
    "diamonds",
    "gammas",
    "gapminder",
    "googleplaystore",
    "googleplaystore_reviews",
    "happiness",
    "harry_potter_characters",
    "iris",
    "mpg",
]
ALL_DATASETS2 = [
    "netflix_titles",
    "penguins",
    "planets",
    "pokemon",
    "seinfeld_episodes",
    "seinfeld_scripts",
    "stockdata",
    "tips",
    "titanic",
    "trump_tweets",
    "us_shooting_incidents",
]
DATASETS1 = solara.reactive([])
DATASETS2 = solara.reactive([])
DDB = duckdb.connect()


@solara.component
def Page():
    query, set_query = solara.use_state(
        "SELECT * FROM googleplaystore_reviews INNER JOIN googleplaystore ON googleplaystore_reviews.App=googleplaystore.App"
    )
    query_executed, set_query_executed = solara.use_state(cast(Optional[str], None))
    ddb_cursor, set_ddb_cursor = solara.use_state(DDB.cursor())
    registered_tables, set_registered_tables = solara.use_state([])
    table_hints, set_table_hints = solara.use_state({})

    def register_tables(cancel: threading.Event):
        for name in DATASETS1.value:
            register_table(
                con=ddb_cursor,
                path=f"{TEMP_PATH}/{name}.parquet",
                name=name,
            )
            set_registered_tables(registered_tables + [name])

        for name in DATASETS2.value:
            register_table(
                con=ddb_cursor,
                path=f"{TEMP_PATH}/{name}.parquet",
                name=name,
            )
            set_registered_tables(registered_tables + [name])

        # table_names = ddb_cursor.sql("SHOW TABLES").pl()["name"]
        if len(registered_tables):
            table_hints_ = {
                table_name: ddb_cursor.sql(f"FROM {table_name}").columns
                for table_name in registered_tables
            }
            set_table_hints(table_hints_)

    def run_query(cancel: threading.Event) -> pd.DataFrame:
        if not query_executed:
            return

        df = ddb_cursor.sql(query_executed).df()

        return df

    result: solara.Result[pd.DataFrame] = solara.use_thread(
        run_query, dependencies=[query_executed]
    )

    with solara.VBox() as main:
        with solara.Card("Toggle to register the dataset."):
            solara.ToggleButtonsMultiple(
                DATASETS1, ALL_DATASETS1, on_value=register_tables
            )
            solara.ToggleButtonsMultiple(
                DATASETS2, ALL_DATASETS2, on_value=register_tables
            )

        solara.SqlCode(
            label="Query Editor",
            query=query,
            tables=table_hints,
            on_query=set_query,
            height="240px",
        )
        enable_execute = (query != query_executed) or result.error is not None

        def execute():
            if not len(registered_tables):
                register_tables()

            set_query_executed(query)
            if query == query_executed and result.error:
                result.retry()  # type: ignore

        solara.Button("Execute", on_click=execute, disabled=not enable_execute)
        if result.error:
            solara.Error(f"Ooops {result.error}")
        elif not query:
            solara.Info("No query")
        elif result.value is not None:
            solara.Markdown(
                f"<details><summary>Query</summary> `{query_executed}`</details>"
            )
            df = result.value
            solara.DataFrame(df)

        elif query_executed is not None:
            with solara.Div():
                solara.Text("Loading data...")
                rv.ProgressCircular(indeterminate=True, class_="solara-progress")

        if result.value is not None:
            with solara.Card("Download"):
                with solara.Column():
                    df = result.value
                    solara.FileDownload(
                        data=df.to_csv(index=False),
                        filename="result.csv",
                        label="Download query result",
                    )

    return main


def run_query():
    download_dataset("googleplaystore")
    download_dataset("googleplaystore_reviews")
    ddb_cursor = DDB.cursor()
    register_table(
        ddb_cursor, "googleplaystore", path=f"{TEMP_PATH}/googleplaystore.parquet"
    )
    register_table(
        ddb_cursor,
        "googleplaystore_reviews",
        path=f"{TEMP_PATH}/googleplaystore_reviews.parquet",
    )

    start_time = time.time()
    df = ddb_cursor.sql(
        "SELECT * FROM googleplaystore_reviews INNER JOIN googleplaystore ON googleplaystore_reviews.App = googleplaystore.App"
    ).df()
    print(f"Execution time: {time.time()-start_time:.2f} seconds.")


if __name__ == "__main__":
    Page()
    # run_query()

Reported occational crash of solara.dev

Reported at https://www.reddit.com/r/Python/comments/13fegbp/comment/jjva0xp/?utm_source=reddit&utm_medium=web2x&context=3

image

11vue.runtime.esm.js:1897 Error: Cannot sendat l.send (solara-widget-manager8.min.js:391:640623)at t.send (solara-widget-manager8.min.js:23:32156)at ee.send (solara-widget-manager8.min.js:23:18578)at VueRenderer.js:183:11at Ye (vue.runtime.esm.js:1863:26)at s.n (vue.runtime.esm.js:2188:14)at Ye (vue.runtime.esm.js:1863:26)at e.$emit (vue.runtime.esm.js:3903:9)at s.click (vuetify.js:2477:12)at Ye (vue.runtime.esm.js:1863:26)

Components sometimes do not get re-rendered (plotly map trigger)

Consider this example

import numpy as np
import pandas as pd
import plotly.express as px
import solara

# Generate data
df = pd.DataFrame.from_records(
    [
        {'code': "GBR", "value": 1},
        {'code': "NLD", "value": 10},
        {'code': "USA", "value": 3},
        {'code': "FRA", "value": 2},
        {'code': "ES", "value": 7},
    ]
)

# Make a figure
fig = px.choropleth(data_frame=df, locations='code', color='value')

# Simple solara app that captures clicks on the map and prints the click event:

@solara.component
def Page():
    
    text, set_text = solara.use_state('text')
    
    def function(x):
        x = str(x)
        set_text(x)

    print(text)
    
    with solara.VBox() as main:
        solara.FigurePlotly(fig=fig, on_click=function)
        solara.Card(title=text)
        # solara.Card(title=solara.Markdown(text))  # uncomment this to break app
    
    return main

display(Page())  # For Jupyter notebook only

If you run this app as is, things will work file. If you uncomment the line indicated in the code, the Card components are no longer updated, but the actual text variable is being updated (as you can see by the print statement).

I only noticed this behavior for the plotly maps. I tried similar example as above with a scatter plot and a histogram and there everything works as expected.

Let me know if you need more info.

solara version: 0.14.0
system: macOS
installed via: pip (from pypi) within conda env

Input components are not `value_components`

I'm trying to use .connect on a solara.InputFloat, because I'm trying to adapt the scatter.py app example.

However, this is a solara.component, instead of a reacton.value_component.
I was expecting the input components to also be value components because Checkbox, Select, Togglebuttons (togglebuttons is solara.value_component vs reacton.value_component.

Is there a reason these are not value components?

solara.dev/apps/scatter raises AssertionError

At the moment, when I visit https://solara.dev/apps/scatter on firefox, I briefly see the web page correctly but then I get the traceback posted below.

The same occurs in chrome or in incognito window.
The other full screen apps are working.

Traceback (most recent call last):
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1794, in _reconsolidate
    self._remove_element(self.context.elements[key], key, parent_key=parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1845, in _remove_element
    self._remove_element(self.context.root_element, "/", parent_key=new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1861, in _remove_element
    assert widget.model_id in widgets.Widget.widgets
AssertionError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1838, in _remove_element
    effect.cleanup()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 968, in cleanup
    self._cleanup()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/solara/hooks/dataframe.py", line 45, in cleanup
    listener()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/solara/hooks/dataframe.py", line 35, in on_change
    updater()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/solara/hooks/misc.py", line 355, in updater
    set_counter(lambda count: count + 1)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1154, in set_
    self.render(self.element, self.container)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1271, in render
    widget = self._reconsolidate(self.element, default_key="/", parent_key=ROOT_KEY)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  [Previous line repeated 1 more time]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
    kwargs = reconsolidate_children()
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1678, in reconsolidate_children
    new_kwargs = self._visit_children_values(kwargs, key, parent_key, self._reconsolidate)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in _visit_children_values
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1907, in <dictcomp>
    return {k: self._visit_children_values(v, f"{key}{k}/", parent_key, f) for k, v in value.items()}
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in _visit_children_values
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1902, in <listcomp>
    values = [self._visit_children_values(v, f"{key}{index}/", parent_key, f) for index, v in enumerate(value)]
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1899, in _visit_children_values
    return f(value, key, parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1594, in _reconsolidate
    widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1794, in _reconsolidate
    self._remove_element(self.context.elements[key], key, parent_key=parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1845, in _remove_element
    self._remove_element(self.context.root_element, "/", parent_key=new_parent_key)
  File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1861, in _remove_element
    assert widget.model_id in widgets.Widget.widgets
AssertionError

[Feature request] Fade or loading overlay for components

I have an app with a plotly graph which re-renders when users change some inputs (number of bins, selection of x/y axis, etc)
I'm using the use_thread such that the rendering is threaded, and when the redrawing is in progress, the app shows the solara.SpinnerSolara. This works well but there are a lot of pixels which change a lot between the loading and rendered state, which makes the app feel very jittery.

Instead, I would like to be able to place a fade, possible with text / spinner, on top of the previous render of the graph to show the component is loading. Perhaps something similar to or an extension of #81.

Getting an error `ERROR: nbextension pydeck/extension not found` always

I'm running a simple solara app, but keep seeing the Error

ERROR:    nbextension pydeck/extension not found
2023-04-11 08:32:49,240 nbextension pydeck/extension not found

It's not stopping the app from running, but I do get the error every time

I'm running this from code, not from a jupyter notebook, so it's weird to get an nbextension error. When I list my nbextensions I get
image

I manually installed it

jupyter nbextension install --sys-prefix --symlink --overwrite --py pydeck
jupyter nbextension enable --sys-prefix --py pydeck

and I got a success message, but it still shows that it's not successful, and I still get the error when running the app

[Feature Request] New Table component

I think sl.Table would be great, especially if It could come from a pandas dataframe (or list of dictionaries etc).

Currently, I need to do this to get a decent centered table

html = (f"""
            <table class='center' height="50%" width="100%" align=center cellpadding ="25">
              <tr>
                <th><h2>Question</h2></th>
                <th><h2>Answer</h2></th>
              </tr>
              {get_table_rows()}
            </table>
            """
        )

and then a get_table_rows helper function thats like this

def get_table_rows() -> str:
    table_rows = ""
    for question in State.history.value:
        table_rows += f"<tr>\n\t<td>{question.q}</td>\n\t<td>{question.a}</td>\n</tr>"
    return table_rows

It would be awesome if I could have a simple styled centered table from an object
sl.Table(my_data)

Layout is 'blindly' used, we should check if it is a component

# sol.py
from ipywidgets import Layout, Button
page = Button()
# solara run sol.py

Will not give a nice error msg, but: traitlets.traitlets.TraitError: The 'children' trait of a Sheet instance contains an Union of a List which expected a DOMWidget or a unicode string, not the Layout Layout().

cc @mangecoeur

Review component_vue decorator.

@mariobuikhuizen I took the opportunity to implement the decorator we desperately needed to avoid boilerplate in 9b47b51:

@solara._component_vue("algolia.vue")
def Algolia(app_id: str, index_name: str, api_key: str, debug=False):
    pass

which I used in 7793e76

I think we should review this together and remove the underscore

`use_state_or_update` API docs source doesn't show `use_state_or_update` example code

On the use_state_or_update API docs (https://solara.dev/api/use_state_or_update), when clicking the 'show code' button, you only see the code of the Page component, which doesn't use use_state_or_update at all.

I guess this is because the api docs page is autogenerated from the Page component, which for most cases should be fine, however in this case the other components have the actual use case and information needed to understand the example.

Suggestion: a button that links to the github pages/api/ ... and/or a button that links to the solara implementation on GitHub

DataFrame Widget: Navigation controls not visible on wide dataframes in Jupyter Lab

It seems the navigation controls are remaining under the rightmost portion of the dataframe, even when the frame cannot be displayed completely due to it wide width. This leaves the navigation controls not accessible. Also, there is no scrollbar to view the rest of the dataframe columns. Here is some sample code to demo the problem:

import solara
import pandas as pd
import plotly

df = plotly.data.iris()

for col in range(60):
    df[str(col)] = str(col + 1)

@solara.component
def Page():
    solara.DataFrame(df, items_per_page=5)

Jupyter Lab: Simple demo failure

On Jupyter Lab, the simple word demo gives me 'Error displaying widget'. I'm running the latest ubuntu and chrome. Jupyter server version is 1.4.1.

Here is some of the log that might be helpful

manager-base.js:274 Could not instantiate widget
(anonymous) @ manager-base.js:274
u @ manager-base.js:45
(anonymous) @ manager-base.js:26
a @ manager-base.js:18
Promise.then (async)
u @ manager-base.js:19
(anonymous) @ manager-base.js:20
P @ manager-base.js:16
t._make_model @ manager-base.js:258
(anonymous) @ manager-base.js:247
u @ manager-base.js:45
(anonymous) @ manager-base.js:26
(anonymous) @ manager-base.js:20
P @ manager-base.js:16
t.new_model @ manager-base.js:233
t.handle_comm_open @ manager-base.js:145
_handleCommOpen @ 523.fa256ee012d38a89b65a.js:1
_handleCommOpen @ default.js:1021
await in _handleCommOpen (async)
_handleMessage @ default.js:1189
await in _handleMessage (async)
(anonymous) @ default.js:109
Promise.then (async)
C._onWSMessage @ default.js:106
utils.js:119 Error: Could not create a model.
at r (utils.js:119:27)
at async _handleCommOpen (523.fa256ee012d38a89b65a.js:1:2798)
at async C._handleCommOpen (default.js:1020:102)
at async C._handleMessage (default.js:1188:43)
r @ utils.js:119
Promise.catch (async)
t.handle_comm_open @ manager-base.js:150
_handleCommOpen @ 523.fa256ee012d38a89b65a.js:1
_handleCommOpen @ default.js:1021
await in _handleCommOpen (async)
_handleMessage @ default.js:1189
await in _handleMessage (async)
(anonymous) @ default.js:109
Promise.then (async)
C._onWSMessage @ default.js:106
default.js:1027 Exception opening new comm
_handleCommOpen @ default.js:1027
await in _handleCommOpen (async)
_handleMessage @ default.js:1189
await in _handleMessage (async)
(anonymous) @ default.js:109
Promise.then (async)
C._onWSMessage @ default.js:106

[Solara Enterprise] The Avatar size parameter isn't used

The Avatar component accepts a size var but it's actually not used to alter the image size:

@solara.component
def Avatar(image_url: Optional[str] = None, size: Union[int, str] = 40, color: str = "primary"):
    user = auth.user.value
    if user:
        user_info = user.get("userinfo", {})
        src = image_url
        if src is None:
            src = user_info.get("picture")
        if src:
            with v.Avatar(size=40, class_="ma-2"):
                v.Img(src=src)
        else:
            with v.Avatar(size=40, color=color):
                v.Icon(children=["mdi-account"])
    else:
        with v.Avatar(size=40, color=color):
            with solara.Tooltip("No user"):
                v.Icon(children=["mdi-error"])

Should be

@solara.component
def Avatar(image_url: Optional[str] = None, size: Union[int, str] = 40, color: str = "primary"):
    user = auth.user.value
    if user:
        user_info = user.get("userinfo", {})
        src = image_url
        if src is None:
            src = user_info.get("picture")
        if src:
            with v.Avatar(size=size, class_="ma-2"):
                v.Img(src=src)
        else:
            with v.Avatar(size=size, color=color):
                v.Icon(children=["mdi-account"])
    else:
        with v.Avatar(size=size, color=color):
            with solara.Tooltip("No user"):
                v.Icon(children=["mdi-error"])

Serving App via FastAPI

Hi everyone,

I would love to have some documentation hints at how to serve a wonderful SOLARA app using FastAPI.

In the example shown here, I don't know how to specify the python file name that contains the app. I guess the first argument of app.mount, i.e., /solara is the directory containing the python file containing the app.

Thanks,
Sam

feature request: add package on conda-forge

hi devs, great project, I'm a heavy user of ipyvuetify and I really like the concept behind solara. I had a problem when I wanted to test it: there's no package on conda-forge (that I could find, at least).

I know that it's possible to use pip in a conda environment, which I did, but the large number of dependencies became a problem, because pip and conda don't play together very well in dependency resolution. pip attempted to update and reinstall many already-present packages.

Anyway, something to consider for the future. Thanks for your work!

ListItem enable `two-line`

I'm trying to enable the two-line mode on a ListItem as shown in the lists example here and in the api docs here

I expect this kind of output:
image

But instead, the title and subtitle are side-by-side.

code:

import solara
from solara.alias import rv


FILE_LIST = [
    {"name": "file1.txt", "icon": "mdi-file", "subtitle": "banana"},
    {"name": "file2.pdf", "icon": "mdi-file-pdf", "subtitle": "pear"},
    {"name": "asdf.png", "icon": "mdi-file-image", "subtitle": "apple"}
]


@solara.component
def Page():

    file_list, set_file_list = solara.use_state(FILE_LIST)
    list_items = []
    for idx, file in enumerate(file_list):

        def on_delete(idx=idx):
            new_items = file_list.copy()
            del new_items[idx]
            set_file_list(new_items)


        delete_btn = solara.IconButton(color='primary', small=True, rounded=True, icon_name='mdi-delete',
                                       on_click=lambda *args: on_delete())

        list_item = rv.ListItem(two_line=True, #two_line=True doesnt do anything
                               children=[
                                   rv.ListItemIcon(left=True, children=[rv.Icon(children=[file['icon']])]),
                                   rv.ListItemTitle(children=[file['name']]),
                                   rv.ListItemSubtitle(children=[file["subtitle"]]),
                                   delete_btn
                               ]
                               )
        list_items.append(list_item)

    rv.List(children=list_items, max_width=750)

result

image

clearing cdn cache directory

          Ok, mystery solved. You have to nuke your cdn cache directory, e.g. sth like this:
$ rm -rf /c/ProgramData/Miniconda3/envs/solara39/share/solara/cdn/

Originally posted by @maartenbreddels in #37 (comment)

I just updated my solara 1.7.1 to solara 1.8.0 (both installed with poetry), and I had to manually clear the cache dir to get the new install of solara to work.
Is it possible to automatically clear the cache with a new (minor) version install?

Solara as desktop app

Started #100 and also asked about on Discord.

I'm opening this to collect interest.

What I can see happening is a pyinstaller + https://pypi.org/project/pywebview/ in CI to test if it is possible to make a desktop-like application and because in CI it will always be stable.
But users will still have to build the custom apps themselves if they need particular python packages.

importing solara from python in console starts interactive shell

When I'm in on cmd.exe on windows, I wanted to quickly import solara and check its installed or the version.

This unexpectedly started an interactive shell, which I do not or cannot exit (ctrl + C or exit() do not work)
What I did:

python
>>> import solara

image

Also it looks like that importing solara (also when running as python.exe myfile.py) prints two objects:

image

Support for route in solara.ListItem()

Often you will need to point a listitem to solara route. We can have a path_or_route param to the ListItem(). to support vue route (similar to solara.Link()).

progressbar with filedrop resonds slow

When connecting the FileDrop to a ProgressLinear I find that the progress bar is slow to respond to progress callbacks.
The progress value is being printed at regular intervals, every 1-2 percent for a large file, but the progress bar only updates a few times and lags behind.

code:

import solara
from solara.alias import rv

@solara.component
def Page():
    progress, set_progress = solara.use_state(0.)

    def on_progress(value):
        print(f"on_progress: {value}")
        set_progress(value)

    solara.FileDrop(on_total_progress=on_progress, lazy=False, on_file=lambda x: print('file loaded'))

    rv.ProgressLinear(value=progress)

ProgressCircular has the exact same behaviour

Circular import error

Hi everyone,

After installing the latest Solara (as of today, 1.0.3) and trying to run the simple example shared by @maartenbreddels here

I am getting a circular import error. But things are fine if I use version 0.19.1

I tried to use even 1.0.0 version, but always get this error. Can someone please help?

Thanks,
Sam

Review component_vue decorator.

@mariobuikhuizen I took the opportunity to implement the decorator we desperately needed to avoid boilerplate in 9b47b51:

@solara._component_vue("algolia.vue")
def Algolia(app_id: str, index_name: str, api_key: str, debug=False):
    pass

which I used in 7793e76

I think we should review this together and remove the underscore

502 for docs

@Ben-Epstein got a 502 error,
the only thing I saw in the logs was:

Apr 11 02:36:29 PM      return f(value, key, parent_key)
Apr 11 02:36:29 PM    File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1605, in _reconsolidate
Apr 11 02:36:29 PM      widget = self._reconsolidate(child_context.root_element_next, "/", new_parent_key)
Apr 11 02:36:29 PM    File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 1710, in _reconsolidate
Apr 11 02:36:29 PM      widget, orphan_ids = el._create_widget(kwargs)
Apr 11 02:36:29 PM    File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 351, in _create_widget
Apr 11 02:36:29 PM      raise RuntimeError(f"Could not create widget {self.component.widget} with {kwargs}") from e
 File "/opt/render/project/src/.venv/lib/python3.9/site-packages/reacton/core.py", line 351, in _create_widget
Apr 11 02:36:29 PM      raise RuntimeError(f"Could not create widget {self.component.widget} with {kwargs}") from e
Apr 11 02:36:29 PM  RuntimeError: Could not create widget <class 'ipyvuetify.Html.Html'> with {'tag': 'ul', 'children': [Html(attributes={'href': '/docs'}, children=[Html(attributes={'class': None}, children=['Introduction'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/installing'}, children=[Html(attributes={'class': None}, children=['Installing'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/quickstart'}, children=[Html(attributes={'class': None}, children=['Quickstart'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/tutorial'}, children=[Html(attributes={'class': None}, children=['Tutorial', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/tutorial/data-science'}, children=[Html(attributes={'class': None}, children=['Data Science'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/tutorial/web-app'}, children=[Html(attributes={'class': None}, children=['Web App'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/tutorial/ipywidgets'}, children=[Html(attributes={'class': None}, children=['Ipywidgets'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/tutorial/streamlit'}, children=[Html(attributes={'class': None}, children=['Streamlit'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/tutorial/dash'}, children=[Html(attributes={'class': None}, children=['Dash'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/howto'}, children=[Html(attributes={'class': None}, children=['Howto', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/howto/multipage'}, children=[Html(attributes={'class': None}, children=['Multipage'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/howto/layout'}, children=[Html(attributes={'class': None}, children=['Layout'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference'}, children=[Html(attributes={'class': None}, children=['Reference', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/reference/static-files'}, children=[Html(attributes={'class': None}, children=['Static Files'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/asset-files'}, children=[Html(attributes={'class': None}, children=['Asset Files'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/static-site-generation'}, children=[Html(attributes={'class': None}, children=['Static Site Generation'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/search'}, children=[Html(attributes={'class': None}, children=['Search'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/reloading'}, children=[Html(attributes={'class': None}, children=['Reloading'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/notebook-support'}, children=[Html(attributes={'class': None}, children=['Notebook Support'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/reference/caching'}, children=[Html(attributes={'class': None}, children=['Caching'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding'}, children=[Html(attributes={'class': None}, children=['Understanding', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/understanding/ipywidgets'}, children=[Html(attributes={'class': None}, children=['Ipywidgets'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/ipyvuetify'}, children=[Html(attributes={'class': None}, children=['Ipyvuetify'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/reacton'}, children=[Html(attributes={'class': None}, children=['Reacton'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/reacton-basics'}, children=[Html(attributes={'class': None}, children=['Reacton Basics'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/anatomy'}, children=[Html(attributes={'class': None}, children=['Anatomy'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/rules-of-hooks'}, children=[Html(attributes={'class': None}, children=['Rules Of Hooks'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/containers'}, children=[Html(attributes={'class': None}, children=['Containers'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/solara'}, children=[Html(attributes={'class': None}, children=['Solara'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/routing'}, children=[Html(attributes={'class': None}, children=['Routing'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/solara-server'}, children=[Html(attributes={'class': None}, children=['Solara Server'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/understanding/voila'}, children=[Html(attributes={'class': None}, children=['Voila'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/deploying'}, children=[Html(attributes={'class': None}, children=['Deploying', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/deploying/self-hosted'}, children=[Html(attributes={'class': 'active'}, children=['Self Hosted'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/deploying/cloud-hosted'}, children=[Html(attributes={'class': None}, children=['Cloud Hosted'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/development'}, children=[Html(attributes={'class': None}, children=['Development', Html(attributes={'class': None}, layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/troubleshoot'}, children=[Html(attributes={'class': None}, children=['Troubleshoot'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/faq'}, children=[Html(attributes={'class': None}, children=['Faq'], layout=None, tag='li')], layout=None, tag='a'), Html(attributes={'href': '/docs/lab'}, children=[Html(attributes={'class': None}, children=['Lab', Html(attributes={'class': None}, children=[Html(attributes={'href': '/docs/lab/toestand'}, children=[Html(attributes={'class': None}, children=['Toestand'], layout=None, tag='li')], layout=None, tag='a')], layout=None, tag='ul')], layout=None, tag='li')], layout=None, tag='a')], 'attributes': {'class': None}}

[Feature Request] Create a solara component for a scrollable text area

Often times you want a scrollable text area for markdown, text, sql, code, anything really. You should be able to do something like

with sl.Scrollable(max_height="500px"):
    sl.Markdown("## Hi")
    sl.Markdown(<some_long_text>)

or something similar. Currently, I need to do this, which would be nearly impossible to figure out for a new user

import reacton.ipyvuetify as v
with sl.Card():
    card_md = v.Container(
        style_=(
            "height: 700px; overflow-y: scroll;"
        )
    )
    card_md.add_children([sl.Markdown(my_content)])
        

expand width on `FileDownload`

I'd like the FileDownload the expand to the full width of a column / sidebar.

import solara

@solara.component
def Page():

    with solara.Sidebar():
        with solara.Column():
            solara.InputText(label="Text input")
            solara.Button(label='My button', block=True)
            solara.FileDownload(label='My file download', data='foobar')


    with solara.Column():
        solara.InputText(label="Text input")
        solara.Button(label='My button', block=True)
        solara.FileDownload(label='My file download', data='foobar')

gives:

image

I can make the button expand in width with block=True, but the FileDownload does not accept this kwarg.

Support latex

We currently don't support latex. Although we can support it easily on initial page load, we should also make sure they get updated when the widget value updates.
See voila-dashboards/voila#531 for inspiration

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.