Repository: pypa/pip

Issue:
Vendoring of `tenacity` is leaky
### Description

Tenacity contains a [conditional import of tornado](https://github.com/pypa/pip/blob/88eb4f092e58f3aee1d389ad4f9047df46e44bb4/src/pip/_vendor/tenacity/__init__.py#L25-L28). This makes the behavior of `pip` sensitive to third-party packages outside of its vendor directory. Specifically, if a version of tornado that does not include the `tornado.gen.sleep` function is installed, `pip` will fail to start. (This is unlikely since this function has been around a long time and we have no plans of deprecating it or removing it. But we do have a report of this happening in https://github.com/tornadoweb/tornado/issues/3034)

### Expected behavior

Pip should not be affected by the presence or absence of any other third-party packages. Any conditional imports in its vendored dependencies should be modified to unconditionally fail (e.g. replace the above-linked block with `tornado = None`). 

### pip version

21.1.2

### Python version

3.8

### OS

linux

### How to Reproduce

1. `pip install tornado==4.0.0`
2. `pip --version`

### Output

```sh-session
~/ImpressionableVoluminousCategories$ pip --version
pip 21.1.2 from /opt/virtualenvs/python3/lib/python3.8/site-packages/pip (python 3.8)
~/ImpressionableVoluminousCategories$ pip install tornado==4.0.0
Collecting tornado==4.0.0
  Downloading tornado-4.0.tar.gz (313 kB)
     |████████████████████████████████| 313 kB 4.5 MB/s 
Requirement already satisfied: certifi in /opt/virtualenvs/python3/lib/python3.8/site-packages (from tornado==4.0.0) (2020.12.5)
Building wheels for collected packages: tornado
  Building wheel for tornado (setup.py) ... done
  Created wheel for tornado: filename=tornado-4.0-cp38-cp38-linux_x86_64.whl size=344556 sha256=d9c5e6911e5bdac5b90db4b33d01891562365e235396bd336380dd45cb61a9b7
  Stored in directory: /home/runner/.cache/pip/wheels/9a/d7/93/a846246f95067512a78899329bdb84a695d693e67c28a4e71f
Successfully built tornado
Installing collected packages: tornado
Successfully installed tornado-4.0
~/ImpressionableVoluminousCategories$ pip --version
Traceback (most recent call last):
  File "/opt/virtualenvs/python3/bin/pip", line 5, in <module>
    from pip._internal.cli.main import main
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/cli/main.py", line 9, in <module>
    from pip._internal.cli.autocompletion import autocomplete
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py", line 10, in <module>
    from pip._internal.cli.main_parser import create_main_parser
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py", line 8, in <module>
    from pip._internal.cli import cmdoptions
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py", line 23, in <module>
    from pip._internal.cli.parser import ConfigOptionParser
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/cli/parser.py", line 12, in <module>
    from pip._internal.configuration import Configuration, ConfigurationError
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/configuration.py", line 27, in <module>
    from pip._internal.utils.misc import ensure_dir, enum
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_internal/utils/misc.py", line 38, in <module>
    from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_vendor/tenacity/__init__.py", line 523, in <module>
    from pip._vendor.tenacity.tornadoweb import TornadoRetrying
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_vendor/tenacity/tornadoweb.py", line 26, in <module>
    class TornadoRetrying(BaseRetrying):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/pip/_vendor/tenacity/tornadoweb.py", line 27, in TornadoRetrying
    def __init__(self, sleep=gen.sleep, **kwargs):
AttributeError: module 'tornado.gen' has no attribute 'sleep'
~/ImpressionableVoluminousCategories$ 
```
```


### Code of Conduct

- [X] I agree to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/).


Discussion:
Thanks for raising the issue. I think an easy way would be to vendor a patch to delete those imports. We already have a few of those [here](https://github.com/pypa/pip/tree/main/tools/vendoring/patches). Would you be interested in contributing one for this?

Resolving patch:
diff --git a/src/pip/_vendor/tenacity/__init__.py b/src/pip/_vendor/tenacity/__init__.py
--- a/src/pip/_vendor/tenacity/__init__.py
+++ b/src/pip/_vendor/tenacity/__init__.py
@@ -22,10 +22,12 @@
 except ImportError:
     iscoroutinefunction = None
 
-try:
-    import tornado
-except ImportError:
-    tornado = None
+# Replace a conditional import with a hard-coded None so that pip does
+# not attempt to use tornado even if it is present in the environment.
+# If tornado is non-None, tenacity will attempt to execute some code
+# that is sensitive to the version of tornado, which could break pip
+# if an old version is found.
+tornado = None
 
 import sys
 import threading


Test patch: