diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 7387865..383a84d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,6 +1,6 @@
 ---
 name: Bug report
-about: Something that does not works as expected
+about: Something that does not work as expected
 title: ""
 labels: bug:normal
 assignees: ''
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4e4e0d6..e540913 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -14,9 +14,12 @@ much about the checklist - we will help you get started.
       in message body
 - [ ] added news fragment in [changelog folder](../tree/master/docs/changelog)
   * fragment name: `<issue number>.<type>.rst` for example (588.bugfix.rst)
-  * `<type>` is must be one of `bugfix`, `feature`, `deprecation`,`breaking`, `doc`, `misc`
+  * `<type>` is must be one of `bugfix`, `feature`, `deprecation`, `breaking`, `doc`, `misc`
   * if PR has no issue: consider creating one first or change it to the PR number after creating the PR
-  * "sign" fragment with "by :user:`<your username>`"
-  * please use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files - by :user:`superuser`."
+  * "sign" fragment with ```-- by :user:`<your username>`.```
+  * please, use full sentences with correct case and punctuation, for example:
+    ```rst
+    Fixed an issue with non-ascii contents in doctest text files -- by :user:`superuser`.
+    ```
   * also see [examples](../tree/master/docs/changelog)
 - [ ] added yourself to `CONTRIBUTORS` (preserving alphabetical order)
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
new file mode 100644
index 0000000..d10df54
--- /dev/null
+++ b/.github/workflows/check.yml
@@ -0,0 +1,161 @@
+name: check
+on:
+  push:
+  pull_request:
+  schedule:
+    - cron: "0 8 * * *"
+
+concurrency:
+  group: check-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  test:
+    name: test ${{ matrix.py }} - ${{ matrix.os }}
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        py:
+          - "3.10"
+          - "pypy-3.7-v7.3.7"  # ahead to start it earlier because takes longer
+          - "pypy-2.7-v7.3.6"  # ahead to start it earlier because takes longer
+          - "3.9"
+          - "3.8"
+          - "3.7"
+          - "3.6"
+          - "3.5"
+          - "2.7"
+        os:
+          - ubuntu-20.04
+          - windows-2022
+          - macos-10.15
+
+    steps:
+      - name: Setup python for tox
+        uses: actions/setup-python@v2
+        with:
+          python-version: "3.10"
+      - name: Install tox
+        run: python -m pip install tox
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - name: Setup python for test ${{ matrix.py }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.py }}
+      - name: Pick environment to run
+        run: |
+          import codecs
+          import os
+          import platform
+          import sys
+          cpy = platform.python_implementation() == "CPython"
+          base =("{}{}{}" if cpy else "{}{}").format("py" if cpy else "pypy", *sys.version_info[0:2])
+          env = "TOXENV={}\n".format(base)
+          print("Picked:\n{}for{}".format(env, sys.version))
+          with codecs.open(os.environ["GITHUB_ENV"], "a", "utf-8") as file_handler:
+               file_handler.write(env)
+        shell: python
+      - name: Setup test suite
+        run: tox -vv --notest
+      - name: Run test suite
+        run: tox --skip-pkg-install
+        env:
+          PYTEST_ADDOPTS: "-vv --durations=20"
+          CI_RUN: "yes"
+          DIFF_AGAINST: HEAD
+      - name: Rename coverage report file
+        run: import os; import sys; os.rename(".tox/.coverage.{}".format(os.environ['TOXENV']), ".tox/.coverage.{}-{}.format(os.environ['TOXENV'], sys.platform)")
+        shell: python
+      - name: Upload coverage data
+        uses: actions/upload-artifact@v2
+        with:
+          name: coverage-data
+          path: ".tox/.coverage.*"
+
+  coverage:
+    name: Combine coverage
+    runs-on: ubuntu-latest
+    needs: test
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - uses: actions/setup-python@v2
+        with:
+          python-version: "3.10"
+      - name: Install tox
+        run: python -m pip install tox
+      - name: Setup coverage tool
+        run: tox -e coverage --notest
+      - name: Install package builder
+        run: python -m pip install build
+      - name: Build package
+        run: pyproject-build --wheel .
+      - name: Download coverage data
+        uses: actions/download-artifact@v2
+        with:
+          name: coverage-data
+          path: .tox
+      - name: Combine and report coverage
+        run: tox -e coverage
+      - name: Upload HTML report
+        uses: actions/upload-artifact@v2
+        with:
+          name: html-report
+          path: .tox/htmlcov
+
+  check:
+    name: ${{ matrix.tox_env }} - ${{ matrix.os }}
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - ubuntu-20.04
+          - windows-2022
+        tox_env:
+          - dev
+          - docs
+          - readme
+        exclude:
+          - { os: windows-2022, tox_env: readme }
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - name: Setup Python "3.10"
+        uses: actions/setup-python@v2
+        with:
+          python-version: "3.10"
+      - name: Install tox
+        run: python -m pip install tox
+      - name: Setup test suite
+        run: tox -vv --notest -e ${{ matrix.tox_env }}
+      - name: Run test suite
+        run: tox --skip-pkg-install -e ${{ matrix.tox_env }}
+
+  publish:
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
+    needs: [ check, coverage ]
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Setup python to build package
+        uses: actions/setup-python@v2
+        with:
+          python-version: "3.10"
+      - name: Install build
+        run: python -m pip install build
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - name: Build sdist and wheel
+        run: python -m build -s -w . -o dist
+      - name: Publish to PyPi
+        uses: pypa/gh-action-pypi-publish@master
+        with:
+          skip_existing: true
+          user: __token__
+          password: ${{ secrets.pypi_password }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 70341e6..28b8d59 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,8 +1,6 @@
-default_language_version:
-  python: python3
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.4.0
+    rev: v4.1.0
     hooks:
       - id: check-ast
       - id: check-builtin-literals
@@ -14,45 +12,43 @@ repos:
       - id: end-of-file-fixer
       - id: trailing-whitespace
   - repo: https://github.com/asottile/pyupgrade
-    rev: v2.7.4
+    rev: v2.30.0
     hooks:
       - id: pyupgrade
   - repo: https://github.com/PyCQA/isort
-    rev: 5.7.0
+    rev: 5.10.1
     hooks:
       - id: isort
   - repo: https://github.com/psf/black
-    rev: 20.8b1
+    rev: 21.12b0
     hooks:
       - id: black
-        args:
-          - --safe
-        language_version: python3.8
+        args: [ --safe ]
   - repo: https://github.com/asottile/blacken-docs
-    rev: v1.9.1
+    rev: v1.12.0
     hooks:
       - id: blacken-docs
-        additional_dependencies:
-          - black==20.8b1
-        language_version: python3.8
+        additional_dependencies: [ black==21.12b0 ]
   - repo: https://github.com/pre-commit/pygrep-hooks
-    rev: v1.7.0
+    rev: v1.9.0
     hooks:
       - id: rst-backticks
+  - repo: https://github.com/tox-dev/tox-ini-fmt
+    rev: "0.5.1"
+    hooks:
+      - id: tox-ini-fmt
+        args: [ "-p", "fix_lint" ]
   - repo: https://github.com/asottile/setup-cfg-fmt
-    rev: v1.16.0
+    rev: v1.20.0
     hooks:
       - id: setup-cfg-fmt
-        args:
-          - --min-py3-version
-          - "3.4"
-  - repo: https://gitlab.com/pycqa/flake8
-    rev: 3.8.4
+        args: [ --min-py3-version, "3.5", "--max-py-version", "3.10" ]
+  - repo: https://github.com/PyCQA/flake8
+    rev: 4.0.1
     hooks:
       - id: flake8
         additional_dependencies:
-          - flake8-bugbear == 20.11.1
-        language_version: python3.8
+          - flake8-bugbear==21.11.29
   - repo: local
     hooks:
       - id: changelogs-rst
@@ -64,3 +60,9 @@ repos:
         exclude: >-
           ^docs/changelog/(\d+\.(bugfix|feature|deprecation|breaking|doc|misc).rst|README.rst|template.jinja2)
         files: ^docs/changelog/
+      - id: changelogs-user-role
+        name: changelog files have a non-broken :user:`name` role
+        language: pygrep
+        entry: :user:([^`]+`?|`[^`]+[\s,])
+        pass_filenames: true
+        types: [file, rst]
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000..8f8b623
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,18 @@
+version: 2
+build:
+  os: ubuntu-20.04
+  tools:
+    python: "3.10"
+formats:
+  - htmlzip
+  - epub
+  - pdf
+python:
+   install:
+      - method: pip
+        path: .
+        extra_requirements: ["docs"]
+sphinx:
+  builder: html
+  configuration: docs/conf.py
+  fail_on_warning: true
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 1e085ba..3b2700d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -4,10 +4,12 @@ Alexander Loechel
 Alexander Schepanovski
 Alexandre Conrad
 Allan Feldman
+Andrey Bienkowski
 Andrii Soldatenko
 Andrzej Klajnert
 Anthon van der Neuth
 Anthony Sottile
+Antoine Dechaume
 Anudit Nagar
 Ashley Whetter
 Asmund Grammeltwedt
@@ -18,6 +20,7 @@ Bastien Vallet
 Benoit Pierre
 Bernat Gabor
 Brett Langdon
+Brett Smith
 Bruno Oliveira
 Carl Meyer
 Charles Brunet
@@ -31,6 +34,7 @@ David Diaz
 Ederag
 Eli Collins
 Eugene Yunak
+Felix Hildén
 Fernando L. Pereira
 Florian Bruhin
 Florian Preinstorfer
@@ -40,13 +44,16 @@ Gleb Nikonorov
 Gonéri Le Bouder
 Hazal Ozturk
 Henk-Jaap Wagenaar
+Hugo van Kemenade
 Ian Stapleton Cordasco
 Igor Duarte Cardoso
 Ilya Kulakov
 Ionel Maries Cristian
+Isaac Pedisich
 Itxaka Serrano
 Jake Windle
 Jannis Leidel
+Jesse Schwartzentruber
 Joachim Brandon LeBlanc
 Johannes Christ
 John Mark Vandenberg
@@ -57,7 +64,9 @@ Joshua Hesketh
 Julian Krause
 Jürgen Gmach
 Jurko Gospodnetić
+Karthikeyan Singaravelan
 Krisztian Fekete
+Kian-Meng Ang
 Laszlo Vasko
 Lukasz Balcerzak
 Lukasz Rogalski
@@ -92,8 +101,10 @@ Philip Thiem
 Pierre-Jean Campigotto
 Pierre-Luc Tessier Gagné
 Prakhar Gurunani
+Rahul Bangar
 Ronald Evers
 Ronny Pfannschmidt
+Ryuichi Ohori
 Selim Belhaouane
 Sorin Sbarnea
 Sridhar Ratnakumar
@@ -104,6 +115,7 @@ Tim Laurence
 Tyagraj Desigar
 Usama Sadiq
 Ville Skyttä
+Vincent Vanlaer
 Vlastimil Zíma
 Xander Johnson
 anatoly techtonik
diff --git a/PKG-INFO b/PKG-INFO
index f49c4b9..c922307 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,124 +1,15 @@
 Metadata-Version: 2.1
 Name: tox
-Version: 3.21.4
+Version: 3.24.5
 Summary: tox is a generic virtualenv management and test command line tool
-Home-page: http://tox.readthedocs.org
+Home-page: https://tox.readthedocs.io
 Author: Holger Krekel, Oliver Bestwalter, Bernát Gábor and others
 Maintainer: Bernat Gabor, Oliver Bestwalter, Anthony Asottile
 Maintainer-email: tox-dev@python.org
 License: MIT
 Project-URL: Source, https://github.com/tox-dev/tox
 Project-URL: Tracker, https://github.com/tox-dev/tox/issues
-Description: ![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)
-        [![Supported Python
-        versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/)
-        [![Azure Pipelines build
-        status](https://dev.azure.com/toxdev/tox/_apis/build/status/tox%20ci?branchName=master)](https://dev.azure.com/toxdev/tox/_build/latest?definitionId=9&branchName=master)
-        [![Documentation
-        status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest)
-        [![Code style:
-        black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
-        [![Downloads](https://pepy.tech/badge/tox/month)](https://pepy.tech/project/tox/month)
-        
-        <a href="https://tox.readthedocs.io">
-            <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/_static/img/tox.png"
-                 alt="tox logo"
-                 height="150px"
-                 align="right">
-        </a>
-        
-        # tox automation project
-        
-        **Command line driven CI frontend and development task automation tool**
-        
-        At its core tox provides a convenient way to run arbitrary commands in isolated environments to serve as a single entry
-        point for build, test and release activities.
-        
-        tox is highly [configurable](https://tox.readthedocs.io/en/latest/config.html) and
-        [pluggable](https://tox.readthedocs.io/en/latest/plugins.html).
-        
-        ## Example: run tests with Python 3.7 and Python 3.8
-        
-        tox is mainly used as a command line tool and needs a `tox.ini` or a `tool.tox` section in `pyproject.toml` containing
-        the configuration.
-        
-        To test a simple project that has some tests, here is an example with a `tox.ini` in the root of the project:
-        
-        ```{.sourceCode .ini}
-        [tox]
-        envlist = py37,py38
-        
-        [testenv]
-        deps = pytest
-        commands = pytest
-        ```
-        
-        ```{.sourceCode .console}
-        $ tox
-        
-        [lots of output from what tox does]
-        [lots of output from commands that were run]
-        
-        __________________ summary _________________
-          py37: commands succeeded
-          py38: commands succeeded
-          congratulations :)
-        ```
-        
-        tox created two `testenvs` - one based on Python3.7 and one based on Python3.8, it installed pytest in them and ran the
-        tests. The report at the end summarizes which `testenvs` have failed and which have succeeded.
-        
-        **Note:** To learn more about what you can do with tox, have a look at
-        [the collection of examples in the documentation](https://tox.readthedocs.io/en/latest/examples.html) or
-        [existing projects using tox](https://github.com/search?l=INI&q=tox.ini+in%3Apath&type=Code).
-        
-        ### How it works
-        
-        tox creates virtual environments for all configured so called `testenvs`, it then installs the project and other
-        necessary dependencies and runs the configured set of commands. See
-        [system overview](https://tox.readthedocs.io/en/latest/#system-overview) for more details.
-        
-        <a href="https://tox.readthedocs.io/en/latest/#system-overview">
-            <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/img/tox_flow.png"
-                 alt="tox flow"
-                 width="800px"
-                 align="center">
-        </a>
-        
-        ### tox can be used for ...
-        
-        - creating development environments
-        - running static code analysis and test tools
-        - automating package builds
-        - running tests against the package build by tox
-        - checking that packages install correctly with different Python versions/interpreters
-        - unifying Continuous Integration and command line based testing
-        - building and deploying project documentation
-        - releasing a package to PyPI or any other platform
-        - limit: your imagination
-        
-        ### Documentation
-        
-        Documentation for tox can be found at [Read The Docs](https://tox.readthedocs.org).
-        
-        ### Communication and questions
-        
-        For the fastest and interactive feedback please join our
-        [![Discord](https://img.shields.io/discord/802911963368783933?style=flat-square)](https://discord.gg/edtj86wzBX) server.
-        If you have questions or suggestions you can first check if they have already been answered or discussed on our
-        [issue tracker](https://github.com/tox-dev/tox/issues?utf8=%E2%9C%93&q=is%3Aissue+sort%3Aupdated-desc+label%3A%22type%3Aquestion+%3Agrey_question%3A%22+).
-        On [Stack Overflow (tagged with `tox`)](https://stackoverflow.com/questions/tagged/tox).
-        
-        ### Contributing
-        
-        Contributions are welcome. See [contributing](https://github.com/tox-dev/tox/blob/master/CONTRIBUTING.rst) and our
-        [Contributor Covenant Code of Conduct](https://github.com/tox-dev/tox/blob/master/CODE_OF_CONDUCT.md).
-        
-        Currently the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
-        on Github.
-        
-        The project is licensed under [MIT](https://github.com/tox-dev/tox/blob/master/LICENSE).
-        
+Project-URL: Changelog, https://tox.readthedocs.io/en/latest/changelog.html
 Keywords: virtual,environments,isolated,testing
 Platform: any
 Classifier: Development Status :: 5 - Production/Stable
@@ -136,6 +27,7 @@ Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development :: Libraries
@@ -145,3 +37,115 @@ Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
 Description-Content-Type: text/markdown
 Provides-Extra: docs
 Provides-Extra: testing
+License-File: LICENSE
+
+[![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)](https://pypi.org/project/tox/)
+[![Supported Python
+versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/)
+[![check](https://github.com/tox-dev/tox/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/tox/actions/workflows/check.yml)
+[![Documentation
+status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest)
+[![Code style:
+black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+[![Downloads](https://pepy.tech/badge/tox/month)](https://pepy.tech/project/tox/month)
+
+<a href="https://tox.readthedocs.io">
+    <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/_static/img/tox.png"
+         alt="tox logo"
+         height="150px"
+         align="right">
+</a>
+
+# tox automation project
+
+**Command line driven CI frontend and development task automation tool**
+
+At its core tox provides a convenient way to run arbitrary commands in isolated environments to serve as a single entry
+point for build, test and release activities.
+
+tox is highly [configurable](https://tox.readthedocs.io/en/latest/config.html) and
+[pluggable](https://tox.readthedocs.io/en/latest/plugins.html).
+
+## Example: run tests with Python 3.7 and Python 3.8
+
+tox is mainly used as a command line tool and needs a `tox.ini` or a `tool.tox` section in `pyproject.toml` containing
+the configuration.
+
+To test a simple project that has some tests, here is an example with a `tox.ini` in the root of the project:
+
+```ini
+[tox]
+envlist = py37,py38
+
+[testenv]
+deps = pytest
+commands = pytest
+```
+
+```console
+$ tox
+
+[lots of output from what tox does]
+[lots of output from commands that were run]
+
+__________________ summary _________________
+  py37: commands succeeded
+  py38: commands succeeded
+  congratulations :)
+```
+
+tox created two `testenvs` - one based on Python 3.7 and one based on Python 3.8, it installed pytest in them and ran the
+tests. The report at the end summarizes which `testenvs` have failed and which have succeeded.
+
+**Note:** To learn more about what you can do with tox, have a look at
+[the collection of examples in the documentation](https://tox.readthedocs.io/en/latest/examples.html) or
+[existing projects using tox](https://github.com/search?l=INI&q=tox.ini+in%3Apath&type=Code).
+
+### How it works
+
+tox creates virtual environments for all configured so-called `testenvs`, it then installs the project and other
+necessary dependencies and runs the configured set of commands. See
+[system overview](https://tox.readthedocs.io/en/latest/#system-overview) for more details.
+
+<a href="https://tox.readthedocs.io/en/latest/#system-overview">
+    <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/img/tox_flow.png"
+         alt="tox flow"
+         width="800px"
+         align="center">
+</a>
+
+### tox can be used for ...
+
+- creating development environments
+- running static code analysis and test tools
+- automating package builds
+- running tests against the package built by tox
+- checking that packages install correctly with different Python versions/interpreters
+- unifying Continuous Integration and command line based testing
+- building and deploying project documentation
+- releasing a package to PyPI or any other platform
+- limit: your imagination
+
+### Documentation
+
+Documentation for tox can be found at [Read The Docs](https://tox.readthedocs.org).
+
+### Communication and questions
+
+For the fastest and interactive feedback please join our
+[![Discord](https://img.shields.io/discord/802911963368783933?style=flat-square)](https://discord.gg/edtj86wzBX) server.
+If you have questions or suggestions you can first check if they have already been answered or discussed on our
+[issue tracker](https://github.com/tox-dev/tox/issues?utf8=%E2%9C%93&q=is%3Aissue+sort%3Aupdated-desc+label%3A%22type%3Aquestion+%3Agrey_question%3A%22+).
+On [Stack Overflow (tagged with `tox`)](https://stackoverflow.com/questions/tagged/tox).
+
+### Contributing
+
+Contributions are welcome. See [contributing](https://github.com/tox-dev/tox/blob/master/CONTRIBUTING.rst) and our
+[Contributor Covenant Code of Conduct](https://github.com/tox-dev/tox/blob/master/CODE_OF_CONDUCT.md).
+
+Currently, the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
+on GitHub.
+
+The project is licensed under [MIT](https://github.com/tox-dev/tox/blob/master/LICENSE).
+
+
diff --git a/README.md b/README.md
index 698cb94..0140ac7 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,7 @@
-![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)
+[![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)](https://pypi.org/project/tox/)
 [![Supported Python
 versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/)
-[![Azure Pipelines build
-status](https://dev.azure.com/toxdev/tox/_apis/build/status/tox%20ci?branchName=master)](https://dev.azure.com/toxdev/tox/_build/latest?definitionId=9&branchName=master)
+[![check](https://github.com/tox-dev/tox/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/tox/actions/workflows/check.yml)
 [![Documentation
 status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest)
 [![Code style:
@@ -33,7 +32,7 @@ the configuration.
 
 To test a simple project that has some tests, here is an example with a `tox.ini` in the root of the project:
 
-```{.sourceCode .ini}
+```ini
 [tox]
 envlist = py37,py38
 
@@ -42,7 +41,7 @@ deps = pytest
 commands = pytest
 ```
 
-```{.sourceCode .console}
+```console
 $ tox
 
 [lots of output from what tox does]
@@ -54,7 +53,7 @@ __________________ summary _________________
   congratulations :)
 ```
 
-tox created two `testenvs` - one based on Python3.7 and one based on Python3.8, it installed pytest in them and ran the
+tox created two `testenvs` - one based on Python 3.7 and one based on Python 3.8, it installed pytest in them and ran the
 tests. The report at the end summarizes which `testenvs` have failed and which have succeeded.
 
 **Note:** To learn more about what you can do with tox, have a look at
@@ -63,7 +62,7 @@ tests. The report at the end summarizes which `testenvs` have failed and which h
 
 ### How it works
 
-tox creates virtual environments for all configured so called `testenvs`, it then installs the project and other
+tox creates virtual environments for all configured so-called `testenvs`, it then installs the project and other
 necessary dependencies and runs the configured set of commands. See
 [system overview](https://tox.readthedocs.io/en/latest/#system-overview) for more details.
 
@@ -79,7 +78,7 @@ necessary dependencies and runs the configured set of commands. See
 - creating development environments
 - running static code analysis and test tools
 - automating package builds
-- running tests against the package build by tox
+- running tests against the package built by tox
 - checking that packages install correctly with different Python versions/interpreters
 - unifying Continuous Integration and command line based testing
 - building and deploying project documentation
@@ -103,7 +102,7 @@ On [Stack Overflow (tagged with `tox`)](https://stackoverflow.com/questions/tagg
 Contributions are welcome. See [contributing](https://github.com/tox-dev/tox/blob/master/CONTRIBUTING.rst) and our
 [Contributor Covenant Code of Conduct](https://github.com/tox-dev/tox/blob/master/CODE_OF_CONDUCT.md).
 
-Currently the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
-on Github.
+Currently, the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
+on GitHub.
 
 The project is licensed under [MIT](https://github.com/tox-dev/tox/blob/master/LICENSE).
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index bf87abb..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
-resources:
-  repositories:
-  - repository: tox
-    type: github
-    endpoint: toxdevorg
-    name: tox-dev/azure-pipelines-template
-    ref: master
-
-trigger:
-  batch: true
-  branches:
-    include:
-    - master
-    - rewrite
-    - refs/tags/*
-pr:
-  branches:
-    include:
-    - master
-    - rewrite
-
-variables:
-  PYTEST_ADDOPTS: "-v -v -ra --showlocals"
-  PYTEST_XDIST_PROC_NR: '0'
-  PRE_COMMIT_HOME: $(Pipeline.Workspace)/pre-commit-cache
-
-jobs:
-- template: run-tox-env.yml@tox
-  parameters:
-    tox_version: ''
-    jobs:
-      fix_lint:
-        before:
-        - task: CacheBeta@0
-          displayName: cache pre-commit
-          inputs:
-            key: pre-commit | .pre-commit-config.yaml
-            path: $(PRE_COMMIT_HOME)
-      docs: null
-      py38:
-        image: [linux, windows, macOs]
-      py27:
-        image: [linux, windows, macOs]
-      pypy:
-        image: [linux]
-      py37:
-        image: [linux, windows, macOs]
-      py36:
-        image: [linux, windows, macOs]
-      py35:
-        image: [linux, windows, macOs]
-      pypy3:
-        image: [linux]
-      dev: null
-      package_description: null
-    coverage:
-      with_toxenv: 'coverage' # generate .tox/.coverage, .tox/coverage.xml after test run
-      for_envs: [py38, py37, py36, py35, py27, pypy3, pypy]
-    before:
-      - task: UsePythonVersion@0
-        condition: and(succeeded(), in(variables['TOXENV'], 'pypy'))
-        displayName: provision pypy 3
-        inputs:
-          versionSpec: 'pypy3'
-- ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/') }}:
-  - template: publish-pypi.yml@tox
-    parameters:
-      external_feed: 'toxdev'
-      pypi_remote: 'pypi-toxdev'
-      dependsOn: [fix_lint, docs, package_description, dev, report_coverage]
diff --git a/debian/changelog b/debian/changelog
index 247c1c8..c268f96 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+tox (3.24.5-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 16 Mar 2022 13:31:00 -0000
+
 tox (3.21.4-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/debian/patches/alabaster-no-external-links b/debian/patches/alabaster-no-external-links
index 27ce2f0..2ba192f 100644
--- a/debian/patches/alabaster-no-external-links
+++ b/debian/patches/alabaster-no-external-links
@@ -9,10 +9,10 @@ viewable offline and avoids privacy leaks when online.
  docs/conf.py | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
-diff --git a/docs/conf.py b/docs/conf.py
-index 05f1017..843a48f 100644
---- a/docs/conf.py
-+++ b/docs/conf.py
+Index: tox/docs/conf.py
+===================================================================
+--- tox.orig/docs/conf.py
++++ tox/docs/conf.py
 @@ -72,10 +72,10 @@ html_theme_options = {
      "github_user": "tox-dev",
      "github_repo": "tox",
diff --git a/debian/patches/disable-setuptools-scm b/debian/patches/disable-setuptools-scm
index f9314f4..5212a2f 100644
--- a/debian/patches/disable-setuptools-scm
+++ b/debian/patches/disable-setuptools-scm
@@ -8,11 +8,11 @@ it using a git description (via setuptools_scm).
  setup.py | 18 +++++++-----------
  1 file changed, 7 insertions(+), 11 deletions(-)
 
-diff --git a/setup.py b/setup.py
-index c59b4e9..bc18a38 100644
---- a/setup.py
-+++ b/setup.py
-@@ -3,17 +3,13 @@ import textwrap
+Index: tox/setup.py
+===================================================================
+--- tox.orig/setup.py
++++ tox/setup.py
+@@ -2,17 +2,13 @@ import textwrap
  
  from setuptools import setup
  
diff --git a/docs/_draft.rst b/docs/_draft.rst
new file mode 100644
index 0000000..e69de29
diff --git a/docs/changelog.rst b/docs/changelog.rst
index f561b7a..f2a927e 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -11,6 +11,164 @@ with advance notice in the **Deprecations** section of releases.
 
 .. towncrier release notes start
 
+v3.24.5 (2021-12-29)
+Bugfixes
+^^^^^^^^
+
+- Fixed an issue where ``usedevelop`` would cause an invocation error if setup.py does not exist. -- by :user:`VincentVanlaer`
+  `#2197 <https://github.com/tox-dev/tox/issues/2197>`_
+
+
+v3.24.4 (2021-09-16)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- Fixed handling of ``-e ALL`` in parallel mode by ignoring the ``ALL`` in subprocesses -- by :user:`guahki`.
+  `#2167 <https://github.com/tox-dev/tox/issues/2167>`_
+- Prevent tox from using a truncated interpreter when using
+  ``TOX_LIMITED_SHEBANG`` -- by :user:`jdknight`.
+  `#2208 <https://github.com/tox-dev/tox/issues/2208>`_
+
+
+Documentation
+^^^^^^^^^^^^^
+
+- Enabled the use of the favicon in the Sphinx docs first
+  introduced in :pull:`764` but not integrated fully
+  -- :user:`webknjaz`
+  `#2177 <https://github.com/tox-dev/tox/issues/2177>`_
+
+
+v3.24.3 (2021-08-21)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- ``--parallel`` reports now show ASCII OK/FAIL/SKIP lines when full Unicode output is not available - by :user:`brettcs`
+  `#1421 <https://github.com/tox-dev/tox/issues/1421>`_
+
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+- Started enforcing valid references in Sphinx docs -- :user:`webknjaz`
+  `#2168 <https://github.com/tox-dev/tox/issues/2168>`_
+
+
+v3.24.2 (2021-08-18)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- include ``LC_ALL`` to implicit list of passenv variables - by :user:`ssbarnea`
+  `#2162 <https://github.com/tox-dev/tox/issues/2162>`_
+
+
+v3.24.1 (2021-07-31)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- ``get_requires_for_build_sdist`` hook (PEP 517) is assumed to return an empty list if left unimplemented by the backend build system - by :user:`oczkoisse`
+  `#2130 <https://github.com/tox-dev/tox/issues/2130>`_
+
+
+Documentation
+^^^^^^^^^^^^^
+
+- The documentation of ``install_command`` now also mentions that you can provide arbitrary commands - by :user:`jugmac00`
+  `#2081 <https://github.com/tox-dev/tox/issues/2081>`_
+
+
+v3.24.0 (2021-07-14)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- ``--devenv`` no longer modifies the directory in which the ``.tox`` environment is provisioned - by :user:`isaac-ped`
+  `#2065 <https://github.com/tox-dev/tox/issues/2065>`_
+- Fix show config when the package names are not in canonical form - by :user:`gaborbernat`.
+  `#2103 <https://github.com/tox-dev/tox/issues/2103>`_
+
+
+Documentation
+^^^^^^^^^^^^^
+
+- Extended environment variables section - by :user:`majiang`
+  `#2036 <https://github.com/tox-dev/tox/issues/2036>`_
+
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+- ``tox`` no longer shows deprecation warnings for ``distutils.sysconfig`` on
+  Python 3.10 - by :user:`9999years`
+  `#2100 <https://github.com/tox-dev/tox/issues/2100>`_
+
+
+v3.23.1 (2021-05-05)
+--------------------
+
+Bugfixes
+^^^^^^^^
+
+- Distinguish between normal Windows Python and MSYS2 Python when looking for
+  virtualenv executable path.  Adds os.sep to :class:`~tox.interpreters.InterpreterInfo`
+  - by :user:`jschwartzentruber`
+  `#1982 <https://github.com/tox-dev/tox/issues/1982>`_
+- Fix a ``tox-conda`` isolation build bug - by :user:`AntoineD`.
+  `#2056 <https://github.com/tox-dev/tox/issues/2056>`_
+
+
+Documentation
+^^^^^^^^^^^^^
+
+- Update examples in the documentation to use ``setenv`` in the ``[testenv]`` sections, not wrongly in the ``[tox]`` main section.
+  - by :user:`AndreyNautilus`
+  `#1999 <https://github.com/tox-dev/tox/issues/1999>`_
+
+
+Miscellaneous
+^^^^^^^^^^^^^
+
+- Enable building tox with ``setuptools_scm`` 6+ by :user:`hroncok`
+  `#1984 <https://github.com/tox-dev/tox/issues/1984>`_
+
+
+v3.23.0 (2021-03-03)
+--------------------
+
+Features
+^^^^^^^^
+
+- tox can now be invoked with a new ``--no-provision`` flag that prevents provision,
+  if :conf:`requires` or :conf:`minversion` are not satisfied,
+  tox will fail;
+  if a path is specified as an argument to the flag
+  (e.g. as ``tox --no-provision missing.json``) and provision is prevented,
+  provision metadata are written as JSON to that path - by :user:`hroncok`
+  `#1921 <https://github.com/tox-dev/tox/issues/1921>`_
+- Unicode support in ``pyproject.toml`` - by :user:`domdfcoding`
+  `#1940 <https://github.com/tox-dev/tox/issues/1940>`_
+
+
+v3.22.0 (2021-02-16)
+--------------------
+
+Features
+^^^^^^^^
+
+- The value of the :conf:`requires` configuration option is now exposed via
+  the :class:`tox.config.Config` object - by :user:`hroncok`
+  `#1918 <https://github.com/tox-dev/tox/issues/1918>`_
+
+
 v3.21.4 (2021-02-02)
 --------------------
 
@@ -962,7 +1120,7 @@ Features
 - While running tox invokes various commands (such as building the package, pip installing dependencies and so on), these were printed in case they failed as Python arrays. Changed the representation to a shell command, allowing the users to quickly replicate/debug the failure on their own - by :user:`gaborbernat` (`#851 <https://github.com/tox-dev/tox/issues/851>`_)
 - skip missing interpreters value from the config file can now be overridden via the ``--skip-missing-interpreters`` cli flag - by :user:`gaborbernat` (`#903 <https://github.com/tox-dev/tox/issues/903>`_)
 - keep additional environments config order when listing them - by :user:`gaborbernat` (`#921 <https://github.com/tox-dev/tox/issues/921>`_)
-- allow injecting config value inside the ini file dependent of the fact that we're connected to an interactive shell or not  - by :user:`gaborbernat` (`#947 <https://github.com/tox-dev/tox/issues/947>`_)
+- allow injecting config value inside the ini file dependent of the fact that we're connected to an interactive shell or not via exposing a ``{tty}`` substitution - by :user:`gaborbernat` (`#947 <https://github.com/tox-dev/tox/issues/947>`_)
 - do not build sdist if skip install is specified for the envs to be run - by :user:`gaborbernat` (`#974 <https://github.com/tox-dev/tox/issues/974>`_)
 - when verbosity level increases above two start passing through verbosity flags to pip - by :user:`gaborbernat` (`#982 <https://github.com/tox-dev/tox/issues/982>`_)
 - when discovering the interpreter to use check if the tox host Python matches and use that if so - by :user:`gaborbernat` (`#994 <https://github.com/tox-dev/tox/issues/994>`_)
@@ -1326,7 +1484,7 @@ v2.8.0 (2017-09-01)
 - `pull request 585 <https://github.com/tox-dev/tox/pull/585>`_: Expand documentation to explain pass through of flags from deps to pip
   (e.g. ``-rrequirements.txt``, ``-cconstraints.txt``). Thanks Alexander Loechel (`@loechel <https://github.com/loechel>`_).
 
-- `pull request 588 <https://github.com/tox-dev/tox/pull/588>`_: Run pytest wit xfail_strict and adapt affected tests.
+- `pull request 588 <https://github.com/tox-dev/tox/pull/588>`_: Run pytest with xfail_strict and adapt affected tests.
 
 v2.7.0 (2017-04-02)
 -------------------
diff --git a/docs/conf.py b/docs/conf.py
index 05f1017..7340493 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -22,11 +22,11 @@ ROOT_SRC_TREE_DIR = Path(__file__).parents[1]
 
 def generate_draft_news():
     home = "https://github.com"
-    issue = "{}/issue".format(home)
+    issue = f"{home}/issue"
     fragments_path = ROOT_SRC_TREE_DIR / "docs" / "changelog"
     for pattern, replacement in (
-        (r"[^`]@([^,\s]+)", r"`@\1 <{}/\1>`_".format(home)),
-        (r"[^`]#([\d]+)", r"`#pr\1 <{}/\1>`_".format(issue)),
+        (r"[^`]@([^,\s]+)", fr"`@\1 <{home}/\1>`_"),
+        (r"[^`]#([\d]+)", fr"`#pr\1 <{issue}/\1>`_"),
     ):
         for path in fragments_path.glob("*.rst"):
             path.write_text(re.sub(pattern, replacement, path.read_text()))
@@ -43,20 +43,20 @@ def generate_draft_news():
         content = ""
     else:
         note = "*Changes in master, but not released yet are under the draft section*."
-        content = "{}\n\n{}".format(note, changelog)
+        content = f"{note}\n\n{changelog}"
     (ROOT_SRC_TREE_DIR / "docs" / "_draft.rst").write_text(content)
 
 
 generate_draft_news()
 
-project = u"tox"
+project = "tox"
 _full_version = tox.__version__
 release = _full_version.split("+", 1)[0]
 version = ".".join(release.split(".")[:2])
 
 author = "holger krekel and others"
 year = date.today().year
-copyright = u"2010-{}, {}".format(year, author)
+copyright = f"2010-{year}, {author}"
 
 master_doc = "index"
 source_suffix = ".rst"
@@ -81,15 +81,17 @@ html_theme_options = {
 html_sidebars = {
     "**": ["about.html", "localtoc.html", "relations.html", "searchbox.html", "donate.html"],
 }
+html_favicon = "_static/img/toxfavi.ico"
 html_show_sourcelink = False
 html_static_path = ["_static"]
-htmlhelp_basename = "{}doc".format(project)
-latex_documents = [("index", "tox.tex", u"{} Documentation".format(project), author, "manual")]
-man_pages = [("index", project, u"{} Documentation".format(project), [author], 1)]
+htmlhelp_basename = f"{project}doc"
+latex_documents = [("index", "tox.tex", f"{project} Documentation", author, "manual")]
+man_pages = [("index", project, f"{project} Documentation", [author], 1)]
 epub_title = project
 epub_author = author
 epub_publisher = author
 epub_copyright = copyright
+suppress_warnings = ["epub.unknown_project_files"]  # Prevent barking at `.ico`
 
 intersphinx_mapping = {"https://docs.python.org/": None}
 
@@ -102,11 +104,11 @@ def setup(app):
         node += addnodes.literal_strong(name, name)
 
         if len(args) > 2:
-            default = "={}".format(args[2].strip())
+            default = f"={args[2].strip()}"
             node += nodes.literal(text=default)
 
         if len(args) > 1:
-            content = "({})".format(args[1].strip())
+            content = f"({args[1].strip()})"
             node += addnodes.compact_paragraph(text=content)
 
         return name  # this will be the link
@@ -129,3 +131,8 @@ extlinks = {
     "pull": ("https://github.com/tox-dev/tox/pull/%s", "p"),
     "user": ("https://github.com/%s", "@"),
 }
+
+nitpicky = True
+nitpick_ignore = [
+    ("py:class", "tox.interpreters.InterpreterInfo"),
+]
diff --git a/docs/config.rst b/docs/config.rst
index 01bc9b7..231ccc0 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -38,6 +38,11 @@ Global settings are defined under the ``tox`` section as:
    than this the tool will create an environment and provision it with a version of
    tox that satisfies this under :conf:`provision_tox_env`.
 
+   .. versionchanged:: 3.23.0
+
+   When tox is invoked with the ``--no-provision`` flag,
+   the provision won't be attempted, tox will fail instead.
+
 .. conf:: requires ^ LIST of PEP-508
 
     .. versionadded:: 3.2.0
@@ -54,6 +59,11 @@ Global settings are defined under the ``tox`` section as:
         requires = tox-pipenv
                    setuptools >= 30.0.0
 
+    .. versionchanged:: 3.23.0
+
+    When tox is invoked with the ``--no-provision`` flag,
+    the provision won't be attempted, tox will fail instead.
+
 .. conf:: provision_tox_env ^ string ^ .tox
 
     .. versionadded:: 3.8.0
@@ -61,12 +71,19 @@ Global settings are defined under the ``tox`` section as:
     Name of the virtual environment used to provision a tox having all dependencies specified
     inside :conf:`requires` and :conf:`minversion`.
 
+    .. versionchanged:: 3.23.0
+
+    When tox is invoked with the ``--no-provision`` flag,
+    the provision won't be attempted, tox will fail instead.
+
 .. conf:: toxworkdir ^ PATH ^ {toxinidir}/.tox
 
    Directory for tox to generate its environments into, will be created if it does not exist.
 
 .. conf:: temp_dir ^ PATH ^ {toxworkdir}/.tmp
 
+   .. versionadded:: 3.5.0
+
    Directory where to put tox temporary files. For example: we create a hard link (if possible,
    otherwise new copy) in this directory for the project package. This ensures tox works correctly
    when having parallel runs (as each session will have its own copy of the project package - e.g.
@@ -258,6 +275,13 @@ Complete list of settings that you can put into ``testenv*`` sections:
         translates as the virtual environments ``python`` (having the same runtime version
         as the :conf:`basepython`), and ``pip`` translates as the virtual environments ``pip``.
 
+    :note: Inline scripts can be used, however note these are discovered from the project root directory,
+        and is not influenced by :conf:`changedir` (this only affects the runtime current working directory).
+        To make this behaviour explicit we recommend that you make inline scripts absolute paths by
+        prepending ``{toxinidir}``, instead of ``path/to/my_script`` prefer
+        ``{toxinidir}{/}path{/}to{/}my_script``. If your inline script is platform dependent refer to
+        :ref:`platform-specification` on how to select different script per platform.
+
 .. conf:: commands_pre ^ ARGVLIST
 
     .. versionadded:: 3.4
@@ -284,6 +308,13 @@ Complete list of settings that you can put into ``testenv*`` sections:
     such as ``--pre`` (configured as ``pip_pre``) and potentially index-options from the
     deprecated :conf:`indexserver` option.
 
+    .. note::
+
+        You can also provide arbitrary commands to the ``install_command``. Please take care that these commands can be
+        executed on the supported operating systems. When executing shell scripts we recommend to not specify the script
+        directly but instead pass it to the appropriate shell as argument (e.g. prefer ``bash script.sh`` over
+        ``script.sh``).
+
 .. conf:: list_dependencies_command ^ ARGV ^ python -m pip freeze
 
     .. versionadded:: 2.4
@@ -345,7 +376,7 @@ Complete list of settings that you can put into ``testenv*`` sections:
 
 .. conf:: changedir ^ PATH ^ {toxinidir}
 
-    Change to this working directory when executing the test command.
+    Change the current working directory when executing the test command.
 
     .. note::
 
@@ -353,7 +384,7 @@ Complete list of settings that you can put into ``testenv*`` sections:
 
 .. conf:: deps ^ MULTI-LINE-LIST
 
-    Environment dependencies - installed into the environment ((see :conf:`install_command`) prior
+    Environment dependencies - installed into the environment (see :conf:`install_command`) prior
     to project after environment creation. One dependency (a file, a URL or a package name) per
     line. Must be PEP-508_ compliant. All installer commands are executed using the toxinidir_ as the
     current working directory.
@@ -522,9 +553,11 @@ Complete list of settings that you can put into ``testenv*`` sections:
 
     .. versionadded:: 0.9
 
-    (DEPRECATED, will be removed in a future version) Multi-line ``name =
-    URL`` definitions of python package servers.  Dependencies can
-    specify using a specified index server through the
+    (DEPRECATED, will be removed in a future version) Use :conf:`setenv`
+    to configure PIP_INDEX_URL environment variable, see below.
+
+    Multi-line ``name = URL`` definitions of python package servers.
+    You can specify an alternative index server for dependencies by applying the
     ``:indexservername:depname`` pattern.  The ``default`` indexserver
     definition determines where unscoped dependencies and the sdist install
     installs from.  Example:
@@ -538,6 +571,17 @@ Complete list of settings that you can put into ``testenv*`` sections:
     will make tox install all dependencies from this PyPI index server
     (including when installing the project sdist package).
 
+    The recommended way to set a custom index server URL is to use :conf:`setenv`:
+
+    .. code-block:: ini
+
+        [testenv]
+        setenv =
+            PIP_INDEX_URL = {env:PIP_INDEX_URL:https://pypi.org/simple/}
+
+    This will ensure the desired index server gets used for virtual environment
+    creation and allow overriding the index server URL with an environment variable.
+
 .. conf:: envdir ^ PATH ^ {toxworkdir}/{envname}
 
     .. versionadded:: 1.5
@@ -552,7 +596,9 @@ Complete list of settings that you can put into ``testenv*`` sections:
     Install the current package in development mode with "setup.py
     develop" instead of installing from the ``sdist`` package. (This
     uses pip's ``-e`` option, so should be avoided if you've specified a
-    custom :conf:`install_command` that does not support ``-e``).
+    custom :conf:`install_command` that does not support ``-e``). Note that
+    changes to the build/install process (including changes in dependencies)
+    are only detected when using setuptools with setup.py.
 
 .. conf:: skip_install ^ true|false ^ false
 
@@ -608,7 +654,7 @@ Complete list of settings that you can put into ``testenv*`` sections:
     .. versionadded:: 3.15.2
 
     When an interrupt is sent via Ctrl+C or the tox process is killed with a SIGTERM,
-    a SIGINT is sent to all foreground processes. The :conf:``suicide_timeout`` gives
+    a SIGINT is sent to all foreground processes. The :conf:`suicide_timeout` gives
     the running process time to cleanup and exit before receiving (in some cases, a duplicate) SIGINT from
     tox.
 
@@ -617,17 +663,17 @@ Complete list of settings that you can put into ``testenv*`` sections:
     .. versionadded:: 3.15.0
 
     When tox is interrupted, it propagates the signal to the child process
-    after :conf:``suicide_timeout`` seconds. If the process still hasn't exited
-    after :conf:``interrupt_timeout`` seconds, its sends a SIGTERM.
+    after :conf:`suicide_timeout` seconds. If the process still hasn't exited
+    after :conf:`interrupt_timeout` seconds, its sends a SIGTERM.
 
 .. conf:: terminate_timeout ^ float ^ 0.2
 
     .. versionadded:: 3.15.0
 
-    When tox is interrupted, after waiting :conf:``interrupt_timeout`` seconds,
+    When tox is interrupted, after waiting :conf:`interrupt_timeout` seconds,
     it propagates the signal to the child process, waits
-    :conf:``interrupt_timeout`` seconds, sends it a SIGTERM, waits
-    :conf:``terminate_timeout`` seconds, and sends it a SIGKILL if it hasn't
+    :conf:`interrupt_timeout` seconds, sends it a SIGTERM, waits
+    :conf:`terminate_timeout` seconds, and sends it a SIGKILL if it hasn't
     exited.
 
 Substitutions
@@ -662,6 +708,11 @@ Globally available substitutions
     the directory where virtual environments are created and sub directories
     for packaging reside.
 
+``{temp_dir}``
+    the directory where tox temporary files live.
+
+    .. versionadded:: 3.16.1
+
 ``{homedir}``
     the user-home directory path.
 
@@ -747,6 +798,8 @@ the above example is roughly equivalent to
 Interactive shell substitution
 ++++++++++++++++++++++++++++++
 
+.. versionadded:: 3.4.0
+
 It's possible to inject a config value only when tox is running in interactive shell (standard input)::
 
     {tty:ON_VALUE:OFF_VALUE}
@@ -1046,9 +1099,9 @@ Handle interpreter directives with long lengths
 For systems supporting executable text files (scripts with a shebang), the
 system will attempt to parse the interpreter directive to determine the program
 to execute on the target text file. When ``tox`` prepares a virtual environment
-in a file container which has a large length (e.x. using Jenkins Pipelines), the
+in a file container which has a large length (e.g. using Jenkins Pipelines), the
 system might not be able to invoke shebang scripts which define interpreters
-beyond system limits (e.x. Linux as a limit of 128; ``BINPRM_BUF_SIZE``). To
+beyond system limits (e.g. Linux has a limit of 128; ``BINPRM_BUF_SIZE``). To
 workaround an environment which suffers from an interpreter directive limit, a
 user can bypass the system's interpreter parser by defining the
 ``TOX_LIMITED_SHEBANG`` environment variable before invoking ``tox``::
@@ -1058,8 +1111,22 @@ user can bypass the system's interpreter parser by defining the
 When the workaround is enabled, all tox-invoked text file executables will have
 their interpreter directive parsed by and explicitly executed by ``tox``.
 
+Environment variables
+---------------------
+tox will treat the following environment variables:
+
+- ``TOX_DISCOVER`` for python discovery first try the python executables under these paths
+- ``TOXENV`` see :conf:`envlist`.
+- ``TOX_LIMITED_SHEBANG`` see :ref:`long interpreter directives`.
+- ``TOX_PARALLEL_NO_SPINNER`` see :ref:`parallel_mode`.
+- ``_TOX_PARALLEL_ENV`` lets tox know that it is invoked in the parallel mode.
+- ``TOX_PROVISION`` is only intended to be used internally.
+- ``TOX_REPORTER_TIMESTAMP`` enables showing for each output line its delta since the tox startup when set to ``1``.
+- ``TOX_SKIP_ENV`` see :conf:`envlist`.
+- ``TOX_TESTENV_PASSENV`` see :conf:`passenv`.
+
 Injected environment variables
-------------------------------
+++++++++++++++++++++++++++++++
 tox will inject the following environment variables that you can use to test that your command is running within tox:
 
 .. versionadded:: 3.4
diff --git a/docs/drafts/extend-envs-and-packagebuilds.md b/docs/drafts/extend-envs-and-packagebuilds.md
index cecdb37..ed83791 100644
--- a/docs/drafts/extend-envs-and-packagebuilds.md
+++ b/docs/drafts/extend-envs-and-packagebuilds.md
@@ -47,7 +47,7 @@ To summarize - we would need a:
 
 * reporting in detox is minimal (would need to improve)
 * restricting processes would be necessary depending on power of the machine
-  (creating 16 processe on a dual core machine might be overkill)
+  (creating 16 processes on a dual-core machine might be overkill)
 * port it from eventlets to threads?
 
 ### Concrete use case conda integration (started by Bruno)
@@ -93,7 +93,7 @@ package_formats=            # new option to specify wanted package formats for t
 commands = py.test
 ```
 
-Lising tox environments (`tox --list`) would display the following output:
+Listing tox environments (`tox --list`) would display the following output:
 
 ```
 (sdist) py27
@@ -152,17 +152,17 @@ Output of `tox --list`:
 ```
 
 
-### Implemenation Details
+### Implementation Details
 
 ```
 tox_package_formats() -> ['conda']   # ['sdist', 'wheel']
 tox_testenv_create(env_meta, package_type) -> # creates an environment for given package, using
                                                   # information from env_meta (like .envdir)
-                                                  # returns: an "env" object which is forwaded to the next hooks
+                                                  # returns: an "env" object which is forwarded to the next hooks
 tox_testenv_install(env_meta, package_type, env) -> # installs deps and package into environment
 tox_testenv_runtest(env_meta, package_type, env) -> # activates environment and runs test commands
 
-tox_testenv_updated(env_meta, package_type) ->  # returns True if hte environment is already up to date
+tox_testenv_updated(env_meta, package_type) ->  # returns True if the environment is already up to date
                                                 # otherwise, tox will remove the environment completely and
                                                 # create a new one
 ```
diff --git a/docs/drafts/tox_conda_notes_niccodemus.md b/docs/drafts/tox_conda_notes_niccodemus.md
index 22ad105..c570948 100644
--- a/docs/drafts/tox_conda_notes_niccodemus.md
+++ b/docs/drafts/tox_conda_notes_niccodemus.md
@@ -32,7 +32,7 @@ type=conda-env
 ```
 
 1. Create a new ``create_env_command`` option.
-;2. Create a new ``env_activate_command`` option (also consider how to make that platform dependent).
+2. Create a new ``env_activate_command`` option (also consider how to make that platform dependent).
 2. New substitution variable: {python_version} ('3.5', '2.7', etc')
 3. env type concept: different types change the default options.
 
diff --git a/docs/example/basic.rst b/docs/example/basic.rst
index 90048af..c7b15e4 100644
--- a/docs/example/basic.rst
+++ b/docs/example/basic.rst
@@ -130,13 +130,6 @@ Depending on requirements.txt or defining constraints
 
 or
 
-.. code-block:: ini
-
-    [testenv]
-    deps = -cconstraints.txt
-
-or
-
 .. code-block:: ini
 
     [testenv]
@@ -172,15 +165,15 @@ This variable can be also set in ``tox.ini``:
 
 .. code-block:: ini
 
-    [tox]
+    [testenv]
     setenv =
         PIP_INDEX_URL = https://pypi.my-alternative-index.org
 
-Alternatively, a configuration where ``PIP_INDEX_URL`` could be overriden from environment:
+Alternatively, a configuration where ``PIP_INDEX_URL`` could be overridden from environment:
 
 .. code-block:: ini
 
-    [tox]
+    [testenv]
     setenv =
         PIP_INDEX_URL = {env:PIP_INDEX_URL:https://pypi.my-alternative-index.org}
 
@@ -192,11 +185,9 @@ multiple PyPI servers, using ``PIP_EXTRA_INDEX_URL`` environment variable:
 
 .. code-block:: ini
 
-    [tox]
+    [testenv]
     setenv =
         PIP_EXTRA_INDEX_URL = https://mypypiserver.org
-
-    [testenv]
     deps =
         # docutils will be installed directly from PyPI
         docutils
@@ -204,9 +195,15 @@ multiple PyPI servers, using ``PIP_EXTRA_INDEX_URL`` environment variable:
         mypackage
 
 This configuration will install ``docutils`` from the default
-Python PYPI server and will install the ``mypackage`` from
+Python PyPI server and will install the ``mypackage`` from
 our index server at ``https://mypypiserver.org`` URL.
 
+.. warning::
+
+  Using an extra PyPI index for installing private packages may cause security issues.
+  For example, if ``mypackage`` is registered with the default PyPI index, pip will install ``mypackage``
+  from the default PyPI index, not from the custom one.
+
 Further customizing installation
 ---------------------------------
 
@@ -215,7 +212,7 @@ Further customizing installation
 By default tox uses `pip`_ to install packages, both the
 package-under-test and any dependencies you specify in ``tox.ini``.
 You can fully customize tox's install-command through the
-testenv-specific :conf:`install_command=ARGV` setting.
+testenv-specific :conf:`install_command = ARGV <install_command>` setting.
 For instance, to use pip's ``--find-links`` and ``--no-index`` options to specify
 an alternative source for your dependencies:
 
diff --git a/docs/example/platform.rst b/docs/example/platform.rst
index 647dc3b..a2944e9 100644
--- a/docs/example/platform.rst
+++ b/docs/example/platform.rst
@@ -1,3 +1,5 @@
+.. _platform-specification:
+
 Platform specification
 ============================
 
diff --git a/docs/index.rst b/docs/index.rst
index 908a8a3..e101336 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -137,7 +137,7 @@ Current features
 * :doc:`plugin system <plugins>` to modify tox execution with simple hooks.
 
 * uses pip_ and setuptools_ by default.  Support for configuring the installer command
-  through :conf:`install_command=ARGV`.
+  through :conf:`install_command = ARGV <install_command>`.
 
 * **cross-Python compatible**: CPython-2.7, 3.5 and higher, Jython and pypy_.
 
diff --git a/docs/links.rst b/docs/links.rst
index ba75c60..d51b21c 100644
--- a/docs/links.rst
+++ b/docs/links.rst
@@ -20,7 +20,7 @@
 .. _unittest2: https://pypi.org/project/unittest2
 .. _mock: https://pypi.org/project/mock/
 .. _flit: https://flit.readthedocs.io/en/latest/
-.. _poetry: https://poetry.eustace.io/
+.. _poetry: https://python-poetry.org/
 .. _pypy: https://pypy.org
 
 .. _`Python Packaging Guide`: https://packaging.python.org/tutorials/packaging-projects/
diff --git a/docs/plugins.rst b/docs/plugins.rst
index a262ade..604602e 100644
--- a/docs/plugins.rst
+++ b/docs/plugins.rst
@@ -21,33 +21,45 @@ e.g.:
 
     $ pip install tox-travis
 
-You can search for available plugins on PyPI by typing ``pip search tox`` and filter for
-packages that are prefixed ``tox-`` or contain the word "plugin" in the description.
-You will get some output similar to this::
-
-    tox-pipenv (1.4.1)                   - A pipenv plugin for tox
-    tox-pyenv (1.1.0)                    - tox plugin that makes tox use ``pyenv which`` to find
-                                           python executables
-    tox-globinterpreter (0.3)            - tox plugin to allow specification of interpreter
-                                           locationspaths to use
-    tox-venv (0.2.0)                     - Use python3 venvs for python3 tox testenvs
-    tox-cmake (0.1.1)                    - Build CMake projects using tox
-    tox-tags (0.2.0)                     - Allows running subsets of environments based on tags
-    tox-travis (0.10)                    - Seamless integration of tox into Travis CI
-    tox-py-backwards (0.1)               - tox plugin for py-backwards
-    tox-pytest-summary (0.1.2)           - tox + Py.test summary
-    tox-envreport (0.2.0)                - A tox-plugin to document the setup of used virtual
-                                           environments.
-    tox-no-internet (0.1.0)              - Workarounds for using tox with no internet connection
-    tox-virtualenv-no-download (1.0.2)   - Disable virtualenv's download-by-default in tox
-    tox-run-command (0.4)                - tox plugin to run arbitrary commands in a virtualenv
-    tox-pip-extensions (1.2.1)           - Augment tox with different installation methods via
+You can search for available plugins on PyPI by visiting `PyPI <https://pypi.org/search/?q=tox>`_ and
+searching for packages that are prefixed ``tox-`` or contain the word "plugin" in the description.
+Examples include::
+
+    tox-ansible                          - Plugin for generating tox environments for tools like ansible-test
+    tox-asdf                             - A tox plugin that finds python executables using asdf
+    tox-backticks                        - Allows backticks within setenv blocks for populating
+                                           environment variables
+    tox-bindep                           - Runs bindep checks prior to tests
+    tox-bitbucket-status                 - Update bitbucket status for each env
+    tox-cmake                            - Build CMake projects using tox
+    tox-conda                            - Provides integration with the condo package manager
+    tox-current-env                      - Run tests in the current python environment
+    tox-docker                           - Launch a docker instance around test runs
+    tox-direct                           - Run everything directly without tox venvs
+    tox-envlist                          - Allows selection of a different tox envlist
+    tox-envreport                        - A tox-plugin to document the setup of used virtual
+    tox-factor                           - Runs a subset of tox test environments
+    tox-globinterpreter                  - tox plugin to allow specification of interpreter
+    tox-gh-actions                       - A plugin for helping to run tox in GitHub actions.
+    tox-ltt                              - Light-the-torch integration
+    tox-no-internet                      - Workarounds for using tox with no internet connection
+    tox-pdm                              - Utilizes PDM as the package manager and installer
+    tox-pip-extensions                   - Augment tox with different installation methods via
                                            progressive enhancement.
-    tox-run-before (0.1)                 - tox plugin to run shell commands before the test
+    tox-pipenv                           - A pipenv plugin for tox
+    tox-pipenv-install                   - Install packages from Pipfile
+    tox-poetry                           - Install packages using poetry
+    tox-py-backwards                     - tox plugin for py-backwards
+    tox-pyenv                            - tox plugin that makes tox use ``pyenv which`` to find
+                                           python executables
+    tox-pytest-summary                   - tox + Py.test summary
+    tox-run-before                       - tox plugin to run shell commands before the test
                                            environments are created.
-    tox-docker (1.0.0)                   - Launch a docker instance around test runs
-    tox-bitbucket-status (1.0)           - Update bitbucket status for each env
-    tox-pipenv-install (1.0.3)           - Install packages from Pipfile
+    tox-run-command                      - tox plugin to run arbitrary commands in a virtualenv
+    tox-tags                             - Allows running subsets of environments based on tags
+    tox-travis                           - Seamless integration of tox into Travis CI
+    tox-venv                             - Use python3 venvs for python3 tox testenvs environments.
+    tox-virtualenv-no-download           - Disable virtualenv's download-by-default in tox
 
 
 There might also be some plugins not (yet) available from PyPI that could be installed directly
diff --git a/docs/support.rst b/docs/support.rst
index 16bf48f..9edcdc9 100644
--- a/docs/support.rst
+++ b/docs/support.rst
@@ -7,7 +7,7 @@ Getting in contact:
 
 * join the `tox-dev mailing list`_ for tox related questions and development discussions
 * file a `report on the issue tracker`_
-* hang out on the irc.freenode.net #pylib channel
+* hang out on the tox discord server channel at https://discord.gg/tox
 * `fork the github repository`_ and submit merge/pull requests (see the developers help page -- :ref:`developers`)
 
 Paid professional support
diff --git a/pyproject.toml b/pyproject.toml
index a57d6c9..6aa5a1b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
 [build-system]
 requires = [
     "setuptools >= 40.0.4",
-    "setuptools_scm >= 2.0.0, <6",
+    "setuptools_scm >= 2.0.0",
     "wheel >= 0.29.0",
 ]
 build-backend = 'setuptools.build_meta'
diff --git a/readthedocs.yml b/readthedocs.yml
deleted file mode 100644
index 1aaa175..0000000
--- a/readthedocs.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-build:
-  image: latest
-python:
-  version: 3.6
-  pip_install: true
-  extra_requirements:
-  - docs
-formats: []
diff --git a/setup.cfg b/setup.cfg
index 4aa1e2f..0e161e8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,7 +3,7 @@ name = tox
 description = tox is a generic virtualenv management and test command line tool
 long_description = file: README.md
 long_description_content_type = text/markdown
-url = http://tox.readthedocs.org
+url = https://tox.readthedocs.io
 author = Holger Krekel, Oliver Bestwalter, Bernát Gábor and others
 maintainer = Bernat Gabor, Oliver Bestwalter, Anthony Asottile
 maintainer_email = tox-dev@python.org
@@ -26,6 +26,7 @@ classifiers =
 	Programming Language :: Python :: 3.7
 	Programming Language :: Python :: 3.8
 	Programming Language :: Python :: 3.9
+	Programming Language :: Python :: 3.10
 	Programming Language :: Python :: Implementation :: CPython
 	Programming Language :: Python :: Implementation :: PyPy
 	Topic :: Software Development :: Libraries
@@ -35,6 +36,7 @@ keywords = virtual, environments, isolated, testing
 project_urls = 
 	Source=https://github.com/tox-dev/tox
 	Tracker=https://github.com/tox-dev/tox/issues
+	Changelog=https://tox.readthedocs.io/en/latest/changelog.html
 
 [options]
 packages = find:
@@ -50,6 +52,9 @@ install_requires =
 	importlib-metadata>=0.12;python_version<"3.8"
 python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
 
+[options.packages.find]
+where = src
+
 [options.entry_points]
 console_scripts = 
 	tox=tox:cmdline
@@ -64,16 +69,12 @@ docs =
 testing = 
 	flaky>=3.4.0
 	freezegun>=0.3.11
-	psutil>=5.6.1
 	pytest>=4.0.0
 	pytest-cov>=2.5.1
 	pytest-mock>=1.10.0
 	pytest-randomly>=1.0.0
-	pytest-xdist>=1.22.2
 	pathlib2>=2.3.3;python_version<"3.4"
-
-[options.packages.find]
-where = src
+	psutil>=5.6.1;platform_python_implementation=="cpython"
 
 [bdist_wheel]
 universal = 1
diff --git a/setup.py b/setup.py
index c59b4e9..d6efbf5 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import textwrap
 
 from setuptools import setup
diff --git a/src/tox.egg-info/PKG-INFO b/src/tox.egg-info/PKG-INFO
index f49c4b9..c922307 100644
--- a/src/tox.egg-info/PKG-INFO
+++ b/src/tox.egg-info/PKG-INFO
@@ -1,124 +1,15 @@
 Metadata-Version: 2.1
 Name: tox
-Version: 3.21.4
+Version: 3.24.5
 Summary: tox is a generic virtualenv management and test command line tool
-Home-page: http://tox.readthedocs.org
+Home-page: https://tox.readthedocs.io
 Author: Holger Krekel, Oliver Bestwalter, Bernát Gábor and others
 Maintainer: Bernat Gabor, Oliver Bestwalter, Anthony Asottile
 Maintainer-email: tox-dev@python.org
 License: MIT
 Project-URL: Source, https://github.com/tox-dev/tox
 Project-URL: Tracker, https://github.com/tox-dev/tox/issues
-Description: ![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)
-        [![Supported Python
-        versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/)
-        [![Azure Pipelines build
-        status](https://dev.azure.com/toxdev/tox/_apis/build/status/tox%20ci?branchName=master)](https://dev.azure.com/toxdev/tox/_build/latest?definitionId=9&branchName=master)
-        [![Documentation
-        status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest)
-        [![Code style:
-        black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
-        [![Downloads](https://pepy.tech/badge/tox/month)](https://pepy.tech/project/tox/month)
-        
-        <a href="https://tox.readthedocs.io">
-            <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/_static/img/tox.png"
-                 alt="tox logo"
-                 height="150px"
-                 align="right">
-        </a>
-        
-        # tox automation project
-        
-        **Command line driven CI frontend and development task automation tool**
-        
-        At its core tox provides a convenient way to run arbitrary commands in isolated environments to serve as a single entry
-        point for build, test and release activities.
-        
-        tox is highly [configurable](https://tox.readthedocs.io/en/latest/config.html) and
-        [pluggable](https://tox.readthedocs.io/en/latest/plugins.html).
-        
-        ## Example: run tests with Python 3.7 and Python 3.8
-        
-        tox is mainly used as a command line tool and needs a `tox.ini` or a `tool.tox` section in `pyproject.toml` containing
-        the configuration.
-        
-        To test a simple project that has some tests, here is an example with a `tox.ini` in the root of the project:
-        
-        ```{.sourceCode .ini}
-        [tox]
-        envlist = py37,py38
-        
-        [testenv]
-        deps = pytest
-        commands = pytest
-        ```
-        
-        ```{.sourceCode .console}
-        $ tox
-        
-        [lots of output from what tox does]
-        [lots of output from commands that were run]
-        
-        __________________ summary _________________
-          py37: commands succeeded
-          py38: commands succeeded
-          congratulations :)
-        ```
-        
-        tox created two `testenvs` - one based on Python3.7 and one based on Python3.8, it installed pytest in them and ran the
-        tests. The report at the end summarizes which `testenvs` have failed and which have succeeded.
-        
-        **Note:** To learn more about what you can do with tox, have a look at
-        [the collection of examples in the documentation](https://tox.readthedocs.io/en/latest/examples.html) or
-        [existing projects using tox](https://github.com/search?l=INI&q=tox.ini+in%3Apath&type=Code).
-        
-        ### How it works
-        
-        tox creates virtual environments for all configured so called `testenvs`, it then installs the project and other
-        necessary dependencies and runs the configured set of commands. See
-        [system overview](https://tox.readthedocs.io/en/latest/#system-overview) for more details.
-        
-        <a href="https://tox.readthedocs.io/en/latest/#system-overview">
-            <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/img/tox_flow.png"
-                 alt="tox flow"
-                 width="800px"
-                 align="center">
-        </a>
-        
-        ### tox can be used for ...
-        
-        - creating development environments
-        - running static code analysis and test tools
-        - automating package builds
-        - running tests against the package build by tox
-        - checking that packages install correctly with different Python versions/interpreters
-        - unifying Continuous Integration and command line based testing
-        - building and deploying project documentation
-        - releasing a package to PyPI or any other platform
-        - limit: your imagination
-        
-        ### Documentation
-        
-        Documentation for tox can be found at [Read The Docs](https://tox.readthedocs.org).
-        
-        ### Communication and questions
-        
-        For the fastest and interactive feedback please join our
-        [![Discord](https://img.shields.io/discord/802911963368783933?style=flat-square)](https://discord.gg/edtj86wzBX) server.
-        If you have questions or suggestions you can first check if they have already been answered or discussed on our
-        [issue tracker](https://github.com/tox-dev/tox/issues?utf8=%E2%9C%93&q=is%3Aissue+sort%3Aupdated-desc+label%3A%22type%3Aquestion+%3Agrey_question%3A%22+).
-        On [Stack Overflow (tagged with `tox`)](https://stackoverflow.com/questions/tagged/tox).
-        
-        ### Contributing
-        
-        Contributions are welcome. See [contributing](https://github.com/tox-dev/tox/blob/master/CONTRIBUTING.rst) and our
-        [Contributor Covenant Code of Conduct](https://github.com/tox-dev/tox/blob/master/CODE_OF_CONDUCT.md).
-        
-        Currently the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
-        on Github.
-        
-        The project is licensed under [MIT](https://github.com/tox-dev/tox/blob/master/LICENSE).
-        
+Project-URL: Changelog, https://tox.readthedocs.io/en/latest/changelog.html
 Keywords: virtual,environments,isolated,testing
 Platform: any
 Classifier: Development Status :: 5 - Production/Stable
@@ -136,6 +27,7 @@ Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development :: Libraries
@@ -145,3 +37,115 @@ Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
 Description-Content-Type: text/markdown
 Provides-Extra: docs
 Provides-Extra: testing
+License-File: LICENSE
+
+[![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)](https://pypi.org/project/tox/)
+[![Supported Python
+versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/)
+[![check](https://github.com/tox-dev/tox/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/tox/actions/workflows/check.yml)
+[![Documentation
+status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest)
+[![Code style:
+black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+[![Downloads](https://pepy.tech/badge/tox/month)](https://pepy.tech/project/tox/month)
+
+<a href="https://tox.readthedocs.io">
+    <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/_static/img/tox.png"
+         alt="tox logo"
+         height="150px"
+         align="right">
+</a>
+
+# tox automation project
+
+**Command line driven CI frontend and development task automation tool**
+
+At its core tox provides a convenient way to run arbitrary commands in isolated environments to serve as a single entry
+point for build, test and release activities.
+
+tox is highly [configurable](https://tox.readthedocs.io/en/latest/config.html) and
+[pluggable](https://tox.readthedocs.io/en/latest/plugins.html).
+
+## Example: run tests with Python 3.7 and Python 3.8
+
+tox is mainly used as a command line tool and needs a `tox.ini` or a `tool.tox` section in `pyproject.toml` containing
+the configuration.
+
+To test a simple project that has some tests, here is an example with a `tox.ini` in the root of the project:
+
+```ini
+[tox]
+envlist = py37,py38
+
+[testenv]
+deps = pytest
+commands = pytest
+```
+
+```console
+$ tox
+
+[lots of output from what tox does]
+[lots of output from commands that were run]
+
+__________________ summary _________________
+  py37: commands succeeded
+  py38: commands succeeded
+  congratulations :)
+```
+
+tox created two `testenvs` - one based on Python 3.7 and one based on Python 3.8, it installed pytest in them and ran the
+tests. The report at the end summarizes which `testenvs` have failed and which have succeeded.
+
+**Note:** To learn more about what you can do with tox, have a look at
+[the collection of examples in the documentation](https://tox.readthedocs.io/en/latest/examples.html) or
+[existing projects using tox](https://github.com/search?l=INI&q=tox.ini+in%3Apath&type=Code).
+
+### How it works
+
+tox creates virtual environments for all configured so-called `testenvs`, it then installs the project and other
+necessary dependencies and runs the configured set of commands. See
+[system overview](https://tox.readthedocs.io/en/latest/#system-overview) for more details.
+
+<a href="https://tox.readthedocs.io/en/latest/#system-overview">
+    <img src="https://raw.githubusercontent.com/tox-dev/tox/master/docs/img/tox_flow.png"
+         alt="tox flow"
+         width="800px"
+         align="center">
+</a>
+
+### tox can be used for ...
+
+- creating development environments
+- running static code analysis and test tools
+- automating package builds
+- running tests against the package built by tox
+- checking that packages install correctly with different Python versions/interpreters
+- unifying Continuous Integration and command line based testing
+- building and deploying project documentation
+- releasing a package to PyPI or any other platform
+- limit: your imagination
+
+### Documentation
+
+Documentation for tox can be found at [Read The Docs](https://tox.readthedocs.org).
+
+### Communication and questions
+
+For the fastest and interactive feedback please join our
+[![Discord](https://img.shields.io/discord/802911963368783933?style=flat-square)](https://discord.gg/edtj86wzBX) server.
+If you have questions or suggestions you can first check if they have already been answered or discussed on our
+[issue tracker](https://github.com/tox-dev/tox/issues?utf8=%E2%9C%93&q=is%3Aissue+sort%3Aupdated-desc+label%3A%22type%3Aquestion+%3Agrey_question%3A%22+).
+On [Stack Overflow (tagged with `tox`)](https://stackoverflow.com/questions/tagged/tox).
+
+### Contributing
+
+Contributions are welcome. See [contributing](https://github.com/tox-dev/tox/blob/master/CONTRIBUTING.rst) and our
+[Contributor Covenant Code of Conduct](https://github.com/tox-dev/tox/blob/master/CODE_OF_CONDUCT.md).
+
+Currently, the [code](https://github.com/tox-dev/tox) and the [issues](https://github.com/tox-dev/tox/issues) are hosted
+on GitHub.
+
+The project is licensed under [MIT](https://github.com/tox-dev/tox/blob/master/LICENSE).
+
+
diff --git a/src/tox.egg-info/SOURCES.txt b/src/tox.egg-info/SOURCES.txt
index 25455ca..de1989b 100644
--- a/src/tox.egg-info/SOURCES.txt
+++ b/src/tox.egg-info/SOURCES.txt
@@ -1,5 +1,6 @@
 .gitignore
 .pre-commit-config.yaml
+.readthedocs.yml
 CODE_OF_CONDUCT.md
 CONTRIBUTING.rst
 CONTRIBUTORS
@@ -7,9 +8,7 @@ HOWTORELEASE.rst
 LICENSE
 MANIFEST.in
 README.md
-azure-pipelines.yml
 pyproject.toml
-readthedocs.yml
 setup.cfg
 setup.py
 tox.ini
@@ -18,6 +17,8 @@ tox.ini
 .github/config.yml
 .github/ISSUE_TEMPLATE/bug_report.md
 .github/ISSUE_TEMPLATE/feature_request.md
+.github/workflows/check.yml
+docs/_draft.rst
 docs/changelog.rst
 docs/conf.py
 docs/config.rst
@@ -110,8 +111,6 @@ src/tox/util/main.py
 src/tox/util/path.py
 src/tox/util/spinner.py
 src/tox/util/stdlib.py
-tasks/client_secret.json
-tasks/notify.py
 tasks/release.py
 tests/__init__.py
 tests/conftest.py
diff --git a/src/tox.egg-info/requires.txt b/src/tox.egg-info/requires.txt
index a1ad5b7..c9e3f88 100644
--- a/src/tox.egg-info/requires.txt
+++ b/src/tox.egg-info/requires.txt
@@ -21,12 +21,13 @@ towncrier>=18.5.0
 [testing]
 flaky>=3.4.0
 freezegun>=0.3.11
-psutil>=5.6.1
 pytest>=4.0.0
 pytest-cov>=2.5.1
 pytest-mock>=1.10.0
 pytest-randomly>=1.0.0
-pytest-xdist>=1.22.2
+
+[testing:platform_python_implementation == "cpython"]
+psutil>=5.6.1
 
 [testing:python_version < "3.4"]
 pathlib2>=2.3.3
diff --git a/src/tox/_pytestplugin.py b/src/tox/_pytestplugin.py
index c917634..d0c8703 100644
--- a/src/tox/_pytestplugin.py
+++ b/src/tox/_pytestplugin.py
@@ -491,7 +491,14 @@ def create_files(base, filedefs):
             create_files(base.ensure(key, dir=1), value)
         elif isinstance(value, six.string_types):
             s = textwrap.dedent(value)
-            base.join(key).write(s)
+
+            if not isinstance(s, six.text_type):
+                if not isinstance(s, six.binary_type):
+                    s = str(s)
+                else:
+                    s = six.ensure_text(s)
+
+            base.join(key).write_text(s, encoding="UTF-8")
 
 
 @pytest.fixture()
diff --git a/src/tox/_quickstart.py b/src/tox/_quickstart.py
index 1c7dfc2..175d970 100644
--- a/src/tox/_quickstart.py
+++ b/src/tox/_quickstart.py
@@ -223,8 +223,8 @@ def get_default_deps(commands):
 def post_process_input(map_):
     envlist = [env for env in tox.PYTHON.QUICKSTART_PY_ENVS if map_.get(env) is True]
     map_["envlist"] = ", ".join(envlist)
-    map_["commands"] = "\n    ".join([cmd.strip() for cmd in map_["commands"]])
-    map_["deps"] = "\n    ".join([dep.strip() for dep in set(map_["deps"])])
+    map_["commands"] = "\n    ".join(cmd.strip() for cmd in map_["commands"])
+    map_["deps"] = "\n    ".join(dep.strip() for dep in set(map_["deps"]))
 
 
 def generate(map_):
@@ -247,7 +247,7 @@ def generate(map_):
 
 
 def prepare_content(content):
-    return "\n".join([line.rstrip() for line in content.split("\n")])
+    return "\n".join(line.rstrip() for line in content.split("\n"))
 
 
 def parse_args():
diff --git a/src/tox/config/__init__.py b/src/tox/config/__init__.py
index 6004332..10acbe1 100644
--- a/src/tox/config/__init__.py
+++ b/src/tox/config/__init__.py
@@ -1,7 +1,9 @@
 from __future__ import print_function
 
 import argparse
+import io
 import itertools
+import json
 import os
 import random
 import re
@@ -59,9 +61,9 @@ SUICIDE_TIMEOUT = 0.0
 INTERRUPT_TIMEOUT = 0.3
 TERMINATE_TIMEOUT = 0.2
 
-_FACTOR_LINE_PATTERN = re.compile(r"^([\w{}\.!,-]+)\:\s+(.+)")
-_ENVSTR_SPLIT_PATTERN = re.compile(r"((?:\{[^}]+\})+)|,")
-_ENVSTR_EXPAND_PATTERN = re.compile(r"\{([^}]+)\}")
+_FACTOR_LINE_PATTERN = re.compile(r"^([\w{}.!,-]+):\s+(.+)")
+_ENVSTR_SPLIT_PATTERN = re.compile(r"((?:{[^}]+})+)|,")
+_ENVSTR_EXPAND_PATTERN = re.compile(r"{([^}]+)}")
 _WHITESPACE_PATTERN = re.compile(r"\s+")
 
 
@@ -302,7 +304,7 @@ def parseconfig(args, plugins=()):
 
 
 def get_py_project_toml(path):
-    with open(str(path)) as file_handler:
+    with io.open(str(path), encoding="UTF-8") as file_handler:
         config_data = toml.load(file_handler)
         return config_data
 
@@ -572,6 +574,16 @@ def tox_addoption(parser):
         action="store_true",
         help="override alwayscopy setting to True in all envs",
     )
+    parser.add_argument(
+        "--no-provision",
+        action="store",
+        nargs="?",
+        default=False,
+        const=True,
+        metavar="REQUIRES_JSON",
+        help="do not perform provision, but fail and if a path was provided "
+        "write provision metadata as JSON to it",
+    )
 
     cli_skip_missing_interpreter(parser)
     parser.add_argument("--workdir", metavar="PATH", help="tox working directory")
@@ -583,7 +595,10 @@ def tox_addoption(parser):
     )
 
     def _set_envdir_from_devenv(testenv_config, value):
-        if testenv_config.config.option.devenv is not None:
+        if (
+            testenv_config.config.option.devenv is not None
+            and testenv_config.envname != testenv_config.config.provision_tox_env
+        ):
             return py.path.local(testenv_config.config.option.devenv)
         else:
             return value
@@ -755,6 +770,7 @@ def tox_addoption(parser):
             "CURL_CA_BUNDLE",
             "LANG",
             "LANGUAGE",
+            "LC_ALL",
             "LD_LIBRARY_PATH",
             "PATH",
             "PIP_INDEX_URL",
@@ -1041,6 +1057,11 @@ class TestenvConfig:
             isinstance(self.python_info, NoInterpreterInfo)
             or tox.INFO.IS_WIN is False
             or self.python_info.implementation == "Jython"
+            or (
+                # this combination is MSYS2
+                tox.INFO.IS_WIN
+                and self.python_info.os_sep == "/"
+            )
             or (
                 tox.INFO.IS_WIN
                 and self.python_info.implementation == "PyPy"
@@ -1059,7 +1080,7 @@ class TestenvConfig:
         return self.get_envpython()
 
     def get_envpython(self):
-        """ path to python/jython executable. """
+        """path to python/jython executable."""
         if "jython" in str(self.basepython):
             name = "jython"
         else:
@@ -1295,11 +1316,11 @@ class ParseIni(object):
             feedback("--devenv requires only a single -e", sysexit=True)
 
     def handle_provision(self, config, reader):
-        requires_list = reader.getlist("requires")
+        config.requires = reader.getlist("requires")
         config.minversion = reader.getstring("minversion", None)
         config.provision_tox_env = name = reader.getstring("provision_tox_env", ".tox")
         min_version = "tox >= {}".format(config.minversion or Version(tox.__version__).public)
-        deps = self.ensure_requires_satisfied(config, requires_list, min_version)
+        deps = self.ensure_requires_satisfied(config, config.requires, min_version)
         if config.run_provision:
             section_name = "testenv:{}".format(name)
             if section_name not in self._cfg.sections:
@@ -1318,8 +1339,8 @@ class ParseIni(object):
         # raise on unknown args
         self.config._parser.parse_cli(args=self.config.args, strict=True)
 
-    @staticmethod
-    def ensure_requires_satisfied(config, requires, min_version):
+    @classmethod
+    def ensure_requires_satisfied(cls, config, requires, min_version):
         missing_requirements = []
         failed_to_parse = False
         deps = []
@@ -1346,12 +1367,33 @@ class ParseIni(object):
                 missing_requirements.append(str(requirements.Requirement(require)))
         if failed_to_parse:
             raise tox.exception.BadRequirement()
+        if config.option.no_provision and missing_requirements:
+            msg = "provisioning explicitly disabled within {}, but missing {}"
+            if config.option.no_provision is not True:  # it's a path
+                msg += " and wrote to {}"
+                cls.write_requires_to_json_file(config)
+            raise tox.exception.Error(
+                msg.format(sys.executable, missing_requirements, config.option.no_provision)
+            )
         if WITHIN_PROVISION and missing_requirements:
             msg = "break infinite loop provisioning within {} missing {}"
             raise tox.exception.Error(msg.format(sys.executable, missing_requirements))
         config.run_provision = bool(len(missing_requirements))
         return deps
 
+    @staticmethod
+    def write_requires_to_json_file(config):
+        requires_dict = {
+            "minversion": config.minversion,
+            "requires": config.requires,
+        }
+        try:
+            with open(config.option.no_provision, "w", encoding="utf-8") as outfile:
+                json.dump(requires_dict, outfile, indent=4)
+        except TypeError:  # Python 2
+            with open(config.option.no_provision, "w") as outfile:
+                json.dump(requires_dict, outfile, indent=4, encoding="utf-8")
+
     def parse_build_isolation(self, config, reader):
         config.isolated_build = reader.getbool("isolated_build", False)
         config.isolated_build_env = reader.getstring("isolated_build_env", ".package")
@@ -1374,7 +1416,7 @@ class ParseIni(object):
         factors = set()
         if section in self._cfg:
             for _, value in self._cfg[section].items():
-                exprs = re.findall(r"^([\w{}\.!,-]+)\:\s+", value, re.M)
+                exprs = re.findall(r"^([\w{}.!,-]+):\s+", value, re.M)
                 factors.update(*mapcat(_split_factor_expr_all, exprs))
         return factors
 
@@ -1456,9 +1498,10 @@ class ParseIni(object):
 
         env_list = []
         envlist_explicit = False
-        if (from_option and "ALL" in from_option) or (
-            not from_option and from_environ and "ALL" in from_environ.split(",")
-        ):
+        if (
+            (from_option and "ALL" in from_option)
+            or (not from_option and from_environ and "ALL" in from_environ.split(","))
+        ) and PARALLEL_ENV_VAR_KEY_PRIVATE not in os.environ:
             all_envs = self._getallenvs(reader)
         else:
             candidates = (
@@ -1498,7 +1541,7 @@ class ParseIni(object):
         The parser will see it as two different sections: [testenv:py36-cov], [testenv:py37-cov]
 
         """
-        factor_re = re.compile(r"\{\s*([\w\s,-]+)\s*\}")
+        factor_re = re.compile(r"{\s*([\w\s,-]+)\s*}")
         split_re = re.compile(r"\s*,\s*")
         to_remove = set()
         for section in list(config.sections):
@@ -1514,12 +1557,12 @@ class ParseIni(object):
 
 
 def _split_env(env):
-    """if handed a list, action="append" was used for -e """
+    """if handed a list, action="append" was used for -e"""
     if env is None:
         return []
     if not isinstance(env, list):
         env = [e.split("#", 1)[0].strip() for e in env.split("\n")]
-        env = ",".join([e for e in env if e])
+        env = ",".join(e for e in env if e)
         env = [env]
     return mapcat(_expand_envstr, env)
 
@@ -1708,7 +1751,7 @@ class SectionReader:
     def getargv_install_command(self, name, default="", replace=True):
         s = self.getstring(name, default, replace=False)
         if not s:
-            # This occurs when factors are used, and a testenv doesnt have
+            # This occurs when factors are used, and a testenv doesn't have
             # a factorised value for install_command, most commonly occurring
             # if setting platform is also used.
             # An empty value causes error install_command must contain '{packages}'.
@@ -1751,7 +1794,7 @@ class SectionReader:
             if sys.platform.startswith("win"):
                 posargs_string = list2cmdline([x for x in posargs if x])
             else:
-                posargs_string = " ".join([shlex_quote(x) for x in posargs if x])
+                posargs_string = " ".join(shlex_quote(x) for x in posargs if x)
             return posargs_string
         else:
             return default or ""
diff --git a/src/tox/helper/build_isolated.py b/src/tox/helper/build_isolated.py
index 3d89709..4c57c57 100644
--- a/src/tox/helper/build_isolated.py
+++ b/src/tox/helper/build_isolated.py
@@ -29,7 +29,7 @@ def _ensure_module_in_paths(module, paths):
 dist_folder = sys.argv[1]
 backend_spec = sys.argv[2]
 backend_obj = sys.argv[3] if len(sys.argv) >= 4 else None
-backend_paths = sys.argv[4].split(os.path.pathsep) if sys.argv[4] else []
+backend_paths = sys.argv[4].split(os.path.pathsep) if (len(sys.argv) >= 5 and sys.argv[4]) else []
 
 sys.path[:0] = backend_paths
 
diff --git a/src/tox/helper/build_requires.py b/src/tox/helper/build_requires.py
index aafb258..a91671c 100644
--- a/src/tox/helper/build_requires.py
+++ b/src/tox/helper/build_requires.py
@@ -12,6 +12,13 @@ backend = __import__(backend_spec, fromlist=["_trash"])
 if backend_obj:
     backend = getattr(backend, backend_obj)
 
-for_build_requires = backend.get_requires_for_build_sdist(None)
+try:
+    for_build_requires = backend.get_requires_for_build_sdist(None)
+except AttributeError:
+    # PEP 517 states that get_requires_for_build_sdist is optional for a build
+    # backend object. When the backend object omits it, the default
+    # implementation must be equivalent to return []
+    for_build_requires = []
+
 output = json.dumps(for_build_requires)
 print(output)
diff --git a/src/tox/helper/get_site_package_dir.py b/src/tox/helper/get_site_package_dir.py
index 584f510..adb6ca1 100644
--- a/src/tox/helper/get_site_package_dir.py
+++ b/src/tox/helper/get_site_package_dir.py
@@ -1,8 +1,22 @@
 from __future__ import unicode_literals
 
-import distutils.sysconfig
 import json
 import sys
+import sysconfig
+import warnings
 
-data = json.dumps({"dir": distutils.sysconfig.get_python_lib(prefix=sys.argv[1])})
-print(data)
+dest_prefix = sys.argv[1]
+with warnings.catch_warnings():  # disable warning for PEP-632
+    warnings.simplefilter("ignore")
+    try:
+        import distutils.sysconfig
+
+        data = distutils.sysconfig.get_python_lib(prefix=dest_prefix)
+    except ImportError:  # if removed or not installed ignore
+        config_vars = {
+            k: dest_prefix if any(v == p for p in (sys.prefix, sys.base_prefix)) else v
+            for k, v in sysconfig.get_config_vars().items()
+        }
+        data = sysconfig.get_path("purelib", vars=config_vars)
+
+print(json.dumps({"dir": data}))
diff --git a/src/tox/helper/get_version.py b/src/tox/helper/get_version.py
index b1a8455..8f370e5 100644
--- a/src/tox/helper/get_version.py
+++ b/src/tox/helper/get_version.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 import json
+import os
 import platform
 import sys
 
@@ -11,6 +12,7 @@ info = {
     "version": sys.version,
     "is_64": sys.maxsize > 2 ** 32,
     "sysplatform": sys.platform,
+    "os_sep": os.sep,
     "extra_version_info": getattr(sys, "pypy_version_info", None),
 }
 info_as_dump = json.dumps(info)
diff --git a/src/tox/hookspecs.py b/src/tox/hookspecs.py
index 90374cf..5ea9c07 100644
--- a/src/tox/hookspecs.py
+++ b/src/tox/hookspecs.py
@@ -6,7 +6,7 @@ hookspec = pluggy.HookspecMarker("tox")
 
 @hookspec
 def tox_addoption(parser):
-    """ add command line options to the argparse-style parser object."""
+    """add command line options to the argparse-style parser object."""
 
 
 @hookspec
diff --git a/src/tox/interpreters/__init__.py b/src/tox/interpreters/__init__.py
index a313140..7bc2fbd 100644
--- a/src/tox/interpreters/__init__.py
+++ b/src/tox/interpreters/__init__.py
@@ -103,6 +103,7 @@ class InterpreterInfo:
         version_info,
         sysplatform,
         is_64,
+        os_sep,
         extra_version_info,
     ):
         self.implementation = implementation
@@ -111,6 +112,7 @@ class InterpreterInfo:
         self.version_info = version_info
         self.sysplatform = sysplatform
         self.is_64 = is_64
+        self.os_sep = os_sep
         self.extra_version_info = extra_version_info
 
     def __str__(self):
diff --git a/src/tox/logs/env.py b/src/tox/logs/env.py
index c941f24..ff8fc8e 100644
--- a/src/tox/logs/env.py
+++ b/src/tox/logs/env.py
@@ -28,7 +28,7 @@ class EnvLog(object):
 
     def set_header(self, installpkg):
         """
-        :param py.path.local installpkg: Path ot the package.
+        :param py.path.local installpkg: Path to the package.
         """
         self.dict["installpkg"] = {
             "sha256": installpkg.computehash("sha256"),
diff --git a/src/tox/package/__init__.py b/src/tox/package/__init__.py
index f692516..9a32f3f 100644
--- a/src/tox/package/__init__.py
+++ b/src/tox/package/__init__.py
@@ -18,7 +18,7 @@ def tox_package(session, venv):
 
 
 def get_package(session):
-    """"Perform the package operation"""
+    """Perform the package operation"""
     config = session.config
     if config.skipsdist:
         info("skipping sdist step")
diff --git a/src/tox/package/local.py b/src/tox/package/local.py
index aa0751b..0ae8615 100644
--- a/src/tox/package/local.py
+++ b/src/tox/package/local.py
@@ -49,7 +49,7 @@ def get_latest_version_of_package(package_spec):
         return candidates[0]
 
 
-_REGEX_FILE_NAME_WITH_VERSION = re.compile(r"[\w_\-\+\.]+-(.*)\.(zip|tar\.gz)")
+_REGEX_FILE_NAME_WITH_VERSION = re.compile(r"[\w_+.-]+-(.*)\.(zip|tar\.gz)")
 
 
 def get_version_from_filename(basename):
diff --git a/src/tox/reporter.py b/src/tox/reporter.py
index d954ab2..17a3c92 100644
--- a/src/tox/reporter.py
+++ b/src/tox/reporter.py
@@ -42,7 +42,7 @@ class Reporter(object):
         return self.verbose_level - self.quiet_level
 
     def log_popen(self, cwd, outpath, cmd_args_shell, pid):
-        """ log information about the action.popen() created process. """
+        """log information about the action.popen() created process."""
         msg = "[{}] {}$ {}".format(pid, cwd, cmd_args_shell)
         if outpath:
             if outpath.common(cwd) is not None:
diff --git a/src/tox/session/commands/show_config.py b/src/tox/session/commands/show_config.py
index 7fb03a2..f0ff955 100644
--- a/src/tox/session/commands/show_config.py
+++ b/src/tox/session/commands/show_config.py
@@ -2,7 +2,6 @@ import sys
 from collections import OrderedDict
 
 from packaging.requirements import Requirement
-from packaging.utils import canonicalize_name
 from six import StringIO
 from six.moves import configparser
 
@@ -65,16 +64,15 @@ def version_info(parser):
     while to_visit:
         current = to_visit.pop()
         current_dist = importlib_metadata.distribution(current)
-        current_name = canonicalize_name(current_dist.metadata["name"])
+        current_name = current_dist.metadata["name"]
         versions[current_name] = current_dist.version
         if current_dist.requires is not None:
             for require in current_dist.requires:
                 pkg = Requirement(require)
-                pkg_name = canonicalize_name(pkg.name)
                 if (
                     pkg.marker is None or pkg.marker.evaluate({"extra": ""})
-                ) and pkg_name not in versions:
-                    to_visit.add(pkg_name)
+                ) and pkg.name not in versions:
+                    to_visit.add(pkg.name)
     set_section(parser, "tox:versions", versions)
 
 
diff --git a/src/tox/util/spinner.py b/src/tox/util/spinner.py
index 6241a29..ee22589 100644
--- a/src/tox/util/spinner.py
+++ b/src/tox/util/spinner.py
@@ -5,7 +5,7 @@ from __future__ import absolute_import, unicode_literals
 import os
 import sys
 import threading
-from collections import OrderedDict
+from collections import OrderedDict, namedtuple
 from datetime import datetime
 
 import py
@@ -19,34 +19,32 @@ if os.name == "nt":
         _fields_ = [("size", ctypes.c_int), ("visible", ctypes.c_byte)]
 
 
-def _file_support_encoding(chars, file):
-    encoding = getattr(file, "encoding", None)
-    if encoding is not None:
-        for char in chars:
-            try:
-                char.encode(encoding)
-            except UnicodeEncodeError:
-                break
+_BaseMessage = namedtuple("_BaseMessage", ["unicode_msg", "ascii_msg"])
+
+
+class SpinnerMessage(_BaseMessage):
+    def for_file(self, file):
+        try:
+            self.unicode_msg.encode(file.encoding)
+        except (AttributeError, TypeError, UnicodeEncodeError):
+            return self.ascii_msg
         else:
-            return True
-    return False
+            return self.unicode_msg
 
 
 class Spinner(object):
     CLEAR_LINE = "\033[K"
     max_width = 120
-    UNICODE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
-    ASCII_FRAMES = ["|", "-", "+", "x", "*"]
+    FRAMES = SpinnerMessage("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏", "|-+x*")
+    OK_FLAG = SpinnerMessage("✔ OK", "[ OK ]")
+    FAIL_FLAG = SpinnerMessage("✖ FAIL", "[FAIL]")
+    SKIP_FLAG = SpinnerMessage("⚠ SKIP", "[SKIP]")
 
     def __init__(self, enabled=True, refresh_rate=0.1):
         self.refresh_rate = refresh_rate
         self.enabled = enabled
         self._file = sys.stdout
-        self.frames = (
-            self.UNICODE_FRAMES
-            if _file_support_encoding(self.UNICODE_FRAMES, sys.stdout)
-            else self.ASCII_FRAMES
-        )
+        self.frames = self.FRAMES.for_file(self._file)
         self.stream = py.io.TerminalWriter(file=self._file)
         self._envs = OrderedDict()
         self._frame_index = 0
@@ -84,7 +82,7 @@ class Spinner(object):
         self.render_frame()
         self._stop_spinner = threading.Event()
         self._spinner_thread = threading.Thread(target=self.render)
-        self._spinner_thread.setDaemon(True)
+        self._spinner_thread.daemon = True
         self._spinner_thread.start()
         return self
 
@@ -105,13 +103,13 @@ class Spinner(object):
         self._envs[name] = datetime.now()
 
     def succeed(self, key):
-        self.finalize(key, "✔ OK", green=True)
+        self.finalize(key, self.OK_FLAG.for_file(self._file), green=True)
 
     def fail(self, key):
-        self.finalize(key, "✖ FAIL", red=True)
+        self.finalize(key, self.FAIL_FLAG.for_file(self._file), red=True)
 
     def skip(self, key):
-        self.finalize(key, "⚠ SKIP", white=True)
+        self.finalize(key, self.SKIP_FLAG.for_file(self._file), white=True)
 
     def finalize(self, key, status, **kwargs):
         start_at = self._envs[key]
diff --git a/src/tox/venv.py b/src/tox/venv.py
index 5390e97..cdd6949 100644
--- a/src/tox/venv.py
+++ b/src/tox/venv.py
@@ -19,6 +19,9 @@ from tox.util.path import ensure_empty_dir
 
 from .config import DepConfig
 
+#: maximum parsed shebang interpreter length (see: prepend_shebang_interpreter)
+MAXINTERP = 2048
+
 
 class CreationConfig:
     def __init__(
@@ -154,7 +157,7 @@ class VirtualEnv(object):
 
     @property
     def path(self):
-        """ Path to environment base dir. """
+        """Path to environment base dir."""
         return self.envconfig.envdir
 
     @property
@@ -163,7 +166,7 @@ class VirtualEnv(object):
 
     @property
     def name(self):
-        """ test environment name. """
+        """test environment name."""
         return self.envconfig.envname
 
     def __repr__(self):
@@ -322,6 +325,10 @@ class VirtualEnv(object):
 
     def _needs_reinstall(self, setupdir, action):
         setup_py = setupdir.join("setup.py")
+
+        if not setup_py.exists():
+            return False
+
         setup_cfg = setupdir.join("setup.cfg")
         args = [self.envconfig.envpython, str(setup_py), "--name"]
         env = self._get_os_environ()
@@ -527,7 +534,7 @@ class VirtualEnv(object):
                 # happens if the same environment is invoked twice
                 message = "commands[{}] | {}".format(
                     i,
-                    " ".join([pipes.quote(str(x)) for x in argv]),
+                    " ".join(pipes.quote(str(x)) for x in argv),
                 )
                 action.setactivity(name, message)
                 # check to see if we need to ignore the return code
@@ -609,10 +616,8 @@ class VirtualEnv(object):
                 "unresolvable substitution(s):\n    {}\n"
                 "Environment variables are missing or defined recursively.".format(
                     "\n    ".join(
-                        [
-                            "{}: '{}'".format(section_key, exc.name)
-                            for section_key, exc in sorted(self.envconfig._missing_subs.items())
-                        ],
+                        "{}: '{}'".format(section_key, exc.name)
+                        for section_key, exc in sorted(self.envconfig._missing_subs.items())
                     ),
                 )
             )
@@ -674,7 +679,7 @@ def prepend_shebang_interpreter(args):
     #
     # When preparing virtual environments in a file container which has large
     # length, the system might not be able to invoke shebang scripts which
-    # define interpreters beyond system limits (e.x. Linux as a limit of 128;
+    # define interpreters beyond system limits (e.g. Linux has a limit of 128;
     # BINPRM_BUF_SIZE). This method can be used to check if the executable is
     # a script containing a shebang line. If so, extract the interpreter (and
     # possible optional argument) and prepend the values to the provided
@@ -684,8 +689,9 @@ def prepend_shebang_interpreter(args):
     try:
         with open(args[0], "rb") as f:
             if f.read(1) == b"#" and f.read(1) == b"!":
-                MAXINTERP = 2048
-                interp = f.readline(MAXINTERP).rstrip().decode("UTF-8")
+                interp = f.readline(MAXINTERP + 1).rstrip().decode("UTF-8")
+                if len(interp) > MAXINTERP:  # avoid a truncated interpreter
+                    return args
                 interp_args = interp.split(None, 1)[:2]
                 return interp_args + args
     except (UnicodeDecodeError, IOError):
diff --git a/src/tox/version.py b/src/tox/version.py
index 0329f82..75cc4cf 100644
--- a/src/tox/version.py
+++ b/src/tox/version.py
@@ -1,4 +1,4 @@
 # coding: utf-8
 from __future__ import unicode_literals
 
-__version__ = '3.21.4'
+__version__ = '3.24.5'
diff --git a/tasks/client_secret.json b/tasks/client_secret.json
deleted file mode 100644
index 20c59ad..0000000
--- a/tasks/client_secret.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "installed": {
-    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
-    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
-    "client_id": "84180756337-bd32ogk9j5nbu71srlsko923r8s78ler.apps.googleusercontent.com",
-    "client_secret": "",
-    "project_id": "send-notificatio-1530696447231",
-    "redirect_uris": [
-      "urn:ietf:wg:oauth:2.0:oob",
-      "http://localhost"
-    ],
-    "token_uri": "https://accounts.google.com/o/oauth2/token"
-  }
-}
diff --git a/tasks/notify.py b/tasks/notify.py
deleted file mode 100644
index d9e48a9..0000000
--- a/tasks/notify.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Handles creating a release PR"""
-import base64
-import json
-import os
-import tempfile
-import textwrap
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-from pathlib import Path
-from typing import Tuple
-
-import httplib2
-from apiclient import discovery
-from git import Remote, Repo
-from oauth2client import client, file, tools
-from packaging.version import Version
-
-ROOT_SRC_DIR = Path(__file__).parents[1]
-
-
-def main() -> None:
-    repo = Repo(str(ROOT_SRC_DIR))
-    update_upstream(repo)
-    prev_version, release_version = get_last_release_versions(repo)
-    send_mail_message(
-        subject=f"tox release {release_version}",
-        content=get_message_body(release_version, prev_version),
-    )
-    print("All done! ✨ 🍰 ✨")
-
-
-def get_message_body(release_version: Version, prev_version: Version) -> str:
-    is_major_release = release_version.release[0:2] != prev_version.release[0:2]
-    if is_major_release:
-        return textwrap.dedent(
-            f"""
-        The tox team is proud to announce the {release_version} feature release at https://pypi.org/project/tox/!
-
-        tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software.
-
-        Details about the changes can be found at https://tox.readthedocs.io/en/{release_version}/changelog.html
-        For complete documentation, please visit: https://tox.readthedocs.io/en/{release_version}/
-
-        As usual, you can upgrade from PyPI via:
-
-            pip install --upgrade tox
-
-        or - if you also want to get pre release versions:
-
-            pip install -upgrade --pre tox
-
-        We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed.
-
-        Happy toxing,
-        the tox-dev team
-        """,  # noqa
-        )
-    else:
-        return textwrap.dedent(
-            f"""
-                The tox team is proud to announce the {release_version} bug fix release at https://pypi.org/project/tox/!
-
-                tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software.
-
-                For details about the fix(es),please check the CHANGELOG: https://tox.readthedocs.io/en/{release_version}/changelog.html
-
-                We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed.
-
-                Happy toxing,
-                the tox-dev team
-                """,  # noqa
-        )
-
-
-def get_upstream(repo: Repo) -> Remote:
-    for remote in repo.remotes:
-        for url in remote.urls:
-            if url.endswith("tox-dev/tox.git"):
-                return remote
-    raise RuntimeError("could not find tox-dev/tox.git remote")
-
-
-def get_last_release_versions(repo: Repo) -> Tuple[Version, Version]:
-    print("get latest release version")
-    commit_to_tag = {tag.commit.hexsha: tag for tag in repo.tags}
-    _, release_tag = sorted(
-        [(tag.commit.committed_datetime, tag) for tag in repo.tags],
-        reverse=True,
-    )[0]
-    for commit in release_tag.commit.iter_parents():
-        if commit.hexsha in commit_to_tag:
-            prev_release_tag = commit_to_tag[commit.hexsha]
-            prev_version = Version(prev_release_tag.name)
-            if not any(
-                (
-                    prev_version.is_devrelease,
-                    prev_version.is_prerelease,
-                    prev_version.is_postrelease,
-                ),
-            ):
-                break
-    else:
-        raise RuntimeError("no previous release")
-    release_version = Version(release_tag.name)
-    print(f"\trelease {release_version} with previous {prev_version}")
-    return prev_version, release_version
-
-
-def update_upstream(repo: Repo) -> None:
-    print("fetch latest remote")
-    upstream = get_upstream(repo)
-    upstream.fetch()
-
-
-def send_mail_message(subject, content):
-    this_dir = Path(__file__).parent
-    store = file.Storage("credentials.json")
-    credentials = store.get()
-    if not credentials or credentials.invalid:
-        client_secret_json = json.loads((this_dir / "client_secret.json").read_text())
-        client_secret_json["installed"]["client_secret"] = os.environ["TOX_DEV_GOOGLE_SECRET"]
-        with tempfile.NamedTemporaryFile(mode="w+t") as temp_filename:
-            json.dump(client_secret_json, temp_filename)
-            temp_filename.flush()
-            flow = client.flow_from_clientsecrets(
-                filename=temp_filename.name,
-                scope="https://www.googleapis.com/auth/gmail.send",
-            )
-            credentials = tools.run_flow(flow, store)
-    service = discovery.build("gmail", "v1", http=credentials.authorize(httplib2.Http()))
-
-    message = MIMEMultipart("alternative")
-    message["Subject"] = subject
-    message["From"] = "toxdevorg@gmail.com"
-    recipients = ["testing-in-python@lists.idyll.org", "tox-dev@python.org"]
-    message["To"] = ", ".join(recipients)
-    message.attach(MIMEText(content, "plain"))
-    raw_message_no_attachment = base64.urlsafe_b64encode(message.as_bytes())
-    raw_message_no_attachment = raw_message_no_attachment.decode()
-    body = {"raw": raw_message_no_attachment}
-    message_sent = service.users().messages().send(userId="me", body=body).execute()
-    message_id = message_sent["id"]
-    print(f"\tMessage sent with id: {message_id}")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/tasks/release.py b/tasks/release.py
index 503adab..52066cb 100644
--- a/tasks/release.py
+++ b/tasks/release.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """Handles creating a release PR"""
 from pathlib import Path
 from subprocess import check_call
@@ -57,9 +56,9 @@ def tag_release_commit(release_commit, repo, version) -> TagReference:
     print("tag release commit")
     existing_tags = [x.name for x in repo.tags]
     if version in existing_tags:
-        print("delete existing tag {}".format(version))
+        print(f"delete existing tag {version}")
         repo.delete_tag(version)
-    print("create tag {}".format(version))
+    print(f"create tag {version}")
     tag = repo.create_tag(version, ref=release_commit, force=True)
     return tag
 
diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py
index fe11224..d6ff0ab 100644
--- a/tests/unit/config/test_config.py
+++ b/tests/unit/config/test_config.py
@@ -1,3 +1,4 @@
+# coding=utf-8
 import os
 import re
 import sys
@@ -7,6 +8,7 @@ import py
 import pytest
 from pluggy import PluginManager
 from six import PY2
+from virtualenv.info import IS_PYPY
 
 import tox
 from tox.config import (
@@ -1452,6 +1454,7 @@ class TestConfigTestEnv:
         assert envconfig.envpython == envconfig.envbindir.join("python")
 
     @pytest.mark.parametrize("bp", ["jython", "pypy", "pypy3"])
+    @pytest.mark.skipif(IS_PYPY, reason="fails on pypy")
     def test_envbindir_jython(self, newconfig, bp):
         config = newconfig(
             """
@@ -1468,6 +1471,23 @@ class TestConfigTestEnv:
         if bp == "jython":
             assert envconfig.envpython == envconfig.envbindir.join(bp)
 
+    @pytest.mark.skipif(tox.INFO.IS_PYPY, reason="only applies to CPython")
+    @pytest.mark.parametrize("sep, bindir", [("\\", "Scripts"), ("/", "bin")])
+    def test_envbindir_win(self, newconfig, monkeypatch, sep, bindir):
+        monkeypatch.setattr(tox.INFO, "IS_WIN", True)
+        config = newconfig(
+            """
+            [testenv]
+            basepython=python
+        """,
+        )
+        assert len(config.envconfigs) == 1
+        envconfig = config.envconfigs["python"]
+        envconfig.python_info.os_sep = sep  # force os.sep result
+        # on win32 with msys2, virtualenv uses "bin" for python
+        assert envconfig.envbindir.basename == bindir
+        assert envconfig.envpython == envconfig.envbindir.join("python")
+
     @pytest.mark.parametrize("plat", ["win32", "linux2"])
     def test_passenv_as_multiline_list(self, newconfig, monkeypatch, plat):
         monkeypatch.setattr(tox.INFO, "IS_WIN", plat == "win32")
@@ -1938,7 +1958,7 @@ class TestConfigTestEnv:
                 frob{{env:ENV_VAR:>1.0,<2.0}}
         """.format(
             envlist=",".join(envlist),
-            deps="\n" + "\n".join([" " * 17 + d for d in deps]),
+            deps="\n" + "\n".join(" " * 17 + d for d in deps),
         )
         conf = newconfig([], inisource).envconfigs["py27"]
         packages = [dep.name for dep in conf.deps]
@@ -2366,24 +2386,23 @@ class TestConfigTestEnv:
         for name, config in configs.items():
             assert config.basepython == "python{}.{}".format(name[2], name[3])
 
+    @pytest.mark.skipif(IS_PYPY, reason="fails on pypy")
     def test_default_factors_conflict(self, newconfig, capsys):
         with pytest.warns(UserWarning, match=r"conflicting basepython .*"):
-            exe = "pypy3" if tox.INFO.IS_PYPY else "python3"
             env = "pypy27" if tox.INFO.IS_PYPY else "py27"
             config = newconfig(
                 """\
                 [testenv]
-                basepython={}
+                basepython=python3
                 [testenv:{}]
                 commands = python --version
                 """.format(
-                    exe,
-                    env,
+                    env
                 ),
             )
         assert len(config.envconfigs) == 1
         envconfig = config.envconfigs[env]
-        assert envconfig.basepython == exe
+        assert envconfig.basepython == "python3"
 
     def test_default_factors_conflict_lying_name(
         self,
@@ -3556,7 +3575,10 @@ def test_config_via_pyproject_legacy(initproj):
     initproj(
         "config_via_pyproject_legacy-0.5",
         filedefs={
-            "pyproject.toml": '''
+            "pyproject.toml": u'''
+                [project]
+                description = "Factory ⸻ A code generator 🏭"
+                authors = [{name = "Łukasz Langa"}]
                 [tool.tox]
                 legacy_tox_ini = """
                 [tox]
diff --git a/tests/unit/config/test_config_parallel.py b/tests/unit/config/test_config_parallel.py
index 785b771..f070ca8 100644
--- a/tests/unit/config/test_config_parallel.py
+++ b/tests/unit/config/test_config_parallel.py
@@ -1,5 +1,7 @@
 import pytest
 
+from tox.config.parallel import ENV_VAR_KEY_PRIVATE as PARALLEL_ENV_VAR_KEY_PRIVATE
+
 
 def test_parallel_default(newconfig):
     config = newconfig([], "")
@@ -38,7 +40,7 @@ def test_parallel_number_negative(newconfig, capsys):
     assert "value must be positive" in err
 
 
-def test_depends(newconfig, capsys):
+def test_depends(newconfig):
     config = newconfig(
         """\
         [tox]
@@ -49,7 +51,7 @@ def test_depends(newconfig, capsys):
     assert config.envconfigs["py"].depends == ("py37", "py36")
 
 
-def test_depends_multi_row_facotr(newconfig, capsys):
+def test_depends_multi_row_facotr(newconfig):
     config = newconfig(
         """\
         [tox]
@@ -61,7 +63,7 @@ def test_depends_multi_row_facotr(newconfig, capsys):
     assert config.envconfigs["py"].depends == ("py37", "py36-a", "py36-b")
 
 
-def test_depends_factor(newconfig, capsys):
+def test_depends_factor(newconfig):
     config = newconfig(
         """\
         [tox]
@@ -70,3 +72,17 @@ def test_depends_factor(newconfig, capsys):
         """,
     )
     assert config.envconfigs["py"].depends == ("py37-cov", "py37-no", "py36-cov", "py36-no")
+
+
+def test_parallel_env_selection_with_ALL(newconfig, monkeypatch):
+    # Regression test for #2167
+    inisource = """
+        [tox]
+        envlist = py,lint
+    """
+    monkeypatch.setenv(PARALLEL_ENV_VAR_KEY_PRIVATE, "py")
+    config = newconfig(["-eALL"], inisource)
+    assert config.envlist == ["py"]
+    monkeypatch.setenv(PARALLEL_ENV_VAR_KEY_PRIVATE, "lint")
+    config = newconfig(["-eALL"], inisource)
+    assert config.envlist == ["lint"]
diff --git a/tests/unit/interpreters/test_interpreters.py b/tests/unit/interpreters/test_interpreters.py
index fd364ba..298a4aa 100644
--- a/tests/unit/interpreters/test_interpreters.py
+++ b/tests/unit/interpreters/test_interpreters.py
@@ -192,7 +192,9 @@ class TestInterpreterInfo:
         version_info="my-version-info",
         sysplatform="my-sys-platform",
     ):
-        return InterpreterInfo(implementation, executable, version_info, sysplatform, True, None)
+        return InterpreterInfo(
+            implementation, executable, version_info, sysplatform, True, "/", None
+        )
 
     def test_data(self):
         x = self.info("larry", "moe", "shemp", "curly")
diff --git a/tests/unit/package/builder/test_package_builder_isolated.py b/tests/unit/package/builder/test_package_builder_isolated.py
index 458e43b..9501f40 100644
--- a/tests/unit/package/builder/test_package_builder_isolated.py
+++ b/tests/unit/package/builder/test_package_builder_isolated.py
@@ -1,8 +1,10 @@
 import os
+import subprocess
 
 import py
 import pytest
 
+import tox.helper
 from tox.package.builder.isolated import get_build_info
 from tox.reporter import _INSTANCE
 
@@ -25,7 +27,7 @@ def test_verbose_isolated_build(initproj, mock_venv, cmd):
     result = cmd("--sdistonly", "-v", "-v", "-v", "-e", "py")
     assert "running sdist" in result.out, result.out
     assert "running egg_info" in result.out, result.out
-    assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out
+    assert "example123-0.5.tar.gz" in result.out, result.out
 
 
 def test_dist_exists_version_change(mock_venv, initproj, cmd):
@@ -192,4 +194,79 @@ def test_verbose_isolated_build_in_tree(initproj, mock_venv, cmd):
     result = cmd("--sdistonly", "-v", "-v", "-v", "-e", "py")
     assert "running sdist" in result.out, result.out
     assert "running egg_info" in result.out, result.out
-    assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out
+    assert "example123-0.5.tar.gz" in result.out, result.out
+
+
+def test_isolated_build_script_args(tmp_path):
+    """Verify that build_isolated.py can be called with only 2 argurments."""
+    # cannot import build_isolated because of its side effects
+    script_path = os.path.join(os.path.dirname(tox.helper.__file__), "build_isolated.py")
+    subprocess.check_call(("python", script_path, str(tmp_path), "setuptools.build_meta"))
+
+
+def test_isolated_build_backend_missing_hook(initproj, cmd):
+    """Verify that tox works with a backend missing optional hooks
+
+    PEP 517 allows backends to omit get_requires_for_build_sdist hook, in which
+    case a default implementation that returns an empty list should be assumed
+    instead of raising an error.
+    """
+    name = "ensconsproj"
+    version = "0.1"
+    src_root = "src"
+
+    initproj(
+        (name, version),
+        filedefs={
+            "pyproject.toml": """
+            [build-system]
+            requires = ["pytoml>=0.1", "enscons==0.26.0"]
+            build-backend = "enscons.api"
+
+            [tool.enscons]
+            name = "{name}"
+            version = "{version}"
+            description = "Example enscons project"
+            license = "MIT"
+            packages = ["{name}"]
+            src_root = "{src_root}"
+            """.format(
+                name=name, version=version, src_root=src_root
+            ),
+            "tox.ini": """
+            [tox]
+            isolated_build = true
+            """,
+            "SConstruct": """
+            import enscons
+
+            env = Environment(
+                tools=["default", "packaging", enscons.generate],
+                PACKAGE_METADATA=dict(
+                    name = "{name}",
+                    version = "{version}"
+                ),
+                WHEEL_TAG="py2.py3-none-any"
+            )
+
+            py_source = env.Glob("src/{name}/*.py")
+
+            purelib = env.Whl("purelib", py_source, root="{src_root}")
+            whl = env.WhlFile(purelib)
+
+            sdist = env.SDist(source=FindSourceFiles() + ["PKG-INFO"])
+            env.NoClean(sdist)
+            env.Alias("sdist", sdist)
+
+            develop = env.Command("#DEVELOP", enscons.egg_info_targets(env), enscons.develop)
+            env.Alias("develop", develop)
+
+            env.Default(whl, sdist)
+            """.format(
+                name=name, version=version, src_root=src_root
+            ),
+        },
+    )
+
+    result = cmd("--sdistonly", "-v", "-v", "-e", "py")
+    assert "scons: done building targets" in result.out, result.out
diff --git a/tests/unit/package/builder/test_package_builder_legacy.py b/tests/unit/package/builder/test_package_builder_legacy.py
index 70b318a..69b9509 100644
--- a/tests/unit/package/builder/test_package_builder_legacy.py
+++ b/tests/unit/package/builder/test_package_builder_legacy.py
@@ -1,6 +1,3 @@
-import os
-
-
 def test_verbose_legacy_build(initproj, mock_venv, cmd):
     initproj(
         "example123-0.5",
@@ -14,4 +11,4 @@ def test_verbose_legacy_build(initproj, mock_venv, cmd):
     result = cmd("--sdistonly", "-vvv", "-e", "py")
     assert "running sdist" in result.out, result.out
     assert "running egg_info" in result.out, result.out
-    assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out
+    assert "removing 'example123-0.5'" in result.out, result.out
diff --git a/tests/unit/package/test_package_view.py b/tests/unit/package/test_package_view.py
index 989ed9c..a05443c 100644
--- a/tests/unit/package/test_package_view.py
+++ b/tests/unit/package/test_package_view.py
@@ -1,10 +1,14 @@
 import os
 
+import pytest
+from virtualenv.info import IS_PYPY
+
 from tox.config import parseconfig
 from tox.package import get_package
 from tox.session import Session
 
 
+@pytest.mark.skipif(IS_PYPY, reason="fails on pypy")
 def test_make_sdist_distshare(tmpdir, initproj):
     distshare = tmpdir.join("distshare")
     initproj(
diff --git a/tests/unit/session/test_provision.py b/tests/unit/session/test_provision.py
index 3065932..24f7b3d 100644
--- a/tests/unit/session/test_provision.py
+++ b/tests/unit/session/test_provision.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import, unicode_literals
 
+import json
 import os
 import shutil
 import subprocess
@@ -7,6 +8,7 @@ import sys
 
 import py
 import pytest
+from virtualenv.info import IS_PYPY
 
 if sys.version_info[:2] >= (3, 4):
     from pathlib import Path
@@ -47,6 +49,35 @@ def test_provision_min_version_is_requires(newconfig, next_tox_major):
     assert config.ignore_basepython_conflict is False
 
 
+def test_provision_config_has_minversion_and_requires(newconfig, next_tox_major):
+    with pytest.raises(MissingRequirement) as context:
+        newconfig(
+            [],
+            """\
+            [tox]
+            minversion = {}
+            requires =
+                setuptools > 2
+                pip > 3
+            """.format(
+                next_tox_major,
+            ),
+        )
+    config = context.value.config
+
+    assert config.run_provision is True
+    assert config.minversion == next_tox_major
+    assert config.requires == ["setuptools > 2", "pip > 3"]
+
+
+def test_provision_config_empty_minversion_and_requires(newconfig, next_tox_major):
+    config = newconfig([], "")
+
+    assert config.run_provision is False
+    assert config.minversion is None
+    assert config.requires == []
+
+
 def test_provision_tox_change_name(newconfig):
     config = newconfig(
         [],
@@ -156,6 +187,99 @@ def test_provision_cli_args_not_ignored_if_provision_false(cmd, initproj):
     result.assert_fail(is_run_test_env=False)
 
 
+parametrize_json_path = pytest.mark.parametrize("json_path", [None, "missing.json"])
+
+
+@parametrize_json_path
+def test_provision_does_not_fail_with_no_provision_no_reason(cmd, initproj, json_path):
+    p = initproj("test-0.1", {"tox.ini": "[tox]"})
+    result = cmd("--no-provision", *([json_path] if json_path else []))
+    result.assert_success(is_run_test_env=True)
+    assert not (p / "missing.json").exists()
+
+
+@parametrize_json_path
+def test_provision_fails_with_no_provision_next_tox(cmd, initproj, next_tox_major, json_path):
+    p = initproj(
+        "test-0.1",
+        {
+            "tox.ini": """\
+                             [tox]
+                             minversion = {}
+                             """.format(
+                next_tox_major,
+            )
+        },
+    )
+    result = cmd("--no-provision", *([json_path] if json_path else []))
+    result.assert_fail(is_run_test_env=False)
+    if json_path:
+        missing = json.loads((p / json_path).read_text("utf-8"))
+        assert missing["minversion"] == next_tox_major
+
+
+@parametrize_json_path
+def test_provision_fails_with_no_provision_missing_requires(cmd, initproj, json_path):
+    p = initproj(
+        "test-0.1",
+        {
+            "tox.ini": """\
+                             [tox]
+                             requires =
+                                 virtualenv > 99999999
+                             """
+        },
+    )
+    result = cmd("--no-provision", *([json_path] if json_path else []))
+    result.assert_fail(is_run_test_env=False)
+    if json_path:
+        missing = json.loads((p / json_path).read_text("utf-8"))
+        assert missing["requires"] == ["virtualenv > 99999999"]
+
+
+@parametrize_json_path
+def test_provision_does_not_fail_with_satisfied_requires(cmd, initproj, next_tox_major, json_path):
+    p = initproj(
+        "test-0.1",
+        {
+            "tox.ini": """\
+                             [tox]
+                             minversion = 0
+                             requires =
+                                 setuptools > 2
+                                 pip > 3
+                             """
+        },
+    )
+    result = cmd("--no-provision", *([json_path] if json_path else []))
+    result.assert_success(is_run_test_env=True)
+    assert not (p / "missing.json").exists()
+
+
+@parametrize_json_path
+def test_provision_fails_with_no_provision_combined(cmd, initproj, next_tox_major, json_path):
+    p = initproj(
+        "test-0.1",
+        {
+            "tox.ini": """\
+                             [tox]
+                             minversion = {}
+                             requires =
+                                 setuptools > 2
+                                 pip > 3
+                             """.format(
+                next_tox_major,
+            )
+        },
+    )
+    result = cmd("--no-provision", *([json_path] if json_path else []))
+    result.assert_fail(is_run_test_env=False)
+    if json_path:
+        missing = json.loads((p / json_path).read_text("utf-8"))
+        assert missing["minversion"] == next_tox_major
+        assert missing["requires"] == ["setuptools > 2", "pip > 3"]
+
+
 @pytest.fixture(scope="session")
 def wheel(tmp_path_factory):
     """create a wheel for a project"""
@@ -209,6 +333,7 @@ def magic_non_canonical_wheel(wheel, tmp_path_factory):
     return wheel(magic_proj)
 
 
+@pytest.mark.skipif(IS_PYPY and sys.version_info[0] > 2, reason="fails on pypy3")
 def test_provision_non_canonical_dep(
     cmd,
     initproj,
@@ -262,3 +387,20 @@ def space_path2url(path):
     if " " not in at_path:
         return at_path
     return urljoin("file:", pathname2url(os.path.abspath(at_path)))
+
+
+def test_provision_does_not_occur_in_devenv(newconfig, next_tox_major):
+    """Adding --devenv should not change the directory where provisioning occurs"""
+    with pytest.raises(MissingRequirement) as context:
+        newconfig(
+            ["--devenv", "my_devenv"],
+            """\
+            [tox]
+            minversion = {}
+            """.format(
+                next_tox_major,
+            ),
+        )
+    config = context.value.config
+    assert config.run_provision is True
+    assert config.envconfigs[".tox"].envdir.basename != "my_devenv"
diff --git a/tests/unit/test_quickstart.py b/tests/unit/test_quickstart.py
index 6ac896e..f52378e 100644
--- a/tests/unit/test_quickstart.py
+++ b/tests/unit/test_quickstart.py
@@ -157,7 +157,7 @@ class _exp:
         (
             _answers([1, "pytest", ""]),
             _exp(
-                "choose current release Python and pytest with defaut deps",
+                "choose current release Python and pytest with default deps",
                 [tox.PYTHON.CURRENT_RELEASE_ENV, "pytest", "pytest"],
             ),
             _cnf(),
@@ -173,14 +173,14 @@ class _exp:
         (
             _answers([2, "pytest", ""]),
             _exp(
-                "choose py27, current release Python and pytest with defaut deps",
+                "choose py27, current release Python and pytest with default deps",
                 ["py27, {}".format(tox.PYTHON.CURRENT_RELEASE_ENV), "pytest", "pytest"],
             ),
             _cnf(),
         ),
         (
             _answers([3, "pytest", ""]),
-            _exp("choose all supported version and pytest with defaut deps"),
+            _exp("choose all supported version and pytest with default deps"),
             _cnf(),
         ),
         (
diff --git a/tests/unit/test_venv.py b/tests/unit/test_venv.py
index 22e76cf..2d01903 100644
--- a/tests/unit/test_venv.py
+++ b/tests/unit/test_venv.py
@@ -9,6 +9,7 @@ import tox
 from tox.interpreters import NoInterpreterInfo
 from tox.session.commands.run.sequential import installpkg, runtestenv
 from tox.venv import (
+    MAXINTERP,
     CreationConfig,
     VirtualEnv,
     getdigest,
@@ -69,6 +70,7 @@ def test_create(mocksession, newconfig):
     assert not venv.path.check()
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1
     args = pcalls[0].args
@@ -134,6 +136,7 @@ def test_create_sitepackages(mocksession, newconfig):
     venv = mocksession.getvenv("site")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1
     args = pcalls[0].args
@@ -143,6 +146,7 @@ def test_create_sitepackages(mocksession, newconfig):
     venv = mocksession.getvenv("nosite")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1
     args = pcalls[0].args
@@ -164,6 +168,7 @@ def test_install_deps_wildcard(newmocksession):
     venv = mocksession.getvenv("py123")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
         pcalls = mocksession._pcalls
         assert len(pcalls) == 1
         distshare = venv.envconfig.config.distshare
@@ -200,6 +205,7 @@ def test_install_deps_indexserver(newmocksession):
     venv = mocksession.getvenv("py123")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
         pcalls = mocksession._pcalls
         assert len(pcalls) == 1
         pcalls[:] = []
@@ -232,6 +238,7 @@ def test_install_deps_pre(newmocksession):
     venv = mocksession.getvenv("python")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) == 1
     pcalls[:] = []
@@ -293,6 +300,7 @@ def test_install_sdist_extras(newmocksession):
     venv = mocksession.getvenv("python")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) == 1
     pcalls[:] = []
@@ -313,6 +321,7 @@ def test_develop_extras(newmocksession, tmpdir):
     venv = mocksession.getvenv("python")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) == 1
     pcalls[:] = []
@@ -518,6 +527,7 @@ def test_install_python3(newmocksession):
     venv = mocksession.getvenv("py123")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
         pcalls = mocksession._pcalls
         assert len(pcalls) == 1
         args = pcalls[0].args
@@ -1149,6 +1159,18 @@ def test_tox_testenv_interpret_shebang_long_example(tmpdir):
     assert args == expected + base_args
 
 
+@pytest.mark.skipif("sys.platform == 'win32'", reason="no shebang on Windows")
+def test_tox_testenv_interpret_shebang_skip_truncated(tmpdir):
+    testfile = tmpdir.join("check_shebang_truncation.py")
+    original_args = [str(testfile), "arg1", "arg2", "arg3"]
+
+    # interpreter (too long example)
+    testfile.write("#!" + ("x" * (MAXINTERP + 1)))
+    args = prepend_shebang_interpreter(original_args)
+
+    assert args == original_args
+
+
 @pytest.mark.parametrize("download", [True, False, None])
 def test_create_download(mocksession, newconfig, download):
     config = newconfig(
@@ -1164,6 +1186,7 @@ def test_create_download(mocksession, newconfig, download):
     venv = mocksession.getvenv("env")
     with mocksession.newaction(venv.name, "getenv") as action:
         tox_testenv_create(action=action, venv=venv)
+        venv.just_created = True
     pcalls = mocksession._pcalls
     assert len(pcalls) >= 1
     args = pcalls[0].args
diff --git a/tests/unit/test_z_cmdline.py b/tests/unit/test_z_cmdline.py
index 658c118..c0549c0 100644
--- a/tests/unit/test_z_cmdline.py
+++ b/tests/unit/test_z_cmdline.py
@@ -773,7 +773,7 @@ def _alwayscopy_not_supported():
 alwayscopy_not_supported = _alwayscopy_not_supported()
 
 
-@pytest.mark.skipif(alwayscopy_not_supported, reason="Platform doesnt support alwayscopy")
+@pytest.mark.skipif(alwayscopy_not_supported, reason="Platform doesn't support alwayscopy")
 def test_alwayscopy(initproj, cmd):
     initproj(
         "example123",
diff --git a/tests/unit/util/test_spinner.py b/tests/unit/util/test_spinner.py
index 7c64ac4..2511d58 100644
--- a/tests/unit/util/test_spinner.py
+++ b/tests/unit/util/test_spinner.py
@@ -113,6 +113,31 @@ def test_spinner_stdout_not_unicode(mocker, capfd):
     assert all(f in written for f in spin.frames)
 
 
+@freeze_time("2012-01-14")
+def test_spinner_report_not_unicode(mocker, capfd):
+    stdout = mocker.patch("tox.util.spinner.sys.stdout")
+    stdout.encoding = "ascii"
+    # Disable color to simplify parsing output strings
+    stdout.isatty = lambda: False
+    with spinner.Spinner(refresh_rate=100) as spin:
+        spin.stream.write(os.linesep)
+        spin.add("ok!")
+        spin.add("fail!")
+        spin.add("skip!")
+        spin.succeed("ok!")
+        spin.fail("fail!")
+        spin.skip("skip!")
+    lines = "".join(args[0] for args, _ in stdout.write.call_args_list).split(os.linesep)
+    del lines[0]
+    expected = [
+        "\r{}[ OK ] ok! in 0.0 seconds".format(spin.CLEAR_LINE),
+        "\r{}[FAIL] fail! in 0.0 seconds".format(spin.CLEAR_LINE),
+        "\r{}[SKIP] skip! in 0.0 seconds".format(spin.CLEAR_LINE),
+        "\r{}".format(spin.CLEAR_LINE),
+    ]
+    assert lines == expected
+
+
 @pytest.mark.parametrize(
     "seconds, expected",
     [
diff --git a/tox.ini b/tox.ini
index f999c49..d8e94cd 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,112 +1,135 @@
 [tox]
-envlist = py27,
-          py35,
-          py36,
-          py37,
-          py38,
-          pypy,
-          pypy3,
-          coverage,
-          fix_lint,
-          docs,
-          package_description
-minversion = 3.12
+envlist =
+    fix_lint
+    py310
+    py39
+    py38
+    py37
+    py36
+    py35
+    py27
+    pypy3
+    pypy
+    coverage
+    docs
+    readme
 isolated_build = true
 skip_missing_interpreters = true
+minversion = 3.12
 
 [testenv]
 description = run the tests with pytest under {basepython}
-setenv =
-    PIP_DISABLE_PIP_VERSION_CHECK = 1
-    COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}}
-    {py27,pypy}: PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command
 passenv =
     CURL_CA_BUNDLE
-    http_proxy
-    https_proxy
-    no_proxy
+    PIP_CACHE_DIR
+    PYTEST_*
     REQUESTS_CA_BUNDLE
     SSL_CERT_FILE
-    PYTEST_*
-    PIP_CACHE_DIR
-deps =
-    pip >= 19.3.1
-extras = testing
-commands = pytest \
-           --cov "{envsitepackagesdir}/tox" \
-           --cov-config "{toxinidir}/tox.ini" \
-           --junitxml {toxworkdir}/junit.{envname}.xml \
-           -n={env:PYTEST_XDIST_PROC_NR:auto} \
-           {posargs:.}
-
-[testenv:pypy]
-deps =
-    pip >= 19.3.1
-    psutil <= 5.6.7
-
-[testenv:docs]
-description = invoke sphinx-build to build the HTML docs
-basepython = python3.8
-extras = docs
-commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" --color -W -bhtml {posargs}
-           python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))'
-
-[testenv:package_description]
-description = check that the long description is valid
-basepython = python3.8
-deps = twine >= 1.12.1
-       # TODO installing readme-renderer[md] should not be necessary
-       readme-renderer[md] >= 24.0
-       pip >= 18.0.0
-skip_install = true
+setenv =
+    COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}}
+    PIP_DISABLE_PIP_VERSION_CHECK = 1
+    {py27,pypy}: PYTHONWARNINGS = ignore:DEPRECATION::pip._internal.cli.base_command
 extras =
-commands = pip wheel -w {envtmpdir}/build --no-deps .
-           twine check {envtmpdir}/build/*
+    testing
+commands =
+    pytest \
+      --cov "{envsitepackagesdir}/tox" \
+      --cov-config "{toxinidir}/tox.ini" \
+      --junitxml {toxworkdir}/junit.{envname}.xml \
+      {posargs:.}
 
 [testenv:fix_lint]
 description = format the code base to adhere to our styles, and complain about what we cannot do automatically
-basepython = python3.8
 passenv =
     {[testenv]passenv}
-    # without PROGRAMDATA cloning using git for Windows will fail with an `error setting certificate verify locations` error
-    PROGRAMDATA
     PRE_COMMIT_HOME
-extras = lint
-deps = pre-commit>=2
-skip_install = True
-commands = pre-commit run --all-files --show-diff-on-failure {posargs}
-           python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))'
-
+    PROGRAMDATA
+basepython = python3.10
+skip_install = true
+deps =
+    pre-commit>=2.16
+extras =
+    lint
+commands =
+    pre-commit run --all-files --show-diff-on-failure {posargs}
+    python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))'
 
 [testenv:coverage]
 description = [run locally after tests]: combine coverage data and create report;
-              generates a diff coverage against origin/master (can be changed by setting DIFF_AGAINST env var)
-deps = {[testenv]deps}
-       coverage >= 5.0.1
-       diff_cover
-skip_install = True
-passenv = {[testenv]passenv}
-          DIFF_AGAINST
-setenv = COVERAGE_FILE={toxworkdir}/.coverage
-commands = coverage combine
-           coverage report -m
-           coverage xml -o {toxworkdir}/coverage.xml
-           coverage html -d {toxworkdir}/htmlcov
-           diff-cover --compare-branch {env:DIFF_AGAINST:origin/master} {toxworkdir}/coverage.xml
-depends = py27, py34, py35, py36, py37, py38, pypy, pypy3
-parallel_show_output = True
+    generates a diff coverage against origin/master (can be changed by setting DIFF_AGAINST env var)
+passenv =
+    {[testenv]passenv}
+    DIFF_AGAINST
+setenv =
+    COVERAGE_FILE = {toxworkdir}/.coverage
+skip_install = true
+deps =
+    coverage>=6.2
+    diff-cover>=6.4
+parallel_show_output = true
+commands =
+    coverage combine
+    coverage report -m
+    coverage xml -o {toxworkdir}/coverage.xml
+    coverage html -d {toxworkdir}/htmlcov
+    diff-cover --compare-branch {env:DIFF_AGAINST:origin/master} {toxworkdir}/coverage.xml
+depends = py27, py35, py36, py37, py38, py39, py310, pypy, pypy3
+
+[testenv:docs]
+description = invoke sphinx-build to build the HTML docs
+basepython = python3.10
+extras =
+    docs
+commands =
+    sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" --color -W --keep-going -n -bhtml {posargs}
+    python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))'
+
+[testenv:readme]
+description = check that the long description is valid
+basepython = python3.9
+skip_install = true
+deps =
+    twine>=3.7.1
+extras =
+commands =
+    pip wheel -w {envtmpdir}/build --no-deps .
+    twine check {envtmpdir}/build/*
 
 [testenv:exit_code]
-# to see how the InvocationError is displayed, use
-# PYTHONPATH=.:$PYTHONPATH python3 -m tox -e exit_code
-basepython = python3.8
 description = commands with several exit codes
-skip_install = True
-commands = python3.8 -c "import sys; sys.exit(139)"
+basepython = python3.10
+skip_install = true
+commands =
+    python3.10 -c "import sys; sys.exit(139)"
 
 [testenv:X]
 description = print the positional arguments passed in with echo
-commands = echo {posargs}
+commands =
+    echo {posargs}
+
+[testenv:release]
+description = do a release, required posarg of the version number
+passenv =
+    *
+basepython = python3.10
+deps =
+    gitpython>=3.1.24
+    packaging>=21.3
+    towncrier>=21.3
+commands =
+    python {toxinidir}/tasks/release.py --version {posargs}
+
+[testenv:dev]
+description = dev environment with all deps at {envdir}
+usedevelop = true
+deps =
+    {[testenv:release]deps}
+extras =
+    docs
+    testing
+commands =
+    python -m pip list --format=columns
+    python -c "print(r'{envpython}')"
 
 [flake8]
 max-complexity = 22
@@ -133,16 +156,14 @@ exclude_lines =
 
 [coverage:paths]
 source = src/tox
-         */.tox/*/lib/python*/site-packages/tox
-         */.tox/pypy*/site-packages/tox
-         */.tox\*\Lib\site-packages\tox
-         */src/tox
-         *\src\tox
+    */.tox/*/lib/python*/site-packages/tox
+    */.tox/pypy*/site-packages/tox
+    */.tox\*\Lib\site-packages\tox
+    */src/tox
+    *\src\tox
 
 [pytest]
 addopts = -ra --showlocals --no-success-flaky-report
-rsyncdirs = tests tox
-looponfailroots = tox tests
 testpaths = tests
 xfail_strict = True
 markers =
@@ -153,33 +174,3 @@ markers =
 profile = black
 line_length = 99
 known_first_party = tox,tests
-
-[testenv:release]
-description = do a release, required posarg of the version number
-basepython = python3.8
-passenv = *
-deps = gitpython >= 2.1.10
-       towncrier >= 18.5.0
-       packaging  >= 17.1
-commands = python {toxinidir}/tasks/release.py --version {posargs}
-
-[testenv:notify]
-description = notify people about the release of the library
-basepython = python3.8
-skip_install = true
-passenv = *
-deps = gitpython >= 2.1.10
-       packaging  >= 17.1
-       google-api-python-client >= 1.7.3
-       oauth2client >= 4.1.2
-commands = python {toxinidir}/tasks/notify.py
-
-[testenv:dev]
-description = dev environment with all deps at {envdir}
-extras = testing, docs
-deps = {[testenv]deps}
-       {[testenv:release]deps}
-       {[testenv:notify]deps}
-usedevelop = True
-commands = python -m pip list --format=columns
-           python -c "print(r'{envpython}')"