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

Draft: Generic "Run app" framework #4616

Closed
wants to merge 13 commits into from
Closed

Conversation

seeM
Copy link
Contributor

@seeM seeM commented Sep 9, 2024

The purpose of this draft PR is to gather feedback about a generic approach to support a bunch of Python app frameworks. Feedback about code details isn't needed at this stage. You should be able to open a Shiny, Dash, Gradio, Streamlit, Flask, or FastAPI app and run it with the corresponding command. I haven't hooked up when clauses to only show the relevant command.

The idea is to allow extensions to register "application runners", implementing a getRunOptions method that returns the terminal command and set of environment variables needed to run an application, given some required information. The implementation of the runApplication method was adapted from the shiny-vscode extension.

In hindsight, I think the "application runner" concept is unnecessary at this stage. It's already possible to do all of this in extension land (e.g. shiny-vscode). I'm now leaning toward moving all of the logic into the Python extension. That'd mean duplicating code across extensions for different language packs, but I don't think that's a problem.

Before I make any further changes, what do folks think?

@seeM
Copy link
Contributor Author

seeM commented Sep 9, 2024

One more thing. The approach of finding a free port and passing it as a command-line arg doesn't work if the user hardcodes the port in their application, which is possible in some of these frameworks.

In those cases it would have still been possible to determine the port by scraping the terminal. However, I don't think that would be helpful for Workbench, where I think we have to configure the app framework to use a URL prefix that depends on the port. Determining the port from the terminal would be too late.

@isabelizimm
Copy link
Contributor

It's already possible to do all of this in extension land (e.g. shiny-vscode). I'm now leaning toward moving all of the logic into the Python extension.

I don't feel super strongly about this, but if it is equal convenience/difficulty in either location, I would rather have it in Positron core. I imagine it would be more convenient there (especially if UI elements change later or anything like that).

@juliasilge
Copy link
Contributor

I took a look at what is here so far and I tend to think that it is better not to build out the application runner infrastructure into the Positron core without a motivating example, given that extensions can already provide tasks or run things in the terminal. Maybe we can outline what we would do instead:

  • Use context keys to identify apps
  • Provide command + UI for users to use
  • Build out tasks (probably? could instead link up commands to directly run in terminal) to run the apps

There are a few other bits of this PR that we may still need to add to Positron itself, like finding a port.

@nstrayer
Copy link
Contributor

What's here looks good to me. I haven't had time to fully consider the solution space but I like this.

My vote would be keeping as much in core as possible to make it as easy as possible for new languages to be added. That being said this could be a massive instance of premature optimization so if the workload/ complexity is much less to put that logic into language packs then I will defer that decision to the implementer.

@jmcphers
Copy link
Collaborator

I'm now leaning toward moving all of the logic into the Python extension. That'd mean duplicating code across extensions for different language packs, but I don't think that's a problem.

What I'd suggest is moving this logic into its own extension that exposes an API that other extensions can use. That will allow you to centralize the logic around finding ports, starting terminals, etc. without making a bunch of changes to the core.

You can see the Jupyter Adapter for an example of how this is done:

  • the Jupyter Adapter extension's activate() method returns an API
  • a strongly typed .d.ts file gives the API's shape and is used in extensions that depend on the API
  • extensions like Positron R and Positron Python declare the Jupyter Adapter as a dependency
  • to call the API, they ask VS Code for a handle to the extension

@isabelizimm
Copy link
Contributor

adding some context on ports, from an offline discussion with @seeM

possible ways to find if users have set ports themselves:

  1. Looking for the argument port=XXX in a Python script (apparently this is one strategy workbench uses). People might not be using the named arg, which would make this difficult
  2. Scraping the terminal, which might not be possible on workbench ❌
  3. Watching for ports opened after starting the app. I'm not sure if there would be false positives here?
  4. Not caring about the port, using our own. We can overwrite the user's port for all the frameworks besides gradio. The theory here is, for local dev/testing in the Viewer, the port is probably less important than in a production environment. However, this might be a confusing experience.

@seeM
Copy link
Contributor Author

seeM commented Sep 11, 2024

Thank you all for the feedback!

I'm closing this and will work on a separate PR where this lives in a built-in extension with an exposed API. I've also asked the Workbench team for feedback on how to design the API (or any other necessary changes) to improve Workbench integration and will factor that in, either to the next PR or future work.

@seeM seeM closed this Sep 11, 2024
@seeM seeM deleted the positron-applications-api branch September 11, 2024 13:24
@github-actions github-actions bot locked and limited conversation to collaborators Sep 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants