Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive console in solara web interface. #2683

Open
Sahil-Chhoker opened this issue Feb 12, 2025 · 18 comments · May be fixed by #2697
Open

Interactive console in solara web interface. #2683

Sahil-Chhoker opened this issue Feb 12, 2025 · 18 comments · May be fixed by #2697

Comments

@Sahil-Chhoker
Copy link
Collaborator

Sahil-Chhoker commented Feb 12, 2025

This feature idea originates from discussions on PR #2674 and PR #2176. After setting up an environment for Python code execution in the Solara GUI (PR #2674), the idea of turning it into a more console-like experience was proposed. I decided to take a step back and create a minimal prototype to explore its potential. My plan is to refine the backend for code execution once the Solara GUI is fully developed. However, due to my limited knowledge of the Solara web framework, I’m opening this issue to gather ideas and collaborate on making this feature possible.

Current Implementation:

import solara
import sys
import code
import io


# Backend console stuff
class Interpreter(code.InteractiveInterpreter):
    def __init__(self):
        super().__init__()
        self.output_buffer = io.StringIO()

    def run_code(self, command):
        sys.stdout = self.output_buffer
        sys.stderr = self.output_buffer
        try:
            self.runsource(command)
            output = self.output_buffer.getvalue()
            return output if output else "Command executed successfully."
        except SyntaxError as e:
            return f"SyntaxError: {str(e).split(')')[-1].strip()}"
        except Exception as e:
            return f"{type(e).__name__}: {str(e)}"
        finally:
            sys.stdout = sys.__stdout__
            sys.stderr = sys.__stderr__
            self.output_buffer.truncate(0)
            self.output_buffer.seek(0)


interpreter = Interpreter()

# history list to replicate the console
history = []


def execute_code(input_text, set_input_text):
    if input_text.strip():
        output = interpreter.run_code(input_text)
        # error cleanup
        if isinstance(output, str) and "Traceback" in output:
            error_lines = output.strip().splitlines()
            for line in reversed(error_lines):
                if ": " in line:
                    output = line.strip()
                    break
        history.append((f">>> {input_text}", output))
        set_input_text("")


def clear_console():
    history.clear()


@solara.component
def Page():
    input_text, set_input_text = solara.use_state("")

    solara.Markdown(
        """
    # Python Console
    """
    )

    for cmd, result in history:
        solara.Markdown( # random styling + looks ugly 
            f"""
        <pre style="background-color: #f9f9f9; border: 1px solid #ddd; padding: 10px; border-radius: 1px; margin: 1px 0; font-family: 'Courier New', monospace; font-size: 14px;">
        ```python
        {cmd}
        ```
        {result}
        </pre>
        """
        )

    solara.InputText(
        value=input_text,
        label=">>>",
        continuous_update=True,
        on_value=set_input_text,
    )

    # For styling the input text
    solara.Style("""
    .v-text-field__slot {
        font-family: monospace !important;
    }
    """)

    solara.Button("Run", on_click=lambda: execute_code(input_text, set_input_text))
    solara.Button("Clear", on_click=clear_console)


Page()

Some features I am struggling to implement:

  1. Keyboard Enter -> Enter on app. ✔️
  2. Ctrl + L -> Console cleanup.
  3. Make the GUI look like a proper python console. ✔️

Features I am hoping to implement:

  1. Using _SecureCodeValidator from Feat: Added command center #2674 for validation of code executed in the console(if it gets a pass).
  2. Adding a variable explorer as suggested in this comment.

These features are open for discussion and feedback. I would greatly appreciate any new ideas or suggestions you may have!

@quaquel
Copy link
Member

quaquel commented Feb 12, 2025

Thanks a lot for this. I hope to be able to dig into this a bit more over the weekend.

@tpike3
Copy link
Member

tpike3 commented Feb 12, 2025

This is awesome @Sahil-Chhoker!

I have no immediate thoughts beyond what has already been discussed, but do have strategic goals to keep in mind. Just to emphasize, these are my ideas and @EwoutH and @quaquel can absolutely disagree.

The hard problem in ABMs is the solution space is so large and the details matter, so related to an interactive console would be interactive blocks that allow for rapidly assembling models, with the capability to interact with the blocks to make customizations. Partially articulated here https://github.com/projectmesa/mesa/wiki/Google-Summer-of-Code-2025#mesa-blocks

My thought for posting this here is that as you make these initial decisions you may make different choice for how to interact (initial conditions and long term dependencies).

To my concisely state, I think the long term goal is interactive blocks that can be reassembled rapidly, and not necessarily interacting with the entire model all at once. However, there are many paths to the end state, and getting an interactive console maybe the best 1st step.

@Sahil-Chhoker
Copy link
Collaborator Author

Hey @tpike3, thanks for sharing your thoughts!

While I understand your perspective, I don’t think I fully grasp it yet—maybe due to my inexperience in this field.

I see the benefits of interactive blocks, and they seem both functional and practical for the long term. However, I’m not entirely sure how they connect to the current console feature or how they might impact it.

From my perspective, the console serves as the central control hub for the entire simulation, allowing users to access and modify anything as needed. If Mesa were to incorporate Mesa Blocks, I would expect the console to remain central to that framework rather than being broken down into separate blocks.

That said, I realize I might be misunderstanding something. Please feel free to correct me if I’ve gotten anything wrong or made incorrect assumptions. I truly appreciate the insights!

Thanks again!

@quaquel
Copy link
Member

quaquel commented Feb 13, 2025

In my view, the idea of interactive blocks and the idea of a console/variable explorer are independent. The console/variable explorer should be an optional Solara component that users can add to any UI they want to build. If there is a UI for blocks, then the console/variable explorer would still be an optional add-in to the UI.

Having a console/variable explorer as an optional UI component just gives users even greater power to dynamically investigate (and debug) their model, whatever that model happens to be or how this model is built. Blocks is just a UI way of building a model, instead of having to write code.

@Sahil-Chhoker
Copy link
Collaborator Author

Sahil-Chhoker commented Feb 15, 2025

Update on this, the styling has improved significantly. Please tell me if it still needs improvement.

with solara.Sidebar():
        solara.Markdown("## Console")
        
        # new styling
        with solara.Column(style={"height": "300px", "overflow-y": "auto", "gap":"0px"}):
            for cmd, result in history:
                if result:
                    # Replace < and > with their HTML entities, prevents the browser from interpreting them as HTML tags
                    escaped_result = result.replace("<", "&lt;").replace(">", "&gt;")
                    solara.Markdown(
                    f"""
                    <div style="margin: 0px 0 0 0;">
                        <div style="background-color: #f5f5f5; padding: 6px 8px; border-radius: 4px; font-family: 'Consolas', monospace; font-size: 0.9em;">
                        <span style="color: #2196F3;">{">>> "} </span><span>{cmd.removeprefix(">>> ")}</span>
                        </div>
                        <div style="background-color: #ffffff; padding: 6px 8px; border-left: 3px solid #2196F3; margin-top: 2px; font-family: 'Consolas', monospace; font-size: 0.9em;">
                        {escaped_result}
                        </div>
                    </div>
                    """
                    )
                else:
                    solara.Markdown(
                    f"""
                    <div style="margin: 0px 0 0 0;">
                        <div style="background-color: #f5f5f5; padding: 6px 8px; border-radius: 4px; font-family: 'Consolas', monospace; font-size: 0.9em;">
                        <span style="color: #2196F3;">{">>> "} </span><span>{cmd.removeprefix(">>> ")}</span>
                        </div>
                    </div>
                    """
                    )

        input_element = solara.v.TextField(
            v_model=input_text,
            on_v_model=set_input_text,
            flat=True,
            style_="font-family: monospace;",
            label=">>>",
            outlined=True,
            placeholder="Enter Python code...",
            attributes={"spellcheck": "false"},
        )

Before:

Image

After:

Image

@quaquel
Copy link
Member

quaquel commented Feb 15, 2025

I like this styling a lot more.

  1. Is the run button needed or can it by tied to a key pressed event (i.e., enter?)
  2. It seems it might be possible to use ipython as a console via ipython.embed. Which might be even more powerful if that is easy to do.

@Sahil-Chhoker
Copy link
Collaborator Author

  1. Is the run button needed or can it by tied to a key pressed event (i.e., enter?)

I am trying to acheive that, upon looking at the solara documentation, I found use_change can be used to tie it to a keyboard enter press, but after running into several issues, I have opened up an issue on the solara github repo (link).

  1. It seems it might be possible to use ipython as a console via ipython.embed. Which might be even more powerful if that is easy to do.

Thanks, I will look into it!

@Sahil-Chhoker
Copy link
Collaborator Author

Update on this:

  1. Wasn't able to use the ipython.embed.
  2. Got the enter key working.
  3. Multiline commands work like a charm.
  4. Better error handling.

current state:

Image

I am thinking of using the same command validator used in #2674, it would be helpful if the code get's reviewed first.

@quaquel
Copy link
Member

quaquel commented Feb 17, 2025

What did you run into on ipython.embed?

I have a conference this week, but it's close to home, so I am not sure how much time I have for reviewing. I'll do my best to take a look at #2674.

@Sahil-Chhoker
Copy link
Collaborator Author

What did you run into on ipython.embed?

The problem was more fundamental, I couldn't figure out what to do with it. What I am doing is consistently get the user input and turning it into commands and process them, correct me if I'm wrong, IPython is used to get the interface better with some other functionalities right? If that's the case, we have to implement interface in Solara anyways and the code module backend is enough for running the commands. But if you want, I will take a look again and try to leverage the advanced features in that as well.

@quaquel
Copy link
Member

quaquel commented Feb 17, 2025

I had hoped ipython.embed would have been a drop-in alternative to code. But from your experience that does not seem to be the case. So, fine and let's go ahead with what you are doing. I really like it.

@Sahil-Chhoker
Copy link
Collaborator Author

Update on this:
Thinking of working on a variable explorer, not sure how it would look and perform.

Some ideas:

  1. Like in spyder ide:
    Image
  • It shows the namespace contents (including all global objects, variables, class instances and more) of the currently selected IPython Console session, and allows you to add, remove, and edit their values through a variety of GUI-based editors.

  • Pros: Highly detailed, visually appealing, and displays every variable.
  • Cons: Overkill for simple models, complex to implement, and may not fit well on the screen.

  1. Like the "watch" feature in vscode for debugging:
    Image
  • Only displays the specified variables and their values. No data types are shown.
  • Pros: Simple and minimalistic.
  • Cons: May not always reveal all available variables in the model.

I like the 2nd option better, but would love to get opinion on this. Feel free to comment on the ideas and maybe even suggest new ones.

@quaquel
Copy link
Member

quaquel commented Feb 20, 2025

I was thinking in the direction of the variable explorer in pycharm: https://www.jetbrains.com/help/pycharm/debug-tool-window-variables.html

It shows the variables in the current scope (so most likely only model) and then you can open up model in a tree-like manner.

Image

@Corvince
Copy link
Contributor

I was thinking in the direction of the variable explorer in pycharm: https://www.jetbrains.com/help/pycharm/debug-tool-window-variables.html

I like that too, only thing is that it seems a bit more complicated. For the sake of moving forward I would suggest leaving the variable explorer for now and bring on the console first. Otherwise I am afraid we lose focus and also the PR will be get too big to properly review.

@Sahil-Chhoker
Copy link
Collaborator Author

I think that for a larger model, this type of setup will look very cluttered. Similar setup also exists in vscode, but on top of that there exists a "watch" window, there instead of meticulously finding the required variable every time, you just type its name and the window shows the values associated with it may it be a dictionary or just a simple integer.

@quaquel
Copy link
Member

quaquel commented Feb 20, 2025

I agree with @Corvince, let's split of the variable explorer discussion from this one.

I am not familiar with watch in vscode, so I'll try to look into it soon.

@Sahil-Chhoker
Copy link
Collaborator Author

I would suggest leaving the variable explorer for now and bring on the console first. Otherwise I am afraid we lose focus and also the PR will be get too big to properly review.

It is a very valid point. I shall put up a PR as soon as the discussion on whether to include the _SecurityCodeValidator reaches its conclusion.

@Sahil-Chhoker Sahil-Chhoker linked a pull request Feb 21, 2025 that will close this issue
@Sahil-Chhoker
Copy link
Collaborator Author

I have opened a PR #2697, @quaquel @Corvince, I am looking forward to your opinion on that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants