From 37f289a9140f34598ffdd6f68681d359a1d31bb2 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:24:38 -0400
Subject: [PATCH 01/19] Update dash.py

---
 dash/dash.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/dash/dash.py b/dash/dash.py
index c0b6cb410d..9ee5bacfd6 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -15,7 +15,7 @@
 
 import flask
 from flask_compress import Compress
-from werkzeug.debug.tbtools import get_current_traceback
+from werkzeug.debug.tbtools import DebugTraceback
 from pkg_resources import get_distribution, parse_version
 from dash import dcc
 from dash import html
@@ -1757,18 +1757,18 @@ 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()):
                     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_full(), 500
 
         if debug and dev_tools.ui:
 

From 8a50189f6808df67b99d9fb664dfa5f23ddc0dcd Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:38:34 -0400
Subject: [PATCH 02/19] Update requires-all.txt

---
 requires-all.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/requires-all.txt b/requires-all.txt
index 92b8e8cedf..754b18d86c 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -30,7 +30,7 @@ PyYAML>=5.4.1
 diskcache>=5.2.1
 multiprocess>=0.70.12
 psutil>=5.8.0
-Flask>=1.0.4
+Flask>=1.0.4,<2.1.0
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 731d9e5f2026e2fa882573c28c42e5215714311c Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:38:55 -0400
Subject: [PATCH 03/19] Update requires-install.txt

---
 requires-install.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/requires-install.txt b/requires-install.txt
index 7e0ff3ec4f..bb9b2e4016 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,4 +1,4 @@
-Flask>=1.0.4
+Flask>=1.0.4,<2.1.0
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 107c074c5f91ef58de211e443cba0055c8f220d6 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:40:56 -0400
Subject: [PATCH 04/19] Update dash.py

---
 dash/dash.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/dash/dash.py b/dash/dash.py
index 9ee5bacfd6..c0b6cb410d 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -15,7 +15,7 @@
 
 import flask
 from flask_compress import Compress
-from werkzeug.debug.tbtools import DebugTraceback
+from werkzeug.debug.tbtools import get_current_traceback
 from pkg_resources import get_distribution, parse_version
 from dash import dcc
 from dash import html
@@ -1757,18 +1757,18 @@ def enable_dev_tools(
         if debug and dev_tools.prune_errors:
 
             @self.server.errorhandler(Exception)
-            def _wrap_errors(e):
+            def _wrap_errors(_):
                 # 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 = DebugTraceback(e)
+                tb = get_current_traceback()
                 skip = 0
                 for i, line in enumerate(tb.plaintext.splitlines()):
                     if "%% callback invoked %%" in line:
                         skip = int((i + 1) / 2)
                         break
-                return DebugTraceback(e, skip=skip).render_full(), 500
+                return get_current_traceback(skip=skip).render_full(), 500
 
         if debug and dev_tools.ui:
 

From 1c1a933163f756b416b791068cd896bdf06f9297 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:51:02 -0400
Subject: [PATCH 05/19] Update requires-install.txt

---
 requires-install.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/requires-install.txt b/requires-install.txt
index bb9b2e4016..36c5cb6f50 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,4 +1,5 @@
-Flask>=1.0.4,<2.1.0
+Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
+Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From c763231e4a924e981414a2355a09d54e8662091b Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:51:25 -0400
Subject: [PATCH 06/19] Update requires-all.txt

---
 requires-all.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/requires-all.txt b/requires-all.txt
index 754b18d86c..7dab592450 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -30,7 +30,8 @@ PyYAML>=5.4.1
 diskcache>=5.2.1
 multiprocess>=0.70.12
 psutil>=5.8.0
-Flask>=1.0.4,<2.1.0
+Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
+Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 225faba38672b5c924928dba76c2c464f8fd83ac Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 15:59:53 -0400
Subject: [PATCH 07/19] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b036f014cf..0b125d7f0d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 - [#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.
+- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0 and Werkzeug<2.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
 
 ## [2.3.0] - 2022-03-13
 

From 206b31d00e4a32a3419e15bb57efeeaec7b11453 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Mon, 28 Mar 2022 16:03:57 -0400
Subject: [PATCH 08/19] Pin `click<8.1.0` to retain Python 3.6 compatibility

---
 CHANGELOG.md         | 2 +-
 requires-all.txt     | 1 +
 requires-install.txt | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b125d7f0d..69522b31b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 - [#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.
-- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0 and Werkzeug<2.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
+- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0, Werkzeug<2.1.0, and click<8.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
 
 ## [2.3.0] - 2022-03-13
 
diff --git a/requires-all.txt b/requires-all.txt
index 7dab592450..e5e83c5c2e 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -32,6 +32,7 @@ multiprocess>=0.70.12
 psutil>=5.8.0
 Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
 Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
+click<8.1.0  # click 8.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0
diff --git a/requires-install.txt b/requires-install.txt
index 36c5cb6f50..6e61a438bb 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,5 +1,6 @@
 Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
 Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
+click<8.1.0  # click 8.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 2fc1e3dac6a0343406c907027fec44abe83ce503 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:58:58 -0400
Subject: [PATCH 09/19] Revert "Pin `click<8.1.0` to retain Python 3.6
 compatibility"

This reverts commit 206b31d00e4a32a3419e15bb57efeeaec7b11453.
---
 CHANGELOG.md         | 2 +-
 requires-all.txt     | 1 -
 requires-install.txt | 1 -
 3 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69522b31b2..0b125d7f0d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 - [#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.
-- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0, Werkzeug<2.1.0, and click<8.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
+- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0 and Werkzeug<2.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
 
 ## [2.3.0] - 2022-03-13
 
diff --git a/requires-all.txt b/requires-all.txt
index e5e83c5c2e..7dab592450 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -32,7 +32,6 @@ multiprocess>=0.70.12
 psutil>=5.8.0
 Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
 Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
-click<8.1.0  # click 8.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0
diff --git a/requires-install.txt b/requires-install.txt
index 6e61a438bb..36c5cb6f50 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,6 +1,5 @@
 Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
 Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
-click<8.1.0  # click 8.1.0 dropped support for Python 3.6
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From b5ec4f7342a1dd2e179276f634bac84bda29bdae Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:05 -0400
Subject: [PATCH 10/19] Revert "Update CHANGELOG.md"

This reverts commit 225faba38672b5c924928dba76c2c464f8fd83ac.
---
 CHANGELOG.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b125d7f0d..b036f014cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,6 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 - [#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.
-- [#1993](https://github.com/plotly/dash/pull/1993) Pin Flask<2.1.0 and Werkzeug<2.1.0 to retain Python 3.6 compatibility, resolving [#1992](https://github.com/plotly/dash/issues/1992).
 
 ## [2.3.0] - 2022-03-13
 

From c9b6af95ee4f3696373715b7be764608b6209b01 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:08 -0400
Subject: [PATCH 11/19] Revert "Update requires-all.txt"

This reverts commit c763231e4a924e981414a2355a09d54e8662091b.
---
 requires-all.txt | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/requires-all.txt b/requires-all.txt
index 7dab592450..754b18d86c 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -30,8 +30,7 @@ PyYAML>=5.4.1
 diskcache>=5.2.1
 multiprocess>=0.70.12
 psutil>=5.8.0
-Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
-Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
+Flask>=1.0.4,<2.1.0
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 89e9538f3b0ceec0824890cbebd538cb3468c079 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:09 -0400
Subject: [PATCH 12/19] Revert "Update requires-install.txt"

This reverts commit 1c1a933163f756b416b791068cd896bdf06f9297.
---
 requires-install.txt | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/requires-install.txt b/requires-install.txt
index 36c5cb6f50..bb9b2e4016 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,5 +1,4 @@
-Flask>=1.0.4,<2.1.0  # Flask 2.1.0 dropped support for Python 3.6
-Werkzeug<2.1.0  # Werkzeug 2.1.0 dropped support for Python 3.6
+Flask>=1.0.4,<2.1.0
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From a3d5e6d8fcc709f190cd05b887e3f68ce4284b93 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:10 -0400
Subject: [PATCH 13/19] Revert "Update dash.py"

This reverts commit 107c074c5f91ef58de211e443cba0055c8f220d6.
---
 dash/dash.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/dash/dash.py b/dash/dash.py
index c0b6cb410d..9ee5bacfd6 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -15,7 +15,7 @@
 
 import flask
 from flask_compress import Compress
-from werkzeug.debug.tbtools import get_current_traceback
+from werkzeug.debug.tbtools import DebugTraceback
 from pkg_resources import get_distribution, parse_version
 from dash import dcc
 from dash import html
@@ -1757,18 +1757,18 @@ 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()):
                     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_full(), 500
 
         if debug and dev_tools.ui:
 

From 8a7417683ce0d28ec109fd0cd4230bbbb6aa7d25 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:11 -0400
Subject: [PATCH 14/19] Revert "Update requires-install.txt"

This reverts commit 731d9e5f2026e2fa882573c28c42e5215714311c.
---
 requires-install.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/requires-install.txt b/requires-install.txt
index bb9b2e4016..7e0ff3ec4f 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -1,4 +1,4 @@
-Flask>=1.0.4,<2.1.0
+Flask>=1.0.4
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 87598a0f88106994385272f57702002d026bbcb1 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 08:59:12 -0400
Subject: [PATCH 15/19] Revert "Update requires-all.txt"

This reverts commit 8a50189f6808df67b99d9fb664dfa5f23ddc0dcd.
---
 requires-all.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/requires-all.txt b/requires-all.txt
index 754b18d86c..92b8e8cedf 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -30,7 +30,7 @@ PyYAML>=5.4.1
 diskcache>=5.2.1
 multiprocess>=0.70.12
 psutil>=5.8.0
-Flask>=1.0.4,<2.1.0
+Flask>=1.0.4
 flask-compress
 plotly>=5.0.0
 dash_html_components==2.0.0

From 1eb6fd8f78362ddcc6dd86f80b88572da39b9430 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 15:09:32 -0400
Subject: [PATCH 16/19] If `werkzeug<2.1.0`, mock minimal `DebugTraceback`

---
 dash/dash.py | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/dash/dash.py b/dash/dash.py
index 9ee5bacfd6..c647dcccc1 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -15,7 +15,32 @@
 
 import flask
 from flask_compress import Compress
-from werkzeug.debug.tbtools import DebugTraceback
+
+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
@@ -1764,11 +1789,16 @@ def _wrap_errors(e):
                 # skip anything.
                 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 DebugTraceback(e, 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:
 

From b2e5b67dac2ca9e24d7e133328f591b6e5584138 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 15:35:38 -0400
Subject: [PATCH 17/19] Upgrade black version in CI to be click-compatible

---
 requires-all.txt | 2 +-
 requires-ci.txt  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/requires-all.txt b/requires-all.txt
index 92b8e8cedf..9e376d465a 100644
--- a/requires-all.txt
+++ b/requires-all.txt
@@ -2,7 +2,7 @@
 redis>=3.5.3
 celery[redis]>=5.1.2
 # Dependencies used by CI on github.com/plotly/dash
-black==21.6b0
+black==22.3.0
 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..a2d25167fe 100644
--- a/requires-ci.txt
+++ b/requires-ci.txt
@@ -1,5 +1,5 @@
 # Dependencies used by CI on github.com/plotly/dash
-black==21.6b0
+black==22.3.0
 dash-flow-example==0.0.5
 dash-dangerously-set-inner-html
 flake8==3.9.2

From c1a9dbf61aea8bfcd15254513e55b75b0b1cc120 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 15:48:24 -0400
Subject: [PATCH 18/19] Condition black version on python version

---
 requires-all.txt | 3 ++-
 requires-ci.txt  | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/requires-all.txt b/requires-all.txt
index 9e376d465a..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==22.3.0
+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 a2d25167fe..c13a1aee10 100644
--- a/requires-ci.txt
+++ b/requires-ci.txt
@@ -1,5 +1,6 @@
 # Dependencies used by CI on github.com/plotly/dash
-black==22.3.0
+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

From 5b2c4d0e88d2001a677045fbd4be1a04f6d46e65 Mon Sep 17 00:00:00 2001
From: Deepyaman Datta <deepyaman.datta@utexas.edu>
Date: Tue, 29 Mar 2022 16:12:04 -0400
Subject: [PATCH 19/19] Black

---
 .../tests/integration/misc/conftest.py        |  8 ++---
 .../integration/misc/test_persistence.py      | 36 +++++++++----------
 .../tests/integration/misc/test_platter.py    |  2 +-
 .../dash-table/dash_table_base/Format.py      | 34 +++++++++---------
 .../tests/selenium/test_pagination.py         |  4 +--
 .../dash-table/tests/unit/format_test.py      |  4 +--
 dash/dash.py                                  |  1 +
 dash/development/base_component.py            |  2 +-
 .../dash_assets/test_dash_assets.py           | 16 ++++-----
 9 files changed, 54 insertions(+), 53 deletions(-)

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 c647dcccc1..007f9811ec 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -41,6 +41,7 @@ def render_debugger_html(
         ) -> str:
             return self._tb.render_full()
 
+
 from pkg_resources import get_distribution, parse_version
 from dash import dcc
 from dash import html
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/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"
