diff --git a/components/dash-core-components/tests/integration/misc/conftest.py b/components/dash-core-components/tests/integration/misc/conftest.py index 2374f573e7..07c4451592 100644 --- a/components/dash-core-components/tests/integration/misc/conftest.py +++ b/components/dash-core-components/tests/integration/misc/conftest.py @@ -6,10 +6,10 @@ OPTIONS = [ {"label": "New York City", "value": "NYC"}, - {"label": u"Montréal", "value": "MTL"}, + {"label": "Montréal", "value": "MTL"}, {"label": "San Francisco", "value": "SF"}, - {"label": u"北京", "value": u"帝都"}, - {"label": u"臺北", "value": u"天龍國"}, + {"label": "北京", "value": "帝都"}, + {"label": "臺北", "value": "天龍國"}, ] @@ -107,7 +107,7 @@ def platter_app(): id="graph", figure={ "data": [{"x": [1, 2, 3], "y": [4, 1, 4]}], - "layout": {"title": u"北京"}, + "layout": {"title": "北京"}, }, ), html.Div( diff --git a/components/dash-core-components/tests/integration/misc/test_persistence.py b/components/dash-core-components/tests/integration/misc/test_persistence.py index 1559d57815..4d7f796ca3 100644 --- a/components/dash-core-components/tests/integration/misc/test_persistence.py +++ b/components/dash-core-components/tests/integration/misc/test_persistence.py @@ -13,11 +13,11 @@ def test_msps001_basic_persistence(dash_dcc): dcc.Checklist( id="checklist", options=[ - {"label": u"Slow 🐢", "value": u"🐢"}, - {"label": u"Fast 🏎️", "value": u"🏎️"}, - {"label": u"Faster 🚀", "value": u"🚀"}, + {"label": "Slow 🐢", "value": "🐢"}, + {"label": "Fast 🏎️", "value": "🏎️"}, + {"label": "Faster 🚀", "value": "🚀"}, ], - value=[u"🏎️"], + value=["🏎️"], persistence=True, ), dcc.DatePickerRange( @@ -35,21 +35,21 @@ def test_msps001_basic_persistence(dash_dcc): dcc.Dropdown( id="dropdownsingle", options=[ - {"label": u"One 1️⃣", "value": u"1️⃣"}, - {"label": u"Two 2️⃣", "value": u"2️⃣"}, - {"label": u"Three 3️⃣", "value": u"3️⃣"}, + {"label": "One 1️⃣", "value": "1️⃣"}, + {"label": "Two 2️⃣", "value": "2️⃣"}, + {"label": "Three 3️⃣", "value": "3️⃣"}, ], - value=u"2️⃣", + value="2️⃣", persistence=True, ), dcc.Dropdown( id="dropdownmulti", options=[ - {"label": u"Four 4️⃣", "value": u"4️⃣"}, - {"label": u"Five 5️⃣", "value": u"5️⃣"}, - {"label": u"Six 6️⃣", "value": u"6️⃣"}, + {"label": "Four 4️⃣", "value": "4️⃣"}, + {"label": "Five 5️⃣", "value": "5️⃣"}, + {"label": "Six 6️⃣", "value": "6️⃣"}, ], - value=[u"4️⃣"], + value=["4️⃣"], multi=True, persistence=True, ), @@ -104,12 +104,12 @@ def make_output(*args): return json.dumps(args) initial_settings = [ - [u"🏎️"], + ["🏎️"], "2017-08-21", "2024-04-08", "2019-01-01", - u"2️⃣", - [u"4️⃣"], + "2️⃣", + ["4️⃣"], "yes", "b", [3, 7], @@ -153,12 +153,12 @@ def make_output(*args): dash_dcc.find_element("#textarea").send_keys(Keys.ENTER + "who's there?") edited_settings = [ - [u"🏎️", u"🚀"], + ["🏎️", "🚀"], "2019-05-04", "2019-05-14", "2019-01-20", - u"1️⃣", - [u"4️⃣", u"6️⃣"], + "1️⃣", + ["4️⃣", "6️⃣"], "yes maybe", "r", [5, 8], diff --git a/components/dash-core-components/tests/integration/misc/test_platter.py b/components/dash-core-components/tests/integration/misc/test_platter.py index d3878db19b..593fe399bd 100644 --- a/components/dash-core-components/tests/integration/misc/test_platter.py +++ b/components/dash-core-components/tests/integration/misc/test_platter.py @@ -16,7 +16,7 @@ def test_mspl001_dcc_components_platter(platter_app, dash_dcc): dash_dcc.percy_snapshot("gallery") - dash_dcc.find_element("#dropdown .Select-input input").send_keys(u"北") + dash_dcc.find_element("#dropdown .Select-input input").send_keys("北") dash_dcc.percy_snapshot("gallery - chinese character") text_input = dash_dcc.find_element("#textinput") diff --git a/components/dash-table/dash_table_base/Format.py b/components/dash-table/dash_table_base/Format.py index 8dd12638cb..39c39d933a 100644 --- a/components/dash-table/dash_table_base/Format.py +++ b/components/dash-table/dash_table_base/Format.py @@ -17,23 +17,23 @@ def get_named_tuple(name, dict): Prefix = get_named_tuple( "prefix", { - "yocto": 10 ** -24, - "zepto": 10 ** -21, - "atto": 10 ** -18, - "femto": 10 ** -15, - "pico": 10 ** -12, - "nano": 10 ** -9, - "micro": 10 ** -6, - "milli": 10 ** -3, + "yocto": 10**-24, + "zepto": 10**-21, + "atto": 10**-18, + "femto": 10**-15, + "pico": 10**-12, + "nano": 10**-9, + "micro": 10**-6, + "milli": 10**-3, "none": None, - "kilo": 10 ** 3, - "mega": 10 ** 6, - "giga": 10 ** 9, - "tera": 10 ** 12, - "peta": 10 ** 15, - "exa": 10 ** 18, - "zetta": 10 ** 21, - "yotta": 10 ** 24, + "kilo": 10**3, + "mega": 10**6, + "giga": 10**9, + "tera": 10**12, + "peta": 10**15, + "exa": 10**18, + "zetta": 10**21, + "yotta": 10**24, }, ) @@ -121,7 +121,7 @@ def _validate_named(self, value, named_values): raise TypeError("expected value to be one of", str(list(named_values))) def _validate_string(self, value): - if not isinstance(value, (str, u"".__class__)): + if not isinstance(value, (str, "".__class__)): raise TypeError("expected value to be a string") # Specifier diff --git a/components/dash-table/tests/selenium/test_pagination.py b/components/dash-table/tests/selenium/test_pagination.py index 98765ec31e..3e427a3712 100644 --- a/components/dash-table/tests/selenium/test_pagination.py +++ b/components/dash-table/tests/selenium/test_pagination.py @@ -216,7 +216,7 @@ def get_app2(): id="table", page_size=5, columns=[{"name": "i", "id": "i"}, {"name": "square", "id": "square"}], - data=[{"i": i, "square": i ** 2} for i in range(50 + 1)], + data=[{"i": i, "square": i**2} for i in range(50 + 1)], page_current=5, ), dcc.Graph(), @@ -226,7 +226,7 @@ def get_app2(): @app.callback(Output("table", "data"), Input("button", "n_clicks")) def update_table_data(n): return ( - [{"i": i, "square": i ** 2} for i in range(20 + 1)] + [{"i": i, "square": i**2} for i in range(20 + 1)] if n > 0 else dash.no_update ) diff --git a/components/dash-table/tests/unit/format_test.py b/components/dash-table/tests/unit/format_test.py index aac381c907..e26d895f31 100644 --- a/components/dash-table/tests/unit/format_test.py +++ b/components/dash-table/tests/unit/format_test.py @@ -146,13 +146,13 @@ def test_invalid_precision_type(self): self.assertRaises(TypeError, Format().precision, 7.7) def test_valid_prefix_number(self): - Format().si_prefix(10 ** -24) + Format().si_prefix(10**-24) def test_valid_prefix_named(self): Format().si_prefix(f.Prefix.micro) def test_invalid_prefix_number(self): - self.assertRaises(TypeError, Format().si_prefix, 10 ** -23) + self.assertRaises(TypeError, Format().si_prefix, 10**-23) def test_invalid_prefix_type(self): self.assertRaises(TypeError, Format().si_prefix, "10**-23") diff --git a/dash/dash.py b/dash/dash.py index c0b6cb410d..007f9811ec 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -15,7 +15,33 @@ import flask from flask_compress import Compress -from werkzeug.debug.tbtools import get_current_traceback + +try: + from werkzeug.debug.tbtools import DebugTraceback +except ImportError: + # If `werkzeug<2.1.0`, mock a minimally-functional `DebugTraceback`. + from werkzeug.debug.tbtools import get_current_traceback + + class DebugTraceback: + __slots__ = ("_tb",) + + def __init__( + self, + exc: BaseException, + *, + skip: int = 0, + ): + self._tb = get_current_traceback(skip=skip) + + def render_traceback_text(self) -> str: + return self._tb.plaintext + + def render_debugger_html( + self, evalex: bool, secret: str, evalex_trusted: bool + ) -> str: + return self._tb.render_full() + + from pkg_resources import get_distribution, parse_version from dash import dcc from dash import html @@ -1757,18 +1783,23 @@ def enable_dev_tools( if debug and dev_tools.prune_errors: @self.server.errorhandler(Exception) - def _wrap_errors(_): + def _wrap_errors(e): # find the callback invocation, if the error is from a callback # and skip the traceback up to that point # if the error didn't come from inside a callback, we won't # skip anything. - tb = get_current_traceback() + tb = DebugTraceback(e) skip = 0 - for i, line in enumerate(tb.plaintext.splitlines()): + for i, line in enumerate(tb.render_traceback_text().splitlines()): if "%% callback invoked %%" in line: skip = int((i + 1) / 2) break - return get_current_traceback(skip=skip).render_full(), 500 + return ( + DebugTraceback(e, skip=skip).render_debugger_html( + evalex=False, secret=None, evalex_trusted=True + ), + 500, + ) if debug and dev_tools.ui: diff --git a/dash/development/base_component.py b/dash/development/base_component.py index 9cf84010a3..7ff1c24662 100644 --- a/dash/development/base_component.py +++ b/dash/development/base_component.py @@ -196,7 +196,7 @@ def _set_random_id(self): """ ) - v = str(uuid.UUID(int=rd.randint(0, 2 ** 128))) + v = str(uuid.UUID(int=rd.randint(0, 2**128))) setattr(self, "id", v) return v diff --git a/requires-all.txt b/requires-all.txt index 92b8e8cedf..ea908475a0 100644 --- a/requires-all.txt +++ b/requires-all.txt @@ -2,7 +2,8 @@ redis>=3.5.3 celery[redis]>=5.1.2 # Dependencies used by CI on github.com/plotly/dash -black==21.6b0 +black==21.6b0;python_version<"3.7" +black==22.3.0;python_version>="3.7" dash-flow-example==0.0.5 dash-dangerously-set-inner-html flake8==3.9.2 diff --git a/requires-ci.txt b/requires-ci.txt index dbeb8476c0..c13a1aee10 100644 --- a/requires-ci.txt +++ b/requires-ci.txt @@ -1,5 +1,6 @@ # Dependencies used by CI on github.com/plotly/dash -black==21.6b0 +black==21.6b0;python_version<"3.7" +black==22.3.0;python_version>="3.7" dash-flow-example==0.0.5 dash-dangerously-set-inner-html flake8==3.9.2 diff --git a/tests/integration/dash_assets/test_dash_assets.py b/tests/integration/dash_assets/test_dash_assets.py index 07fe3b01c9..dc55e07d86 100644 --- a/tests/integration/dash_assets/test_dash_assets.py +++ b/tests/integration/dash_assets/test_dash_assets.py @@ -41,14 +41,14 @@ def test_dada001_assets(dash_duo): tested = json.loads(dash_duo.wait_for_element("#tested").text) order = [ - u"load_first", - u"load_after", - u"load_after1", - u"load_after10", - u"load_after11", - u"load_after2", - u"load_after3", - u"load_after4", + "load_first", + "load_after", + "load_after1", + "load_after10", + "load_after11", + "load_after2", + "load_after3", + "load_after4", ] assert order == tested, "the content and order is expected"