We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pinning pip fails via app data seeder
```
VIRTUALENV_PIP=19.2.3 virtualenv --download --seeder app-data .venv
ERROR: Invalid requirement: 'pip=19.2.3'
```

from https://github.com/pglass/tox-pip-version/issues/17#issuecomment-616246861

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/virtualenv/util/path/_pathlib/via_os_path.py`
Content:
```
1 from __future__ import absolute_import, unicode_literals
2 
3 import os
4 import platform
5 from contextlib import contextmanager
6 
7 from virtualenv.util.six import ensure_str, ensure_text
8 
9 IS_PYPY = platform.python_implementation() == "PyPy"
10 
11 
12 class Path(object):
13     def __init__(self, path):
14         if isinstance(path, Path):
15             _path = path._path
16         else:
17             _path = ensure_text(path)
18             if IS_PYPY:
19                 _path = _path.encode("utf-8")
20         self._path = _path
21 
22     def __repr__(self):
23         return ensure_str("Path({})".format(ensure_text(self._path)))
24 
25     def __unicode__(self):
26         return ensure_text(self._path)
27 
28     def __str__(self):
29         return ensure_str(self._path)
30 
31     def __div__(self, other):
32         if isinstance(other, Path):
33             right = other._path
34         else:
35             right = ensure_text(other)
36             if IS_PYPY:
37                 right = right.encode("utf-8")
38         return Path(os.path.join(self._path, right))
39 
40     def __truediv__(self, other):
41         return self.__div__(other)
42 
43     def __eq__(self, other):
44         return self._path == (other._path if isinstance(other, Path) else None)
45 
46     def __ne__(self, other):
47         return not (self == other)
48 
49     def __hash__(self):
50         return hash(self._path)
51 
52     def exists(self):
53         return os.path.exists(self._path)
54 
55     @property
56     def parent(self):
57         return Path(os.path.abspath(os.path.join(self._path, os.path.pardir)))
58 
59     def resolve(self):
60         return Path(os.path.realpath(self._path))
61 
62     @property
63     def name(self):
64         return os.path.basename(self._path)
65 
66     @property
67     def parts(self):
68         return self._path.split(os.sep)
69 
70     def is_file(self):
71         return os.path.isfile(self._path)
72 
73     def is_dir(self):
74         return os.path.isdir(self._path)
75 
76     def mkdir(self, parents=True, exist_ok=True):
77         if not self.exists() and exist_ok:
78             os.makedirs(self._path)
79 
80     def read_text(self, encoding="utf-8"):
81         return self.read_bytes().decode(encoding)
82 
83     def read_bytes(self):
84         with open(self._path, "rb") as file_handler:
85             return file_handler.read()
86 
87     def write_text(self, text, encoding="utf-8"):
88         with open(self._path, "wb") as file_handler:
89             file_handler.write(text.encode(encoding))
90 
91     def iterdir(self):
92         for p in os.listdir(self._path):
93             yield Path(os.path.join(self._path, p))
94 
95     @property
96     def suffix(self):
97         _, ext = os.path.splitext(self.name)
98         return ext
99 
100     @property
101     def stem(self):
102         base, _ = os.path.splitext(self.name)
103         return base
104 
105     @contextmanager
106     def open(self, mode="r"):
107         with open(self._path, mode) as file_handler:
108             yield file_handler
109 
110     @property
111     def parents(self):
112         result = []
113         parts = self.parts
114         for i in range(len(parts)):
115             result.append(Path(os.sep.join(parts[0 : i + 1])))
116         return result
117 
118     def unlink(self):
119         os.remove(self._path)
120 
121     def with_name(self, name):
122         return self.parent / name
123 
124     def is_symlink(self):
125         return os.path.islink(self._path)
126 
127     def relative_to(self, other):
128         if not self._path.startswith(other._path):
129             raise ValueError("{} does not start with {}".format(self._path, other._path))
130         return Path(os.sep.join(self.parts[len(other.parts) :]))
131 
132     def stat(self):
133         return os.stat(self._path)
134 
135     def chmod(self, mode):
136         os.chmod(self._path, mode)
137 
138 
139 __all__ = ("Path",)
140
```

Path: `src/virtualenv/seed/embed/wheels/acquire.py`
Content:
```
1 """Bootstrap"""
2 from __future__ import absolute_import, unicode_literals
3 
4 import logging
5 import os
6 import sys
7 from collections import defaultdict
8 from contextlib import contextmanager
9 from copy import copy
10 from shutil import copy2
11 from zipfile import ZipFile
12 
13 from virtualenv.info import IS_ZIPAPP
14 from virtualenv.util.path import Path
15 from virtualenv.util.six import ensure_str, ensure_text
16 from virtualenv.util.subprocess import Popen, subprocess
17 from virtualenv.util.zipapp import ensure_file_on_disk
18 
19 from . import BUNDLE_SUPPORT, MAX
20 
21 BUNDLE_FOLDER = Path(os.path.abspath(__file__)).parent
22 
23 
24 def get_wheels(for_py_version, wheel_cache_dir, extra_search_dir, download, packages, app_data):
25     # not all wheels are compatible with all python versions, so we need to py version qualify it
26     processed = copy(packages)
27     # 1. acquire from bundle
28     acquire_from_bundle(processed, for_py_version, wheel_cache_dir)
29     # 2. acquire from extra search dir
30     acquire_from_dir(processed, for_py_version, wheel_cache_dir, extra_search_dir)
31     # 3. download from the internet
32     if download and processed:
33         download_wheel(processed, for_py_version, wheel_cache_dir, app_data)
34 
35     # in the end just get the wheels
36     wheels = _get_wheels(wheel_cache_dir, packages)
37     return {p: next(iter(ver_to_files))[1] for p, ver_to_files in wheels.items()}
38 
39 
40 def acquire_from_bundle(packages, for_py_version, to_folder):
41     for pkg, version in list(packages.items()):
42         bundle = get_bundled_wheel(pkg, for_py_version)
43         if bundle is not None:
44             pkg_version = bundle.stem.split("-")[1]
45             exact_version_match = version == pkg_version
46             if exact_version_match:
47                 del packages[pkg]
48             if version is None or exact_version_match:
49                 bundled_wheel_file = to_folder / bundle.name
50                 if not bundled_wheel_file.exists():
51                     logging.debug("get bundled wheel %s", bundle)
52                     if IS_ZIPAPP:
53                         from virtualenv.util.zipapp import extract
54 
55                         extract(bundle, bundled_wheel_file)
56                     else:
57                         copy2(str(bundle), str(bundled_wheel_file))
58 
59 
60 def get_bundled_wheel(package, version_release):
61     return BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(version_release, {}) or BUNDLE_SUPPORT[MAX]).get(package)
62 
63 
64 def acquire_from_dir(packages, for_py_version, to_folder, extra_search_dir):
65     if not packages:
66         return
67     for search_dir in extra_search_dir:
68         wheels = _get_wheels(search_dir, packages)
69         for pkg, ver_wheels in wheels.items():
70             stop = False
71             for _, filename in ver_wheels:
72                 dest = to_folder / filename.name
73                 if not dest.exists():
74                     if wheel_support_py(filename, for_py_version):
75                         logging.debug("get extra search dir wheel %s", filename)
76                         copy2(str(filename), str(dest))
77                         stop = True
78                 else:
79                     stop = True
80                 if stop and packages[pkg] is not None:
81                     del packages[pkg]
82                     break
83 
84 
85 def wheel_support_py(filename, py_version):
86     name = "{}.dist-info/METADATA".format("-".join(filename.stem.split("-")[0:2]))
87     with ZipFile(ensure_text(str(filename)), "r") as zip_file:
88         metadata = zip_file.read(name).decode("utf-8")
89     marker = "Requires-Python:"
90     requires = next((i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker)), None)
91     if requires is None:  # if it does not specify a python requires the assumption is compatible
92         return True
93     py_version_int = tuple(int(i) for i in py_version.split("."))
94     for require in (i.strip() for i in requires.split(",")):
95         # https://www.python.org/dev/peps/pep-0345/#version-specifiers
96         for operator, check in [
97             ("!=", lambda v: py_version_int != v),
98             ("==", lambda v: py_version_int == v),
99             ("<=", lambda v: py_version_int <= v),
100             (">=", lambda v: py_version_int >= v),
101             ("<", lambda v: py_version_int < v),
102             (">", lambda v: py_version_int > v),
103         ]:
104             if require.startswith(operator):
105                 ver_str = require[len(operator) :].strip()
106                 version = tuple((int(i) if i != "*" else None) for i in ver_str.split("."))[0:2]
107                 if not check(version):
108                     return False
109                 break
110     return True
111 
112 
113 def _get_wheels(from_folder, packages):
114     wheels = defaultdict(list)
115     for filename in from_folder.iterdir():
116         if filename.suffix == ".whl":
117             data = filename.stem.split("-")
118             if len(data) >= 2:
119                 pkg, version = data[0:2]
120                 if pkg in packages:
121                     pkg_version = packages[pkg]
122                     if pkg_version is None or pkg_version == version:
123                         wheels[pkg].append((version, filename))
124     for versions in wheels.values():
125         versions.sort(
126             key=lambda a: tuple(int(i) if i.isdigit() else i for i in a[0].split(".")), reverse=True,
127         )
128     return wheels
129 
130 
131 def download_wheel(packages, for_py_version, to_folder, app_data):
132     to_download = list(p if v is None else "{}={}".format(p, v) for p, v in packages.items())
133     logging.debug("download wheels %s", to_download)
134     cmd = [
135         sys.executable,
136         "-m",
137         "pip",
138         "download",
139         "--disable-pip-version-check",
140         "--only-binary=:all:",
141         "--no-deps",
142         "--python-version",
143         for_py_version,
144         "-d",
145         str(to_folder),
146     ]
147     cmd.extend(to_download)
148     # pip has no interface in python - must be a new sub-process
149 
150     with pip_wheel_env_run("{}{}".format(*sys.version_info[0:2]), app_data) as env:
151         process = Popen(cmd, env=env, stdout=subprocess.PIPE)
152         process.communicate()
153         if process.returncode != 0:
154             raise RuntimeError("failed to download wheels")
155 
156 
157 @contextmanager
158 def pip_wheel_env_run(version, app_data):
159     env = os.environ.copy()
160     env.update(
161         {
162             ensure_str(k): str(v)  # python 2 requires these to be string only (non-unicode)
163             for k, v in {"PIP_USE_WHEEL": "1", "PIP_USER": "0", "PIP_NO_INPUT": "1"}.items()
164         }
165     )
166     with ensure_file_on_disk(get_bundled_wheel("pip", version), app_data) as pip_wheel_path:
167         # put the bundled wheel onto the path, and use it to do the bootstrap operation
168         env[str("PYTHONPATH")] = str(pip_wheel_path)
169         yield env
170
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/virtualenv/seed/embed/wheels/acquire.py b/src/virtualenv/seed/embed/wheels/acquire.py
--- a/src/virtualenv/seed/embed/wheels/acquire.py
+++ b/src/virtualenv/seed/embed/wheels/acquire.py
@@ -129,7 +129,7 @@
 
 
 def download_wheel(packages, for_py_version, to_folder, app_data):
-    to_download = list(p if v is None else "{}={}".format(p, v) for p, v in packages.items())
+    to_download = list(p if v is None else "{}=={}".format(p, v) for p, v in packages.items())
     logging.debug("download wheels %s", to_download)
     cmd = [
         sys.executable,
diff --git a/src/virtualenv/util/path/_pathlib/via_os_path.py b/src/virtualenv/util/path/_pathlib/via_os_path.py
--- a/src/virtualenv/util/path/_pathlib/via_os_path.py
+++ b/src/virtualenv/util/path/_pathlib/via_os_path.py
@@ -111,9 +111,9 @@
     def parents(self):
         result = []
         parts = self.parts
-        for i in range(len(parts)):
+        for i in range(len(parts) - 1):
             result.append(Path(os.sep.join(parts[0 : i + 1])))
-        return result
+        return result[::-1]
 
     def unlink(self):
         os.remove(self._path)

{"golden_diff": "diff --git a/src/virtualenv/seed/embed/wheels/acquire.py b/src/virtualenv/seed/embed/wheels/acquire.py\n--- a/src/virtualenv/seed/embed/wheels/acquire.py\n+++ b/src/virtualenv/seed/embed/wheels/acquire.py\n@@ -129,7 +129,7 @@\n \n \n def download_wheel(packages, for_py_version, to_folder, app_data):\n-    to_download = list(p if v is None else \"{}={}\".format(p, v) for p, v in packages.items())\n+    to_download = list(p if v is None else \"{}=={}\".format(p, v) for p, v in packages.items())\n     logging.debug(\"download wheels %s\", to_download)\n     cmd = [\n         sys.executable,\ndiff --git a/src/virtualenv/util/path/_pathlib/via_os_path.py b/src/virtualenv/util/path/_pathlib/via_os_path.py\n--- a/src/virtualenv/util/path/_pathlib/via_os_path.py\n+++ b/src/virtualenv/util/path/_pathlib/via_os_path.py\n@@ -111,9 +111,9 @@\n     def parents(self):\n         result = []\n         parts = self.parts\n-        for i in range(len(parts)):\n+        for i in range(len(parts) - 1):\n             result.append(Path(os.sep.join(parts[0 : i + 1])))\n-        return result\n+        return result[::-1]\n \n     def unlink(self):\n         os.remove(self._path)\n", "issue": "pinning pip fails via app data seeder\n```\r\nVIRTUALENV_PIP=19.2.3 virtualenv --download --seeder app-data .venv\r\nERROR: Invalid requirement: 'pip=19.2.3'\r\n```\r\n\r\nfrom https://github.com/pglass/tox-pip-version/issues/17#issuecomment-616246861\n", "before_files": [{"content": "from __future__ import absolute_import, unicode_literals\n\nimport os\nimport platform\nfrom contextlib import contextmanager\n\nfrom virtualenv.util.six import ensure_str, ensure_text\n\nIS_PYPY = platform.python_implementation() == \"PyPy\"\n\n\nclass Path(object):\n    def __init__(self, path):\n        if isinstance(path, Path):\n            _path = path._path\n        else:\n            _path = ensure_text(path)\n            if IS_PYPY:\n                _path = _path.encode(\"utf-8\")\n        self._path = _path\n\n    def __repr__(self):\n        return ensure_str(\"Path({})\".format(ensure_text(self._path)))\n\n    def __unicode__(self):\n        return ensure_text(self._path)\n\n    def __str__(self):\n        return ensure_str(self._path)\n\n    def __div__(self, other):\n        if isinstance(other, Path):\n            right = other._path\n        else:\n            right = ensure_text(other)\n            if IS_PYPY:\n                right = right.encode(\"utf-8\")\n        return Path(os.path.join(self._path, right))\n\n    def __truediv__(self, other):\n        return self.__div__(other)\n\n    def __eq__(self, other):\n        return self._path == (other._path if isinstance(other, Path) else None)\n\n    def __ne__(self, other):\n        return not (self == other)\n\n    def __hash__(self):\n        return hash(self._path)\n\n    def exists(self):\n        return os.path.exists(self._path)\n\n    @property\n    def parent(self):\n        return Path(os.path.abspath(os.path.join(self._path, os.path.pardir)))\n\n    def resolve(self):\n        return Path(os.path.realpath(self._path))\n\n    @property\n    def name(self):\n        return os.path.basename(self._path)\n\n    @property\n    def parts(self):\n        return self._path.split(os.sep)\n\n    def is_file(self):\n        return os.path.isfile(self._path)\n\n    def is_dir(self):\n        return os.path.isdir(self._path)\n\n    def mkdir(self, parents=True, exist_ok=True):\n        if not self.exists() and exist_ok:\n            os.makedirs(self._path)\n\n    def read_text(self, encoding=\"utf-8\"):\n        return self.read_bytes().decode(encoding)\n\n    def read_bytes(self):\n        with open(self._path, \"rb\") as file_handler:\n            return file_handler.read()\n\n    def write_text(self, text, encoding=\"utf-8\"):\n        with open(self._path, \"wb\") as file_handler:\n            file_handler.write(text.encode(encoding))\n\n    def iterdir(self):\n        for p in os.listdir(self._path):\n            yield Path(os.path.join(self._path, p))\n\n    @property\n    def suffix(self):\n        _, ext = os.path.splitext(self.name)\n        return ext\n\n    @property\n    def stem(self):\n        base, _ = os.path.splitext(self.name)\n        return base\n\n    @contextmanager\n    def open(self, mode=\"r\"):\n        with open(self._path, mode) as file_handler:\n            yield file_handler\n\n    @property\n    def parents(self):\n        result = []\n        parts = self.parts\n        for i in range(len(parts)):\n            result.append(Path(os.sep.join(parts[0 : i + 1])))\n        return result\n\n    def unlink(self):\n        os.remove(self._path)\n\n    def with_name(self, name):\n        return self.parent / name\n\n    def is_symlink(self):\n        return os.path.islink(self._path)\n\n    def relative_to(self, other):\n        if not self._path.startswith(other._path):\n            raise ValueError(\"{} does not start with {}\".format(self._path, other._path))\n        return Path(os.sep.join(self.parts[len(other.parts) :]))\n\n    def stat(self):\n        return os.stat(self._path)\n\n    def chmod(self, mode):\n        os.chmod(self._path, mode)\n\n\n__all__ = (\"Path\",)\n", "path": "src/virtualenv/util/path/_pathlib/via_os_path.py"}, {"content": "\"\"\"Bootstrap\"\"\"\nfrom __future__ import absolute_import, unicode_literals\n\nimport logging\nimport os\nimport sys\nfrom collections import defaultdict\nfrom contextlib import contextmanager\nfrom copy import copy\nfrom shutil import copy2\nfrom zipfile import ZipFile\n\nfrom virtualenv.info import IS_ZIPAPP\nfrom virtualenv.util.path import Path\nfrom virtualenv.util.six import ensure_str, ensure_text\nfrom virtualenv.util.subprocess import Popen, subprocess\nfrom virtualenv.util.zipapp import ensure_file_on_disk\n\nfrom . import BUNDLE_SUPPORT, MAX\n\nBUNDLE_FOLDER = Path(os.path.abspath(__file__)).parent\n\n\ndef get_wheels(for_py_version, wheel_cache_dir, extra_search_dir, download, packages, app_data):\n    # not all wheels are compatible with all python versions, so we need to py version qualify it\n    processed = copy(packages)\n    # 1. acquire from bundle\n    acquire_from_bundle(processed, for_py_version, wheel_cache_dir)\n    # 2. acquire from extra search dir\n    acquire_from_dir(processed, for_py_version, wheel_cache_dir, extra_search_dir)\n    # 3. download from the internet\n    if download and processed:\n        download_wheel(processed, for_py_version, wheel_cache_dir, app_data)\n\n    # in the end just get the wheels\n    wheels = _get_wheels(wheel_cache_dir, packages)\n    return {p: next(iter(ver_to_files))[1] for p, ver_to_files in wheels.items()}\n\n\ndef acquire_from_bundle(packages, for_py_version, to_folder):\n    for pkg, version in list(packages.items()):\n        bundle = get_bundled_wheel(pkg, for_py_version)\n        if bundle is not None:\n            pkg_version = bundle.stem.split(\"-\")[1]\n            exact_version_match = version == pkg_version\n            if exact_version_match:\n                del packages[pkg]\n            if version is None or exact_version_match:\n                bundled_wheel_file = to_folder / bundle.name\n                if not bundled_wheel_file.exists():\n                    logging.debug(\"get bundled wheel %s\", bundle)\n                    if IS_ZIPAPP:\n                        from virtualenv.util.zipapp import extract\n\n                        extract(bundle, bundled_wheel_file)\n                    else:\n                        copy2(str(bundle), str(bundled_wheel_file))\n\n\ndef get_bundled_wheel(package, version_release):\n    return BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(version_release, {}) or BUNDLE_SUPPORT[MAX]).get(package)\n\n\ndef acquire_from_dir(packages, for_py_version, to_folder, extra_search_dir):\n    if not packages:\n        return\n    for search_dir in extra_search_dir:\n        wheels = _get_wheels(search_dir, packages)\n        for pkg, ver_wheels in wheels.items():\n            stop = False\n            for _, filename in ver_wheels:\n                dest = to_folder / filename.name\n                if not dest.exists():\n                    if wheel_support_py(filename, for_py_version):\n                        logging.debug(\"get extra search dir wheel %s\", filename)\n                        copy2(str(filename), str(dest))\n                        stop = True\n                else:\n                    stop = True\n                if stop and packages[pkg] is not None:\n                    del packages[pkg]\n                    break\n\n\ndef wheel_support_py(filename, py_version):\n    name = \"{}.dist-info/METADATA\".format(\"-\".join(filename.stem.split(\"-\")[0:2]))\n    with ZipFile(ensure_text(str(filename)), \"r\") as zip_file:\n        metadata = zip_file.read(name).decode(\"utf-8\")\n    marker = \"Requires-Python:\"\n    requires = next((i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker)), None)\n    if requires is None:  # if it does not specify a python requires the assumption is compatible\n        return True\n    py_version_int = tuple(int(i) for i in py_version.split(\".\"))\n    for require in (i.strip() for i in requires.split(\",\")):\n        # https://www.python.org/dev/peps/pep-0345/#version-specifiers\n        for operator, check in [\n            (\"!=\", lambda v: py_version_int != v),\n            (\"==\", lambda v: py_version_int == v),\n            (\"<=\", lambda v: py_version_int <= v),\n            (\">=\", lambda v: py_version_int >= v),\n            (\"<\", lambda v: py_version_int < v),\n            (\">\", lambda v: py_version_int > v),\n        ]:\n            if require.startswith(operator):\n                ver_str = require[len(operator) :].strip()\n                version = tuple((int(i) if i != \"*\" else None) for i in ver_str.split(\".\"))[0:2]\n                if not check(version):\n                    return False\n                break\n    return True\n\n\ndef _get_wheels(from_folder, packages):\n    wheels = defaultdict(list)\n    for filename in from_folder.iterdir():\n        if filename.suffix == \".whl\":\n            data = filename.stem.split(\"-\")\n            if len(data) >= 2:\n                pkg, version = data[0:2]\n                if pkg in packages:\n                    pkg_version = packages[pkg]\n                    if pkg_version is None or pkg_version == version:\n                        wheels[pkg].append((version, filename))\n    for versions in wheels.values():\n        versions.sort(\n            key=lambda a: tuple(int(i) if i.isdigit() else i for i in a[0].split(\".\")), reverse=True,\n        )\n    return wheels\n\n\ndef download_wheel(packages, for_py_version, to_folder, app_data):\n    to_download = list(p if v is None else \"{}={}\".format(p, v) for p, v in packages.items())\n    logging.debug(\"download wheels %s\", to_download)\n    cmd = [\n        sys.executable,\n        \"-m\",\n        \"pip\",\n        \"download\",\n        \"--disable-pip-version-check\",\n        \"--only-binary=:all:\",\n        \"--no-deps\",\n        \"--python-version\",\n        for_py_version,\n        \"-d\",\n        str(to_folder),\n    ]\n    cmd.extend(to_download)\n    # pip has no interface in python - must be a new sub-process\n\n    with pip_wheel_env_run(\"{}{}\".format(*sys.version_info[0:2]), app_data) as env:\n        process = Popen(cmd, env=env, stdout=subprocess.PIPE)\n        process.communicate()\n        if process.returncode != 0:\n            raise RuntimeError(\"failed to download wheels\")\n\n\n@contextmanager\ndef pip_wheel_env_run(version, app_data):\n    env = os.environ.copy()\n    env.update(\n        {\n            ensure_str(k): str(v)  # python 2 requires these to be string only (non-unicode)\n            for k, v in {\"PIP_USE_WHEEL\": \"1\", \"PIP_USER\": \"0\", \"PIP_NO_INPUT\": \"1\"}.items()\n        }\n    )\n    with ensure_file_on_disk(get_bundled_wheel(\"pip\", version), app_data) as pip_wheel_path:\n        # put the bundled wheel onto the path, and use it to do the bootstrap operation\n        env[str(\"PYTHONPATH\")] = str(pip_wheel_path)\n        yield env\n", "path": "src/virtualenv/seed/embed/wheels/acquire.py"}], "after_files": [{"content": "from __future__ import absolute_import, unicode_literals\n\nimport os\nimport platform\nfrom contextlib import contextmanager\n\nfrom virtualenv.util.six import ensure_str, ensure_text\n\nIS_PYPY = platform.python_implementation() == \"PyPy\"\n\n\nclass Path(object):\n    def __init__(self, path):\n        if isinstance(path, Path):\n            _path = path._path\n        else:\n            _path = ensure_text(path)\n            if IS_PYPY:\n                _path = _path.encode(\"utf-8\")\n        self._path = _path\n\n    def __repr__(self):\n        return ensure_str(\"Path({})\".format(ensure_text(self._path)))\n\n    def __unicode__(self):\n        return ensure_text(self._path)\n\n    def __str__(self):\n        return ensure_str(self._path)\n\n    def __div__(self, other):\n        if isinstance(other, Path):\n            right = other._path\n        else:\n            right = ensure_text(other)\n            if IS_PYPY:\n                right = right.encode(\"utf-8\")\n        return Path(os.path.join(self._path, right))\n\n    def __truediv__(self, other):\n        return self.__div__(other)\n\n    def __eq__(self, other):\n        return self._path == (other._path if isinstance(other, Path) else None)\n\n    def __ne__(self, other):\n        return not (self == other)\n\n    def __hash__(self):\n        return hash(self._path)\n\n    def exists(self):\n        return os.path.exists(self._path)\n\n    @property\n    def parent(self):\n        return Path(os.path.abspath(os.path.join(self._path, os.path.pardir)))\n\n    def resolve(self):\n        return Path(os.path.realpath(self._path))\n\n    @property\n    def name(self):\n        return os.path.basename(self._path)\n\n    @property\n    def parts(self):\n        return self._path.split(os.sep)\n\n    def is_file(self):\n        return os.path.isfile(self._path)\n\n    def is_dir(self):\n        return os.path.isdir(self._path)\n\n    def mkdir(self, parents=True, exist_ok=True):\n        if not self.exists() and exist_ok:\n            os.makedirs(self._path)\n\n    def read_text(self, encoding=\"utf-8\"):\n        return self.read_bytes().decode(encoding)\n\n    def read_bytes(self):\n        with open(self._path, \"rb\") as file_handler:\n            return file_handler.read()\n\n    def write_text(self, text, encoding=\"utf-8\"):\n        with open(self._path, \"wb\") as file_handler:\n            file_handler.write(text.encode(encoding))\n\n    def iterdir(self):\n        for p in os.listdir(self._path):\n            yield Path(os.path.join(self._path, p))\n\n    @property\n    def suffix(self):\n        _, ext = os.path.splitext(self.name)\n        return ext\n\n    @property\n    def stem(self):\n        base, _ = os.path.splitext(self.name)\n        return base\n\n    @contextmanager\n    def open(self, mode=\"r\"):\n        with open(self._path, mode) as file_handler:\n            yield file_handler\n\n    @property\n    def parents(self):\n        result = []\n        parts = self.parts\n        for i in range(len(parts) - 1):\n            result.append(Path(os.sep.join(parts[0 : i + 1])))\n        return result[::-1]\n\n    def unlink(self):\n        os.remove(self._path)\n\n    def with_name(self, name):\n        return self.parent / name\n\n    def is_symlink(self):\n        return os.path.islink(self._path)\n\n    def relative_to(self, other):\n        if not self._path.startswith(other._path):\n            raise ValueError(\"{} does not start with {}\".format(self._path, other._path))\n        return Path(os.sep.join(self.parts[len(other.parts) :]))\n\n    def stat(self):\n        return os.stat(self._path)\n\n    def chmod(self, mode):\n        os.chmod(self._path, mode)\n\n\n__all__ = (\"Path\",)\n", "path": "src/virtualenv/util/path/_pathlib/via_os_path.py"}, {"content": "\"\"\"Bootstrap\"\"\"\nfrom __future__ import absolute_import, unicode_literals\n\nimport logging\nimport os\nimport sys\nfrom collections import defaultdict\nfrom contextlib import contextmanager\nfrom copy import copy\nfrom shutil import copy2\nfrom zipfile import ZipFile\n\nfrom virtualenv.info import IS_ZIPAPP\nfrom virtualenv.util.path import Path\nfrom virtualenv.util.six import ensure_str, ensure_text\nfrom virtualenv.util.subprocess import Popen, subprocess\nfrom virtualenv.util.zipapp import ensure_file_on_disk\n\nfrom . import BUNDLE_SUPPORT, MAX\n\nBUNDLE_FOLDER = Path(os.path.abspath(__file__)).parent\n\n\ndef get_wheels(for_py_version, wheel_cache_dir, extra_search_dir, download, packages, app_data):\n    # not all wheels are compatible with all python versions, so we need to py version qualify it\n    processed = copy(packages)\n    # 1. acquire from bundle\n    acquire_from_bundle(processed, for_py_version, wheel_cache_dir)\n    # 2. acquire from extra search dir\n    acquire_from_dir(processed, for_py_version, wheel_cache_dir, extra_search_dir)\n    # 3. download from the internet\n    if download and processed:\n        download_wheel(processed, for_py_version, wheel_cache_dir, app_data)\n\n    # in the end just get the wheels\n    wheels = _get_wheels(wheel_cache_dir, packages)\n    return {p: next(iter(ver_to_files))[1] for p, ver_to_files in wheels.items()}\n\n\ndef acquire_from_bundle(packages, for_py_version, to_folder):\n    for pkg, version in list(packages.items()):\n        bundle = get_bundled_wheel(pkg, for_py_version)\n        if bundle is not None:\n            pkg_version = bundle.stem.split(\"-\")[1]\n            exact_version_match = version == pkg_version\n            if exact_version_match:\n                del packages[pkg]\n            if version is None or exact_version_match:\n                bundled_wheel_file = to_folder / bundle.name\n                if not bundled_wheel_file.exists():\n                    logging.debug(\"get bundled wheel %s\", bundle)\n                    if IS_ZIPAPP:\n                        from virtualenv.util.zipapp import extract\n\n                        extract(bundle, bundled_wheel_file)\n                    else:\n                        copy2(str(bundle), str(bundled_wheel_file))\n\n\ndef get_bundled_wheel(package, version_release):\n    return BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(version_release, {}) or BUNDLE_SUPPORT[MAX]).get(package)\n\n\ndef acquire_from_dir(packages, for_py_version, to_folder, extra_search_dir):\n    if not packages:\n        return\n    for search_dir in extra_search_dir:\n        wheels = _get_wheels(search_dir, packages)\n        for pkg, ver_wheels in wheels.items():\n            stop = False\n            for _, filename in ver_wheels:\n                dest = to_folder / filename.name\n                if not dest.exists():\n                    if wheel_support_py(filename, for_py_version):\n                        logging.debug(\"get extra search dir wheel %s\", filename)\n                        copy2(str(filename), str(dest))\n                        stop = True\n                else:\n                    stop = True\n                if stop and packages[pkg] is not None:\n                    del packages[pkg]\n                    break\n\n\ndef wheel_support_py(filename, py_version):\n    name = \"{}.dist-info/METADATA\".format(\"-\".join(filename.stem.split(\"-\")[0:2]))\n    with ZipFile(ensure_text(str(filename)), \"r\") as zip_file:\n        metadata = zip_file.read(name).decode(\"utf-8\")\n    marker = \"Requires-Python:\"\n    requires = next((i[len(marker) :] for i in metadata.splitlines() if i.startswith(marker)), None)\n    if requires is None:  # if it does not specify a python requires the assumption is compatible\n        return True\n    py_version_int = tuple(int(i) for i in py_version.split(\".\"))\n    for require in (i.strip() for i in requires.split(\",\")):\n        # https://www.python.org/dev/peps/pep-0345/#version-specifiers\n        for operator, check in [\n            (\"!=\", lambda v: py_version_int != v),\n            (\"==\", lambda v: py_version_int == v),\n            (\"<=\", lambda v: py_version_int <= v),\n            (\">=\", lambda v: py_version_int >= v),\n            (\"<\", lambda v: py_version_int < v),\n            (\">\", lambda v: py_version_int > v),\n        ]:\n            if require.startswith(operator):\n                ver_str = require[len(operator) :].strip()\n                version = tuple((int(i) if i != \"*\" else None) for i in ver_str.split(\".\"))[0:2]\n                if not check(version):\n                    return False\n                break\n    return True\n\n\ndef _get_wheels(from_folder, packages):\n    wheels = defaultdict(list)\n    for filename in from_folder.iterdir():\n        if filename.suffix == \".whl\":\n            data = filename.stem.split(\"-\")\n            if len(data) >= 2:\n                pkg, version = data[0:2]\n                if pkg in packages:\n                    pkg_version = packages[pkg]\n                    if pkg_version is None or pkg_version == version:\n                        wheels[pkg].append((version, filename))\n    for versions in wheels.values():\n        versions.sort(\n            key=lambda a: tuple(int(i) if i.isdigit() else i for i in a[0].split(\".\")), reverse=True,\n        )\n    return wheels\n\n\ndef download_wheel(packages, for_py_version, to_folder, app_data):\n    to_download = list(p if v is None else \"{}=={}\".format(p, v) for p, v in packages.items())\n    logging.debug(\"download wheels %s\", to_download)\n    cmd = [\n        sys.executable,\n        \"-m\",\n        \"pip\",\n        \"download\",\n        \"--disable-pip-version-check\",\n        \"--only-binary=:all:\",\n        \"--no-deps\",\n        \"--python-version\",\n        for_py_version,\n        \"-d\",\n        str(to_folder),\n    ]\n    cmd.extend(to_download)\n    # pip has no interface in python - must be a new sub-process\n\n    with pip_wheel_env_run(\"{}{}\".format(*sys.version_info[0:2]), app_data) as env:\n        process = Popen(cmd, env=env, stdout=subprocess.PIPE)\n        process.communicate()\n        if process.returncode != 0:\n            raise RuntimeError(\"failed to download wheels\")\n\n\n@contextmanager\ndef pip_wheel_env_run(version, app_data):\n    env = os.environ.copy()\n    env.update(\n        {\n            ensure_str(k): str(v)  # python 2 requires these to be string only (non-unicode)\n            for k, v in {\"PIP_USE_WHEEL\": \"1\", \"PIP_USER\": \"0\", \"PIP_NO_INPUT\": \"1\"}.items()\n        }\n    )\n    with ensure_file_on_disk(get_bundled_wheel(\"pip\", version), app_data) as pip_wheel_path:\n        # put the bundled wheel onto the path, and use it to do the bootstrap operation\n        env[str(\"PYTHONPATH\")] = str(pip_wheel_path)\n        yield env\n", "path": "src/virtualenv/seed/embed/wheels/acquire.py"}]}