Repository: plotly/dash

Issue:
[Feature Request] Python 3.10 support
**Is your feature request related to a problem? Please describe.**
Hi, I'm wondering if Dash supports Python 3.10 or if this is on the roadmap. Thanks for all your great work!

**Describe the solution you'd like**
As a user of Dash, I would like to be able to install Dash and/or Plotly in a Python 3.10 environment.

**Describe alternatives you've considered**
I tried [searching the forums](https://community.plotly.com/search?q=python%203.10), but didn't find any results. I haven't tried building it myself yet, but plan to.

**Additional context**
n/a



Discussion:
We haven't tested 3.10 explicitly (which is why 3.10 isn't listed in the classifiers), but AFAIK we have never had issues with Python minor version forward compatibility. Is there anything preventing you from installing Dash in a Python 3.10 environment with a simple `pip install dash`?
Got it, was just wondering. I was able to install via poetry (`poetry add dash`) just fine, so it seems like it's probably okay! 
Great! We'll leave this issue open until we get around to explicitly testing (probably just by bumping the 3.9 tests on CI to 3.10) and in case anyone else encounters issues running Dash in 3.10, but I'm glad to know on the surface it works.
I have not had any issues with 3.10.0, for the past few weeks now. Looking forward to speed improvements in 3.10.1 soon.

dash 2.0.0
dash-bootstrap-components 1.0.2

I am currently using python 3.10.1 together with dash 2.0.0 and faced one issue. When trying to add a horizontal line via `html.Hr`, I get the following error:

```
File "/Users/me/Library/Caches/pypoetry/virtualenvs/krb-digital-oscilloscope-Kbg24TcP-py3.10/lib/python3.10/site-packages/dash/_validate.py", line 265, in _validate_value
    if not isinstance(child, (tuple, collections.MutableSequence)):
AttributeError: module 'collections' has no attribute 'MutableSequence'
```

If I see correctly, this has already been fixed 4 months ago by changing the import from `collections.MutableSequence` to `collections.abc.MutableSequence` (see [here](https://github.com/plotly/dash/blob/0f1b299dce356dbec6c669731663ba7ce6ef057d/dash/_validate.py#L1)), but has not been released yet. 

Do you have an idea when you want to release a new version containing this fix?
> Great! We'll leave this issue open until we get around to explicitly testing (probably just by bumping the 3.9 tests on CI to 3.10) and in case anyone else encounters issues running Dash in 3.10, but I'm glad to know on the surface it works.

Hi - has Dash testing under python 3.10 made it into your CI or is it in the roadmap?  Just curious about when we could expect official support for this version of python.
I think at this point we can safely bump the 3.9 tests in the [CircleCI config](https://github.com/plotly/dash/blob/dev/.circleci/config.yml) to 3.10 (leaving the 3.6 tests in place) and add 3.10 to the classifiers. Should be straightforward based on the [cimg/python images](https://circleci.com/developer/images/image/cimg/python?utm_source=google&utm_medium=sem&utm_campaign=sem-google-dg--uscan-en-dsa-maxConv-auth-nb&utm_term=g_-_c__dsa_&utm_content=&gclid=Cj0KCQjw0oyYBhDGARIsAMZEuMuAAeJBr8N__ST77GhWtu5TT-YZr5iBZd9Qy11pQvkxmu_ZItShMlYaAsOrEALw_wcB) if anyone would like to contribute this change, otherwise we'll try to include it next time we do a round of maintenance upgrades.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -68,6 +68,7 @@ def read_req_file(req_type):
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
         "Topic :: Database :: Front-Ends",
         "Topic :: Office/Business :: Financial :: Spreadsheet",
         "Topic :: Scientific/Engineering :: Visualization",


Test patch:
diff --git a/dash/testing/browser.py b/dash/testing/browser.py
--- a/dash/testing/browser.py
+++ b/dash/testing/browser.py
@@ -159,7 +159,10 @@ def percy_snapshot(
         """
         if widths is None:
             widths = [1280]
-        snapshot_name = f"{name} - py{sys.version_info.major}.{sys.version_info.minor}"
+
+        # py3.9 hardcoded here to keep snapshot names the same accorss
+        # future python upgrades
+        snapshot_name = f"{name} - py3.9"
         logger.info("taking snapshot name => %s", snapshot_name)
         try:
             if wait_for_callbacks: