Skip to content

Commit 89973c0

Browse files
authored
Merge pull request #1995 from plotly/1992-fix-debugger
Fix werkzeug 2.1.0 import & dev tools error html rendering.
2 parents e87339f + 5e89d95 commit 89973c0

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
77
### Fixed
88

99
- [#1963](https://github.com/plotly/dash/pull/1963) Fix [#1780](https://github.com/plotly/dash/issues/1780) flask shutdown deprecation warning when running dashduo threaded tests.
10+
- [#1995](https://github.com/plotly/dash/pull/1995) Fix [#1992](https://github.com/plotly/dash/issues/1992) ImportError: cannot import name 'get_current_traceback' from 'werkzeug.debug.tbtools'.
1011

1112
## [2.3.0] - 2022-03-13
1213

dash/_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import logging
99
import io
1010
import json
11+
import secrets
12+
import string
1113
from functools import wraps
1214

1315
logger = logging.getLogger()
@@ -206,3 +208,9 @@ def _wrapper(*args, **kwargs):
206208
return _wrapper
207209

208210
return wrapper
211+
212+
213+
def gen_salt(chars):
214+
return "".join(
215+
secrets.choice(string.ascii_letters + string.digits) for _ in range(chars)
216+
)

dash/dash-renderer/src/components/error/FrontEnd/FrontEndError.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function UnconnectedErrorContent({error, base}) {
110110
)}
111111
{/* Backend Error */}
112112
{typeof error.html !== 'string' ? null : error.html.indexOf(
113-
'<!DOCTYPE HTML'
113+
'<!DOCTYPE'
114114
) === 0 ? (
115115
<div className='dash-be-error__st'>
116116
<div className='dash-backend-error'>

dash/dash.py

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
import mimetypes
1212
import hashlib
1313
import base64
14+
import traceback
1415
from urllib.parse import urlparse
1516

1617
import flask
1718
from flask_compress import Compress
18-
from werkzeug.debug.tbtools import get_current_traceback
19+
1920
from pkg_resources import get_distribution, parse_version
2021
from dash import dcc
2122
from dash import html
@@ -48,6 +49,7 @@
4849
patch_collections_abc,
4950
split_callback_id,
5051
to_json,
52+
gen_salt,
5153
)
5254
from . import _callback
5355
from . import _get_paths
@@ -102,6 +104,42 @@
102104
_re_renderer_scripts_id = 'id="_dash-renderer', "new DashRenderer"
103105

104106

107+
def _get_traceback(secret, error: Exception):
108+
109+
try:
110+
# pylint: disable=import-outside-toplevel
111+
from werkzeug.debug import tbtools
112+
except ImportError:
113+
tbtools = None
114+
115+
def _get_skip(text, divider=2):
116+
skip = 0
117+
for i, line in enumerate(text):
118+
if "%% callback invoked %%" in line:
119+
skip = int((i + 1) / divider)
120+
break
121+
return skip
122+
123+
# werkzeug<2.1.0
124+
if hasattr(tbtools, "get_current_traceback"):
125+
tb = tbtools.get_current_traceback()
126+
skip = _get_skip(tb.plaintext.splitlines())
127+
return tbtools.get_current_traceback(skip=skip).render_full()
128+
129+
if hasattr(tbtools, "DebugTraceback"):
130+
tb = tbtools.DebugTraceback(error) # pylint: disable=no-member
131+
skip = _get_skip(tb.render_traceback_text().splitlines())
132+
133+
# pylint: disable=no-member
134+
return tbtools.DebugTraceback(error, skip=skip).render_debugger_html(
135+
True, secret, True
136+
)
137+
138+
tb = traceback.format_exception(type(error), error, error.__traceback__)
139+
skip = _get_skip(tb, 1)
140+
return tb[0] + "".join(tb[skip:])
141+
142+
105143
class _NoUpdate:
106144
# pylint: disable=too-few-public-methods
107145
pass
@@ -1756,19 +1794,16 @@ def enable_dev_tools(
17561794

17571795
if debug and dev_tools.prune_errors:
17581796

1797+
secret = gen_salt(20)
1798+
17591799
@self.server.errorhandler(Exception)
1760-
def _wrap_errors(_):
1800+
def _wrap_errors(error):
17611801
# find the callback invocation, if the error is from a callback
17621802
# and skip the traceback up to that point
17631803
# if the error didn't come from inside a callback, we won't
17641804
# skip anything.
1765-
tb = get_current_traceback()
1766-
skip = 0
1767-
for i, line in enumerate(tb.plaintext.splitlines()):
1768-
if "%% callback invoked %%" in line:
1769-
skip = int((i + 1) / 2)
1770-
break
1771-
return get_current_traceback(skip=skip).render_full(), 500
1805+
tb = _get_traceback(secret, error)
1806+
return tb, 500
17721807

17731808
if debug and dev_tools.ui:
17741809

0 commit comments

Comments
 (0)