Hi all,
I am interested in a dash app that generates code for buidling a dashapp. As part of this Dash app, I would like to be able to run the generated code and link the main app to see an interactive rendering in the main app. What I tried:
- Having a div generated and link it to the main page layout. It works but does not all call backs to be linked & interact with the first app which creates potential errors.
- Adding a management of registration of the callbakcs from the secondary to the main app. It works but it does not allow refresh or removal of non valid callback anymore from the new iteration of generated code
- Create a full second app, launch it by sub process to isolate both & link to an Iframe. It seems the best solution, but I can"t get the second app launched properly & linked to the Iframe working. Here is the code
app1.py
import dash
from dash import html, dcc, Input, Output, State
import subprocess
import time
import socket
import threading
import sys
def find_available_port():
"""Finds an available port on the system."""
sock = socket.socket()
sock.bind(('', 0))
return sock.getsockname()[1]
available_port = 8055 #find_available_port()
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("Dash App 1"),
html.Button("Launch App 2", id="launch-button"),
html.Div(id="status-div"),
html.Div(id="iframe-container", children=[]), # Placeholder for iframe
])
app2_process = None # Variable to store the subprocess
app2_launched = False # Flag to ensure the second app isn't started multiple times
import subprocess
import sys
def launch_app2(port):
global app2_process, app2_launched
print(port)
# Run app2.py in the background
if not app2_launched:
try:
app2_process = subprocess.Popen([sys.executable, "app2.py", f"--port={port}"], creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, close_fds=True, start_new_session=True)
app2_launched = True
return "App 2 launched successfully!", True
except Exception as e:
return f"Error launching App 2: {e}", False
else:
return "App 2 is already launched", True
@app.callback(
[Output("status-div", "children"),
Output("iframe-container", "children")],
Input("launch-button", "n_clicks"),
State("iframe-container", "children")
)
def update_iframe(n_clicks, current_iframe):
global available_port
if n_clicks is None:
return "Click the button to launch App 2.", current_iframe
status_msg, success = launch_app2(available_port)
if success:
time.sleep(1)
# Replace '192.168.x.x' with your local IP address
iframe = html.Iframe(src=f"http://<your_local_ip>:{available_port}", style={"width": "100%", "height": "600px"})
return status_msg, [iframe]
else:
return status_msg, current_iframe
if __name__ == "__main__":
app.run_server(debug=True)
app2.py
import dash
from dash import html
import argparse
parser = argparse.ArgumentParser(description="Run the second dash application")
parser.add_argument("--port", type=int, required=True, help="Port number")
args = parser.parse_args()
app = dash.Dash(__name__)
app.layout = html.Div("Hello World")
if __name__ == "__main__":
try:
print("starting app2 server") # Debug line
app.run_server(debug=True, port=args.port, host="127.0.0.1")
except Exception as e:
print(f"Error on run_server: {e}")
However, it creates the following error I can’t get rid of. Is there a way that would work ?
Error on run_server: [WinError 10038] An operation has been tried on a non Socket element.
Thanks!