11import dash
22import os
33import requests
4- from flask import request
54import flask .cli
6- from threading import Thread
75from retrying import retry
86import io
97import re
1917import uuid
2018
2119from .comms import _dash_comm , _jupyter_config , _request_jupyter_config
20+ from ._stoppable_thread import StoppableThread
2221
2322
2423def _get_skip (error : Exception ):
2524 tb = traceback .format_exception (type (error ), error , error .__traceback__ )
2625 skip = 0
27- for i , line in enumerate (text ):
26+ for i , line in enumerate (tb ):
2827 if "%% callback invoked %%" in line :
2928 skip = i + 1
3029 break
@@ -49,6 +48,8 @@ class JupyterDash(dash.Dash):
4948 _in_colab = "google.colab" in sys .modules
5049 _token = str (uuid .uuid4 ())
5150
51+ _server_threads = {}
52+
5253 @classmethod
5354 def infer_jupyter_proxy_config (cls ):
5455 """
@@ -138,15 +139,6 @@ def __init__(self, name=None, server_url=None, **kwargs):
138139
139140 self .server_url = server_url
140141
141- # Register route to shut down server
142- @self .server .route ('/_shutdown_' + JupyterDash ._token , methods = ['GET' ])
143- def shutdown ():
144- func = request .environ .get ('werkzeug.server.shutdown' )
145- if func is None :
146- raise RuntimeError ('Not running with the Werkzeug Server' )
147- func ()
148- return 'Server shutting down...'
149-
150142 # Register route that we can use to poll to see when server is running
151143 @self .server .route ('/_alive_' + JupyterDash ._token , methods = ['GET' ])
152144 def alive ():
@@ -225,7 +217,9 @@ def run_server(
225217 inline_exceptions = mode == "inline"
226218
227219 # Terminate any existing server using this port
228- self ._terminate_server_for_port (host , port )
220+ old_server = self ._server_threads .get ((host , port ))
221+ if old_server :
222+ old_server .kill ()
229223
230224 # Configure pathname prefix
231225 requests_pathname_prefix = self .config .get ('requests_pathname_prefix' , None )
@@ -297,12 +291,17 @@ def run_server(
297291 wait_exponential_max = 1000
298292 )
299293 def run ():
300- super_run_server (** kwargs )
294+ try :
295+ super_run_server (** kwargs )
296+ except SystemExit :
297+ pass
301298
302- thread = Thread (target = run )
299+ thread = StoppableThread (target = run )
303300 thread .setDaemon (True )
304301 thread .start ()
305302
303+ self ._server_threads [(host , port )] = thread
304+
306305 # Wait for server to start up
307306 alive_url = "http://{host}:{port}/_alive_{token}" .format (
308307 host = host , port = port , token = JupyterDash ._token
@@ -414,16 +413,6 @@ def _wrap_errors(error):
414413
415414 return html_str , 500
416415
417- @classmethod
418- def _terminate_server_for_port (cls , host , port ):
419- shutdown_url = "http://{host}:{port}/_shutdown_{token}" .format (
420- host = host , port = port , token = JupyterDash ._token
421- )
422- try :
423- response = requests .get (shutdown_url )
424- except Exception as e :
425- pass
426-
427416
428417def _custom_formatargvalues (
429418 args , varargs , varkw , locals ,
0 commit comments