Repository: pypa/virtualenv

Issue:
DeprecationWarning with importlib-metadata>=3.9.0
**Issue**

`importlib-metadata` 3.6.0 changed the behaviour of `entry_points()` to no longer return a dictionary of entry points but instead return an object with a deprecated dict-like interface. As of `importlib-metadata` 3.9.0 a DeprecationWarning is emitted when calling the dictionary methods.

``virtualenv`` calls `.get()` here:

https://github.com/pypa/virtualenv/blob/3f410672291676f7dc665718a84708e1bd405789/src/virtualenv/run/plugin/base.py#L16-L18

This results in the following warning:

```console
$ python3.6 -Wdefault -m virtualenv /tmp/venv
```

```python
virtualenv/run/plugin/base.py:18: DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.
  return OrderedDict((e.name, e.load()) for e in cls.entry_points().get(key, {}))
```


**Environment**

Provide at least:
- OS: Ubuntu 20.04
- ``pip list`` of the host python where ``virtualenv`` is installed:

  ```console
  Package             Version
  ------------------- -------
  appdirs             1.4.4
  distlib             0.3.1
  filelock            3.0.12
  importlib-metadata  3.10.1
  importlib-resources 5.1.2
  pip                 21.0.1
  setuptools          54.0.0
  six                 1.15.0
  typing-extensions   3.7.4.3
  virtualenv          20.4.3
  wheel               0.36.2
  zipp                3.4.1

  ```

**Output of the virtual environment creation**

Make sure to run the creation with `-vvv --with-traceback`:

<details>
  <summary>Output</summary>

```console
60 setup logging to NOTSET [DEBUG report:43]
/tmp/virtualenv-issue/venv/lib/python3.6/site-packages/virtualenv/run/plugin/base.py:18: DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.
  return OrderedDict((e.name, e.load()) for e in cls.entry_points().get(key, {}))
78 find interpreter for spec PythonSpec(path=/tmp/virtualenv-issue/venv/bin/python3.6) [INFO builtin:62]
78 discover exe for PythonInfo(spec=CPython3.6.13.final.0-64, exe=/tmp/virtualenv-issue/venv/bin/python3.6, platform=linux, version='3.6.13 (default, Feb 20 2021, 21:40:46) \n[GCC 9.3.0]', encoding_fs_io=utf-8-UTF-8) in /usr [DEBUG py_info:372]
78 filesystem is case-sensitive [DEBUG info:28]
79 Attempting to acquire lock 140329095360640 on /home/domdf/.local/share/virtualenv/py_info/1/30295c5bec572e859485b1ffa5e89b8b3e2022ef6e3e739c1ac40f143a557caf.lock [DEBUG filelock:270]
79 Lock 140329095360640 acquired on /home/domdf/.local/share/virtualenv/py_info/1/30295c5bec572e859485b1ffa5e89b8b3e2022ef6e3e739c1ac40f143a557caf.lock [INFO filelock:274]
79 got python info of /usr/bin/python3.6 from /home/domdf/.local/share/virtualenv/py_info/1/30295c5bec572e859485b1ffa5e89b8b3e2022ef6e3e739c1ac40f143a557caf.json [DEBUG via_disk_folder:135]
80 Attempting to release lock 140329095360640 on /home/domdf/.local/share/virtualenv/py_info/1/30295c5bec572e859485b1ffa5e89b8b3e2022ef6e3e739c1ac40f143a557caf.lock [DEBUG filelock:315]
80 Lock 140329095360640 released on /home/domdf/.local/share/virtualenv/py_info/1/30295c5bec572e859485b1ffa5e89b8b3e2022ef6e3e739c1ac40f143a557caf.lock [INFO filelock:318]
80 proposed PythonInfo(spec=CPython3.6.13.final.0-64, system=/usr/bin/python3.6, exe=/tmp/virtualenv-issue/venv/bin/python3.6, platform=linux, version='3.6.13 (default, Feb 20 2021, 21:40:46) \n[GCC 9.3.0]', encoding_fs_io=utf-8-UTF-8) [INFO builtin:69]
80 accepted PythonInfo(spec=CPython3.6.13.final.0-64, system=/usr/bin/python3.6, exe=/tmp/virtualenv-issue/venv/bin/python3.6, platform=linux, version='3.6.13 (default, Feb 20 2021, 21:40:46) \n[GCC 9.3.0]', encoding_fs_io=utf-8-UTF-8) [DEBUG builtin:71]
105 create virtual environment via CPython3Posix(dest=/tmp/venv, clear=False, no_vcs_ignore=False, global=False) [INFO session:52]
105 write /tmp/venv/pyvenv.cfg [DEBUG pyenv_cfg:34]
105 	home = /usr [DEBUG pyenv_cfg:38]
105 	implementation = CPython [DEBUG pyenv_cfg:38]
105 	version_info = 3.6.13.final.0 [DEBUG pyenv_cfg:38]
105 	virtualenv = 20.4.3 [DEBUG pyenv_cfg:38]
105 	include-system-site-packages = false [DEBUG pyenv_cfg:38]
105 	base-prefix = /usr [DEBUG pyenv_cfg:38]
105 	base-exec-prefix = /usr [DEBUG pyenv_cfg:38]
105 	base-executable = /usr/bin/python3.6 [DEBUG pyenv_cfg:38]
105 remove file /tmp/venv/bin/python [DEBUG _sync:38]
106 symlink /usr/bin/python3.6 to /tmp/venv/bin/python [DEBUG _sync:44]
106 create virtualenv import hook file /tmp/venv/lib/python3.6/site-packages/_virtualenv.pth [DEBUG api:95]
106 create /tmp/venv/lib/python3.6/site-packages/_virtualenv.py [DEBUG api:98]
106 ============================== target debug ============================== [DEBUG session:54]
106 debug via /tmp/venv/bin/python /tmp/virtualenv-issue/venv/lib/python3.6/site-packages/virtualenv/create/debug.py [DEBUG creator:224]
106 {
  "sys": {
    "executable": "/tmp/venv/bin/python",
    "_base_executable": null,
    "prefix": "/tmp/venv",
    "base_prefix": "/usr",
    "real_prefix": null,
    "exec_prefix": "/tmp/venv",
    "base_exec_prefix": "/usr",
    "path": [
      "/usr/lib/python36.zip",
      "/usr/lib/python3.6",
      "/usr/lib/python3.6/lib-dynload",
      "/tmp/venv/lib/python3.6/site-packages"
    ],
    "meta_path": [
      "<class '_virtualenv._Finder'>",
      "<class '_frozen_importlib.BuiltinImporter'>",
      "<class '_frozen_importlib.FrozenImporter'>",
      "<class '_frozen_importlib_external.PathFinder'>"
    ],
    "fs_encoding": "utf-8",
    "io_encoding": "UTF-8"
  },
  "version": "3.6.13 (default, Feb 20 2021, 21:40:46) \n[GCC 9.3.0]",
  "makefile_filename": "/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu/Makefile",
  "os": "<module 'os' from '/usr/lib/python3.6/os.py'>",
  "site": "<module 'site' from '/usr/lib/python3.6/site.py'>",
  "datetime": "<module 'datetime' from '/usr/lib/python3.6/datetime.py'>",
  "math": "<module 'math' (built-in)>",
  "json": "<module 'json' from '/usr/lib/python3.6/json/__init__.py'>"
} [DEBUG session:55]
130 add seed packages via FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/domdf/.local/share/virtualenv) [INFO session:59]
133 got embed update of distribution setuptools from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/setuptools.json [DEBUG via_disk_folder:135]
133 got embed update of distribution pip from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/pip.json [DEBUG via_disk_folder:135]
134 got embed update of distribution wheel from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/wheel.json [DEBUG via_disk_folder:135]
140 got embed update of distribution setuptools from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/setuptools.json [DEBUG via_disk_folder:135]
142 using periodically updated wheel /home/domdf/.local/share/virtualenv/wheel/house/setuptools-54.0.0-py3-none-any.whl [DEBUG periodic_update:53]
143 got embed update of distribution pip from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/pip.json [DEBUG via_disk_folder:135]
143 got embed update of distribution wheel from /home/domdf/.local/share/virtualenv/wheel/3.6/embed/1/wheel.json [DEBUG via_disk_folder:135]
144 install setuptools from wheel /home/domdf/.local/share/virtualenv/wheel/house/setuptools-54.0.0-py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
144 install pip from wheel /tmp/virtualenv-issue/venv/lib/python3.6/site-packages/virtualenv/seed/wheels/embed/pip-21.0.1-py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
144 install wheel from wheel /tmp/virtualenv-issue/venv/lib/python3.6/site-packages/virtualenv/seed/wheels/embed/wheel-0.36.2-py2.py3-none-any.whl via CopyPipInstall [DEBUG via_app_data:49]
145 Attempting to acquire lock 140329092716248 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any.lock [DEBUG filelock:270]
145 Attempting to acquire lock 140329092347888 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [DEBUG filelock:270]
145 Attempting to acquire lock 140329092715240 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any.lock [DEBUG filelock:270]
145 Lock 140329092347888 acquired on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [INFO filelock:274]
145 Lock 140329092716248 acquired on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any.lock [INFO filelock:274]
146 Lock 140329092715240 acquired on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any.lock [INFO filelock:274]
146 Attempting to release lock 140329092347888 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [DEBUG filelock:315]
146 Lock 140329092347888 released on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [INFO filelock:318]
146 Attempting to release lock 140329092715240 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any.lock [DEBUG filelock:315]
146 Attempting to release lock 140329092716248 on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any.lock [DEBUG filelock:315]
146 Lock 140329092715240 released on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any.lock [INFO filelock:318]
146 Lock 140329092716248 released on /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any.lock [INFO filelock:318]
146 copy /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel-0.36.2.virtualenv to /tmp/venv/lib/python3.6/site-packages/wheel-0.36.2.virtualenv [DEBUG _sync:52]
149 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel to /tmp/venv/lib/python3.6/site-packages/wheel [DEBUG _sync:52]
155 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel-0.36.2.dist-info to /tmp/venv/lib/python3.6/site-packages/wheel-0.36.2.dist-info [DEBUG _sync:52]
157 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/setuptools to /tmp/venv/lib/python3.6/site-packages/setuptools [DEBUG _sync:52]
159 generated console scripts wheel wheel3 wheel3.6 wheel-3.6 [DEBUG base:48]
169 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any/pip to /tmp/venv/lib/python3.6/site-packages/pip [DEBUG _sync:52]
180 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/_distutils_hack to /tmp/venv/lib/python3.6/site-packages/_distutils_hack [DEBUG _sync:52]
181 copy /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/setuptools-54.0.0.virtualenv to /tmp/venv/lib/python3.6/site-packages/setuptools-54.0.0.virtualenv [DEBUG _sync:52]
181 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/setuptools-54.0.0.dist-info to /tmp/venv/lib/python3.6/site-packages/setuptools-54.0.0.dist-info [DEBUG _sync:52]
183 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/pkg_resources to /tmp/venv/lib/python3.6/site-packages/pkg_resources [DEBUG _sync:52]
187 copy /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/setuptools-54.0.0-py3-none-any/distutils-precedence.pth to /tmp/venv/lib/python3.6/site-packages/distutils-precedence.pth [DEBUG _sync:52]
187 generated console scripts  [DEBUG base:48]
209 copy /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any/pip-21.0.1.virtualenv to /tmp/venv/lib/python3.6/site-packages/pip-21.0.1.virtualenv [DEBUG _sync:52]
210 copy directory /home/domdf/.local/share/virtualenv/wheel/3.6/image/1/CopyPipInstall/pip-21.0.1-py3-none-any/pip-21.0.1.dist-info to /tmp/venv/lib/python3.6/site-packages/pip-21.0.1.dist-info [DEBUG _sync:52]
211 generated console scripts pip-3.6 pip3.6 pip pip3 [DEBUG base:48]
211 add activators for Bash, CShell, Fish, PowerShell, Python, Xonsh [INFO session:66]
214 write /tmp/venv/pyvenv.cfg [DEBUG pyenv_cfg:34]
214 	home = /usr [DEBUG pyenv_cfg:38]
214 	implementation = CPython [DEBUG pyenv_cfg:38]
214 	version_info = 3.6.13.final.0 [DEBUG pyenv_cfg:38]
214 	virtualenv = 20.4.3 [DEBUG pyenv_cfg:38]
214 	include-system-site-packages = false [DEBUG pyenv_cfg:38]
214 	base-prefix = /usr [DEBUG pyenv_cfg:38]
214 	base-exec-prefix = /usr [DEBUG pyenv_cfg:38]
214 	base-executable = /usr/bin/python3.6 [DEBUG pyenv_cfg:38]
214 created virtual environment CPython3.6.13.final.0-64 in 155ms
  creator CPython3Posix(dest=/tmp/venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/domdf/.local/share/virtualenv)
    added seed packages: pip==21.0.1, setuptools==54.0.0, wheel==0.36.2
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator [WARNING __main__:19]

```
</details>

See https://github.com/python/importlib_metadata/pull/278 and https://github.com/python/importlib_metadata/pull/289 for more context. The changelog for `importlib-metadata` suggests https://pypi.org/project/backports.entry-points-selectable/ as a possible solution.

This is currently only an issue on Python 3.7 and earlier, as `virtualenv` uses the standard library on newer versions.



Discussion:

Resolving patch:
diff --git a/src/virtualenv/run/plugin/base.py b/src/virtualenv/run/plugin/base.py
--- a/src/virtualenv/run/plugin/base.py
+++ b/src/virtualenv/run/plugin/base.py
@@ -1,12 +1,8 @@
 from __future__ import absolute_import, unicode_literals
 
-import sys
 from collections import OrderedDict
 
-if sys.version_info >= (3, 8):
-    from importlib.metadata import entry_points
-else:
-    from importlib_metadata import entry_points
+from backports.entry_points_selectable import entry_points
 
 
 class PluginLoader(object):
@@ -15,7 +11,7 @@ class PluginLoader(object):
 
     @classmethod
     def entry_points_for(cls, key):
-        return OrderedDict((e.name, e.load()) for e in cls.entry_points().get(key, {}))
+        return OrderedDict((e.name, e.load()) for e in cls.entry_points().select(group=key))
 
     @staticmethod
     def entry_points():


Test patch: