Repository: pypa/virtualenv

Issue:
virtualenv raises StopIteration exception when processing extra search directory wheels.
**Issue**

When creating virtualenv when using `--extra-search-directory`, ``StopIteration`` exception is raised when processing wheels.
**Environment**

Provide at least:
- OS: Centos7
- ``virtualenv`` is installed:
virtualenv version: 20.0.15
```console
Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib64/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/usr/lib64/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.6/site-packages/virtualenv/seed/via_app_data/via_app_data.py", line 75, in _get
    self.app_data,
  File "/usr/local/lib/python3.6/site-packages/virtualenv/seed/embed/wheels/acquire.py", line 30, in get_wheels
    acquire_from_dir(processed, for_py_version, wheel_cache_dir, extra_search_dir)
  File "/usr/local/lib/python3.6/site-packages/virtualenv/seed/embed/wheels/acquire.py", line 74, in acquire_from_dir
    if wheel_support_py(filename, for_py_version):
  File "/usr/local/lib/python3.6/site-packages/virtualenv/seed/embed/wheels/acquire.py", line 91, in wheel_support_py
    requires = next(i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker))
StopIteration
```


Discussion:

Patch:
diff --git a/docs/changelog/1757.bugfix.rst b/docs/changelog/1757.bugfix.rst
new file mode 100644
index 00000000..822322ed
--- /dev/null
+++ b/docs/changelog/1757.bugfix.rst
@@ -0,0 +1,2 @@
+Allow seed wheel files inside the :option:`extra-search-dir` folders that do not have ``Requires-Python``
+metadata specified, these are considered compatible with all python versions - by :user:`gaborbernat`.
diff --git a/src/virtualenv/seed/embed/wheels/acquire.py b/src/virtualenv/seed/embed/wheels/acquire.py
index dd25accc..7f873023 100644
--- a/src/virtualenv/seed/embed/wheels/acquire.py
+++ b/src/virtualenv/seed/embed/wheels/acquire.py
@@ -87,7 +87,9 @@ def wheel_support_py(filename, py_version):
     with ZipFile(ensure_text(str(filename)), "r") as zip_file:
         metadata = zip_file.read(name).decode("utf-8")
     marker = "Requires-Python:"
-    requires = next(i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker))
+    requires = next((i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker)), None)
+    if requires is None:  # if it does not specify a python requires the assumption is compatible
+        return True
     py_version_int = tuple(int(i) for i in py_version.split("."))
     for require in (i.strip() for i in requires.split(",")):
         # https://www.python.org/dev/peps/pep-0345/#version-specifiers


Test patch:
diff --git a/tests/unit/config/test_env_var.py b/tests/unit/config/test_env_var.py
index d104ba61..35d084ce 100644
--- a/tests/unit/config/test_env_var.py
+++ b/tests/unit/config/test_env_var.py
@@ -37,7 +37,7 @@ def test_value_bad(monkeypatch, caplog, empty_conf):
     assert "invalid literal" in caplog.messages[0]
 
 
-def test_extra_search_dir(tmp_path, monkeypatch):
+def test_extra_search_dir_via_env_var(tmp_path, monkeypatch):
     monkeypatch.chdir(tmp_path)
     value = "a{}0{}b{}c".format(os.linesep, os.linesep, os.pathsep)
     monkeypatch.setenv(str("VIRTUALENV_EXTRA_SEARCH_DIR"), str(value))
diff --git a/tests/unit/seed/embed/wheels/test_acquire.py b/tests/unit/seed/embed/wheels/test_acquire.py
new file mode 100644
index 00000000..49f74333
--- /dev/null
+++ b/tests/unit/seed/embed/wheels/test_acquire.py
@@ -0,0 +1,11 @@
+from virtualenv.seed.embed.wheels.acquire import get_bundled_wheel, wheel_support_py
+
+
+def test_wheel_support_no_python_requires(mocker):
+    wheel = get_bundled_wheel(package="setuptools", version_release=None)
+    zip_mock = mocker.MagicMock()
+    mocker.patch("virtualenv.seed.embed.wheels.acquire.ZipFile", new=zip_mock)
+    zip_mock.return_value.__enter__.return_value.read = lambda name: b""
+
+    supports = wheel_support_py(wheel, "3.8")
+    assert supports is True