-
Notifications
You must be signed in to change notification settings - Fork 92
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
Integrate Python web apps with Workbench #4769
Comments
The Quarto preview Terminal output shows the proxied path in addition to the localhost URL: The Quarto extension code that outputs "Browse at ": https://github.com/quarto-dev/quarto/blob/49abc46be3dbfd5cbd1eadf3d04cb4a7ac690b5c/apps/vscode/src/providers/preview/preview.ts#L532 |
Additional testing of Python web apps on Workbench: #4662 (comment)
Just to see what would happen, I tried modifying the following to include a call to positron proxy to retrieve the proxied URI. It seemed to fix the issues with Gradio and Fastapi, but Streamlit and Dash stopped working. Flask still remained happy. positron/extensions/positron-run-app/src/extension.ts Lines 226 to 235 in 659e073
It seems like we're in this situation: App Framework @seeM is it possible to preconfigure the app url (host:port) and pass that information to Positron Proxy? I suspect that may involve a bunch of framework-specific handling which may not be preferred. I'll look into what we can do on the Positron Proxy side to provide a proxy url separately from setting up the proxied connection. |
@sharon-wang thanks for doing this research! I suspected this and had the following solution in mind: The app-specific side is already implemented for Python apps here. Note how the various What still needs to be done is in the positron/extensions/positron-run-app/src/extension.ts Lines 84 to 89 in f1ae7a3
|
## Description - Addresses #4769 (as much as possible for now) ### Framework Support Summary (based on **_limited_** testing) | Framework | Positron Server Web | Positron Desktop | Positron on Workbench | Notes | |--------|--------|--------|--------|--------| | Dash | ✅ yes | ✅ yes | ✅ yes-ish | [Workbench extension issue](rstudio/rstudio-workbench-vscode-ext#262) to skip Dash framework handling to avoid conflicting with Positron's Dash framework handling | | Fastapi | ✅ yes | ✅ yes | 🛑 no | Seems to be a conflict between the way we run a fastapi app and that Workbench is setting `UVICORN_ROOT_PATH` | | Flask | ✅ yes | ✅ yes | ✅ yes | Workbench: works when including the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). | | Gradio | ✅ yes-ish | ✅ yes-ish | ✅ yes-ish | Working when the following dependency versions are used: `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. See gradio-app/gradio#9529 for more information on why more recent versions don't work. | | Streamlit | ✅ yes | ✅ yes | 🟨 partially | Not working on Workbench when SSL is enabled | | Shiny | ✅ yes | ✅ yes | ✅ yes | | ### Implementation Notes #### Positron Proxy CC @softwarenerd & @jmcphers - Add new command `positronProxy.startPendingProxyServer` which starts a new proxy server, but doesn't set up the middleware right away. The command will return the `externalUri` of the proxy server (this is the same as the url shown in the Viewer), the `proxyPath` (which some app frameworks use as the `urlPrefix`) and `finishProxySetup()` which the command-caller will invoke, passing the `targetOrigin` (the actual app url) so that we can finish setting up the middleware to proxy requests from the `externalUri` (app proxy uri) to the `targetOrigin` (actual app uri). - Refactor the proxy code so we can set up a proxy in multiple steps, not only all-at-once - existing callers of `startProxyServer()` will continue to use that method which still does the all-at-once proxy setup, by calling `startNewProxyServer()` and `finishProxySetup()` in succession - new option to call `startNewProxyServer()` standalone, which will only start up the server and then call `finishProxySetup()` later, once the `targetOrigin` is known - Move the HTML-rewriting code to the util file #### Positron Run App CC @seeM - expand the `localUrlRegex` to include the path after the url port `<HOST>:<PORT>/<PATH>` - execute the command `positronProxy.startPendingProxyServer` before setting up terminal options or the debug configuration, so we can start the proxy server and get the `urlPrefix` - before previewing the url in the Viewer, finish the proxy setup by passing the `localUri` to the positron proxy via `proxyInfo.finishProxySetup(localUri.toString())`, so that the proxy middleware is set up - remove `port` from types and test files as it is unused - increase timeout for waiting for the app url to show in the terminal (in particular, Gradio would take a bit longer on Workbench and we would timeout) #### Python Extension CC @seeM - remove `port` from the `webAppCommands` and related test files which is unused - update the framework-specific app arguments and environment variables to work with our proxy server situation #### Custom `resolveExternalUri` CC @melissa-barca - update the `resolvedUri` to inherit the protocol used by the main window as the uri's scheme, so we can upgrade to `https` if the main window is running in a secure context - NOTE: this will need to be upstreamed ### QA Notes This PR involves refactoring the positron-proxy, which is used by Help, Interactive Plots and the Viewer. We should not see any regression in these types of proxied content. Positron Server Web and Desktop should be working across all app frameworks in: - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/python_apps - When running the Gradio app, you will need to install these versions `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. If you can get it working with a more recent combination of versions, please let me know! - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/shiny-py-example - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/streamlit-py-example Positron on Workbench: - `dash` works if the generated `.env` file is deleted before running. Once [this issue](rstudio/rstudio-workbench-vscode-ext#262) is complete, this extra step won't be needed. - `fastapi` does not work. The current hunch is that Workbench setting `UVICORN_ROOT_PATH` at session start is interfering with how we run the `fastapi` app with `uvicorn`. The `UVICORN_ROOT_PATH` is set based on the default fastapi port `8000`, however I think we want the proxied app url as the root path, which is provided by the Positron Proxy. But, when setting `--root-path` in the fastapi app command to the proxied root path, it does not work in Server Web or Desktop. TBD if this resolves the issue on Workbench. More investigation needed. - `flask` works as long as you include the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). - `gradio` works when these versions are installed `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. There's [an issue](gradio-app/gradio#9529) in newer versions of Gradio when the app is run via a proxy. - `streamlit` does not work when SSL is set up. More investigation needed. - `shiny` no notes! --------- Co-authored-by: sharon wang <[email protected]>
Framework Support Summary as of #4978
|
I'll come back to this to investigate Fastapi and Streamlit after looking at the other 2024.11 Workbench-related issues. Moving to |
Opened issues for the remaining frameworks instead of keeping this issue pending. Moving this issue into Verification! |
## Description - Addresses #4769 (as much as possible for now) ### Framework Support Summary (based on **_limited_** testing) | Framework | Positron Server Web | Positron Desktop | Positron on Workbench | Notes | |--------|--------|--------|--------|--------| | Dash | ✅ yes | ✅ yes | ✅ yes-ish | [Workbench extension issue](rstudio/rstudio-workbench-vscode-ext#262) to skip Dash framework handling to avoid conflicting with Positron's Dash framework handling | | Fastapi | ✅ yes | ✅ yes | 🛑 no | Seems to be a conflict between the way we run a fastapi app and that Workbench is setting `UVICORN_ROOT_PATH` | | Flask | ✅ yes | ✅ yes | ✅ yes | Workbench: works when including the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). | | Gradio | ✅ yes-ish | ✅ yes-ish | ✅ yes-ish | Working when the following dependency versions are used: `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. See gradio-app/gradio#9529 for more information on why more recent versions don't work. | | Streamlit | ✅ yes | ✅ yes | 🟨 partially | Not working on Workbench when SSL is enabled | | Shiny | ✅ yes | ✅ yes | ✅ yes | | ### Implementation Notes #### Positron Proxy CC @softwarenerd & @jmcphers - Add new command `positronProxy.startPendingProxyServer` which starts a new proxy server, but doesn't set up the middleware right away. The command will return the `externalUri` of the proxy server (this is the same as the url shown in the Viewer), the `proxyPath` (which some app frameworks use as the `urlPrefix`) and `finishProxySetup()` which the command-caller will invoke, passing the `targetOrigin` (the actual app url) so that we can finish setting up the middleware to proxy requests from the `externalUri` (app proxy uri) to the `targetOrigin` (actual app uri). - Refactor the proxy code so we can set up a proxy in multiple steps, not only all-at-once - existing callers of `startProxyServer()` will continue to use that method which still does the all-at-once proxy setup, by calling `startNewProxyServer()` and `finishProxySetup()` in succession - new option to call `startNewProxyServer()` standalone, which will only start up the server and then call `finishProxySetup()` later, once the `targetOrigin` is known - Move the HTML-rewriting code to the util file #### Positron Run App CC @seeM - expand the `localUrlRegex` to include the path after the url port `<HOST>:<PORT>/<PATH>` - execute the command `positronProxy.startPendingProxyServer` before setting up terminal options or the debug configuration, so we can start the proxy server and get the `urlPrefix` - before previewing the url in the Viewer, finish the proxy setup by passing the `localUri` to the positron proxy via `proxyInfo.finishProxySetup(localUri.toString())`, so that the proxy middleware is set up - remove `port` from types and test files as it is unused - increase timeout for waiting for the app url to show in the terminal (in particular, Gradio would take a bit longer on Workbench and we would timeout) #### Python Extension CC @seeM - remove `port` from the `webAppCommands` and related test files which is unused - update the framework-specific app arguments and environment variables to work with our proxy server situation #### Custom `resolveExternalUri` CC @melissa-barca - update the `resolvedUri` to inherit the protocol used by the main window as the uri's scheme, so we can upgrade to `https` if the main window is running in a secure context - NOTE: this will need to be upstreamed ### QA Notes This PR involves refactoring the positron-proxy, which is used by Help, Interactive Plots and the Viewer. We should not see any regression in these types of proxied content. Positron Server Web and Desktop should be working across all app frameworks in: - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/python_apps - When running the Gradio app, you will need to install these versions `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. If you can get it working with a more recent combination of versions, please let me know! - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/shiny-py-example - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/streamlit-py-example Positron on Workbench: - `dash` works if the generated `.env` file is deleted before running. Once [this issue](rstudio/rstudio-workbench-vscode-ext#262) is complete, this extra step won't be needed. - `fastapi` does not work. The current hunch is that Workbench setting `UVICORN_ROOT_PATH` at session start is interfering with how we run the `fastapi` app with `uvicorn`. The `UVICORN_ROOT_PATH` is set based on the default fastapi port `8000`, however I think we want the proxied app url as the root path, which is provided by the Positron Proxy. But, when setting `--root-path` in the fastapi app command to the proxied root path, it does not work in Server Web or Desktop. TBD if this resolves the issue on Workbench. More investigation needed. - `flask` works as long as you include the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). - `gradio` works when these versions are installed `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. There's [an issue](gradio-app/gradio#9529) in newer versions of Gradio when the app is run via a proxy. - `streamlit` does not work when SSL is set up. More investigation needed. - `shiny` no notes! --------- Co-authored-by: sharon wang <[email protected]>
## Description - Addresses #4769 (as much as possible for now) ### Framework Support Summary (based on **_limited_** testing) | Framework | Positron Server Web | Positron Desktop | Positron on Workbench | Notes | |--------|--------|--------|--------|--------| | Dash | ✅ yes | ✅ yes | ✅ yes-ish | [Workbench extension issue](rstudio/rstudio-workbench-vscode-ext#262) to skip Dash framework handling to avoid conflicting with Positron's Dash framework handling | | Fastapi | ✅ yes | ✅ yes | 🛑 no | Seems to be a conflict between the way we run a fastapi app and that Workbench is setting `UVICORN_ROOT_PATH` | | Flask | ✅ yes | ✅ yes | ✅ yes | Workbench: works when including the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). | | Gradio | ✅ yes-ish | ✅ yes-ish | ✅ yes-ish | Working when the following dependency versions are used: `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. See gradio-app/gradio#9529 for more information on why more recent versions don't work. | | Streamlit | ✅ yes | ✅ yes | 🟨 partially | Not working on Workbench when SSL is enabled | | Shiny | ✅ yes | ✅ yes | ✅ yes | | ### Implementation Notes #### Positron Proxy CC @softwarenerd & @jmcphers - Add new command `positronProxy.startPendingProxyServer` which starts a new proxy server, but doesn't set up the middleware right away. The command will return the `externalUri` of the proxy server (this is the same as the url shown in the Viewer), the `proxyPath` (which some app frameworks use as the `urlPrefix`) and `finishProxySetup()` which the command-caller will invoke, passing the `targetOrigin` (the actual app url) so that we can finish setting up the middleware to proxy requests from the `externalUri` (app proxy uri) to the `targetOrigin` (actual app uri). - Refactor the proxy code so we can set up a proxy in multiple steps, not only all-at-once - existing callers of `startProxyServer()` will continue to use that method which still does the all-at-once proxy setup, by calling `startNewProxyServer()` and `finishProxySetup()` in succession - new option to call `startNewProxyServer()` standalone, which will only start up the server and then call `finishProxySetup()` later, once the `targetOrigin` is known - Move the HTML-rewriting code to the util file #### Positron Run App CC @seeM - expand the `localUrlRegex` to include the path after the url port `<HOST>:<PORT>/<PATH>` - execute the command `positronProxy.startPendingProxyServer` before setting up terminal options or the debug configuration, so we can start the proxy server and get the `urlPrefix` - before previewing the url in the Viewer, finish the proxy setup by passing the `localUri` to the positron proxy via `proxyInfo.finishProxySetup(localUri.toString())`, so that the proxy middleware is set up - remove `port` from types and test files as it is unused - increase timeout for waiting for the app url to show in the terminal (in particular, Gradio would take a bit longer on Workbench and we would timeout) #### Python Extension CC @seeM - remove `port` from the `webAppCommands` and related test files which is unused - update the framework-specific app arguments and environment variables to work with our proxy server situation #### Custom `resolveExternalUri` CC @melissa-barca - update the `resolvedUri` to inherit the protocol used by the main window as the uri's scheme, so we can upgrade to `https` if the main window is running in a secure context - NOTE: this will need to be upstreamed ### QA Notes This PR involves refactoring the positron-proxy, which is used by Help, Interactive Plots and the Viewer. We should not see any regression in these types of proxied content. Positron Server Web and Desktop should be working across all app frameworks in: - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/python_apps - When running the Gradio app, you will need to install these versions `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. If you can get it working with a more recent combination of versions, please let me know! - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/shiny-py-example - https://github.com/posit-dev/qa-example-content/tree/main/workspaces/streamlit-py-example Positron on Workbench: - `dash` works if the generated `.env` file is deleted before running. Once [this issue](rstudio/rstudio-workbench-vscode-ext#262) is complete, this extra step won't be needed. - `fastapi` does not work. The current hunch is that Workbench setting `UVICORN_ROOT_PATH` at session start is interfering with how we run the `fastapi` app with `uvicorn`. The `UVICORN_ROOT_PATH` is set based on the default fastapi port `8000`, however I think we want the proxied app url as the root path, which is provided by the Positron Proxy. But, when setting `--root-path` in the fastapi app command to the proxied root path, it does not work in Server Web or Desktop. TBD if this resolves the issue on Workbench. More investigation needed. - `flask` works as long as you include the code snippet from [Workbench docs](https://docs.posit.co/ide/server-pro/user/vs-code/guide/proxying-web-servers.html#flask). - `gradio` works when these versions are installed `gradio==3.3.1 fastapi==0.85.2 httpx==0.24.1`. There's [an issue](gradio-app/gradio#9529) in newer versions of Gradio when the app is run via a proxy. - `streamlit` does not work when SSL is set up. More investigation needed. - `shiny` no notes! --------- Co-authored-by: sharon wang <[email protected]>
All the apps work as expected with all the noted exceptions. |
Following on from #4662, we should update
runApplication
to detect if we're in Workbench, and if so, find a free port and corresponding proxied URL (possibly related to #4274) and pass them both togetTerminalOptions
. Unfortunately, some application frameworks need the proxied URL to be configured as the "URL prefix"/"root path".The text was updated successfully, but these errors were encountered: