1
1
import dash
2
2
import os
3
3
import requests
4
- from flask import request
5
4
import flask .cli
6
- from threading import Thread
7
5
from retrying import retry
8
6
import io
9
7
import re
19
17
import uuid
20
18
21
19
from .comms import _dash_comm , _jupyter_config , _request_jupyter_config
20
+ from ._stoppable_thread import StoppableThread
22
21
23
22
24
23
def _get_skip (error : Exception ):
25
24
tb = traceback .format_exception (type (error ), error , error .__traceback__ )
26
25
skip = 0
27
- for i , line in enumerate (text ):
26
+ for i , line in enumerate (tb ):
28
27
if "%% callback invoked %%" in line :
29
28
skip = i + 1
30
29
break
@@ -49,6 +48,8 @@ class JupyterDash(dash.Dash):
49
48
_in_colab = "google.colab" in sys .modules
50
49
_token = str (uuid .uuid4 ())
51
50
51
+ _server_threads = {}
52
+
52
53
@classmethod
53
54
def infer_jupyter_proxy_config (cls ):
54
55
"""
@@ -138,15 +139,6 @@ def __init__(self, name=None, server_url=None, **kwargs):
138
139
139
140
self .server_url = server_url
140
141
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
-
150
142
# Register route that we can use to poll to see when server is running
151
143
@self .server .route ('/_alive_' + JupyterDash ._token , methods = ['GET' ])
152
144
def alive ():
@@ -225,7 +217,9 @@ def run_server(
225
217
inline_exceptions = mode == "inline"
226
218
227
219
# 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 ()
229
223
230
224
# Configure pathname prefix
231
225
requests_pathname_prefix = self .config .get ('requests_pathname_prefix' , None )
@@ -297,12 +291,17 @@ def run_server(
297
291
wait_exponential_max = 1000
298
292
)
299
293
def run ():
300
- super_run_server (** kwargs )
294
+ try :
295
+ super_run_server (** kwargs )
296
+ except SystemExit :
297
+ pass
301
298
302
- thread = Thread (target = run )
299
+ thread = StoppableThread (target = run )
303
300
thread .setDaemon (True )
304
301
thread .start ()
305
302
303
+ self ._server_threads [(host , port )] = thread
304
+
306
305
# Wait for server to start up
307
306
alive_url = "http://{host}:{port}/_alive_{token}" .format (
308
307
host = host , port = port , token = JupyterDash ._token
@@ -414,16 +413,6 @@ def _wrap_errors(error):
414
413
415
414
return html_str , 500
416
415
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
-
427
416
428
417
def _custom_formatargvalues (
429
418
args , varargs , varkw , locals ,
0 commit comments