We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
In virtual environment populated with `flit install -s` (editable), `python3 -m pip freeze` raises `AssertionError` on MacOS
**Environment**

* pip version: 20.2.3
* Python version: 3.8
* OS: MacOS 10.15.7 and Ubuntu 20.04 (tested on two different machines)

I created the virtual environments with `python3 -m venv ...` and populated them with `flit install -s` (which installs a local script as "editable" analogously to `python3 -m pip install --editable .`.

**Description**

When I run `python3 -m pip freeze' within the virtual environment, the following exception is raised:
```
ERROR: Exception:
Traceback (most recent call last):
  File "/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py", line 228, in _main
    status = self.run(options, args)
  File "/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py", line 101, in run
    for line in freeze(**freeze_kwargs):
  File "/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py", line 67, in freeze
    req = FrozenRequirement.from_dist(dist)
  File "/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py", line 257, in from_dist
    req = direct_url_as_pep440_direct_reference(
  File "/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py", line 49, in direct_url_as_pep440_direct_reference
    assert not direct_url.info.editable
AssertionError
```
@sbidoul @chrahunt I note that this assertion error was introduced a few months ago (see #7612).

**Expected behavior**

I expected pip to display a list of installed modules, as it does when I run pip 20.2.3 within virtual environments created prior to mid-August, e.g.:
```
alabaster==0.7.12
appdirs==1.4.4
astroid==2.4.2
attrs==19.3.0
Babel==2.8.0
black==19.10b0
```

**How to Reproduce**

1. Go to a Github repo with a Python script under development - or clone the small project [mklists](https://github.com/tombaker/mklists) that I used for this test (and note its [pyproject.toml](https://github.com/tombaker/mklists/blob/master/pyproject.toml).
2. Create a virtual environment, e.g.: `python3 -m venv .venv`
3. Activate the virtual environment, e.g.: `source .venv/bin/activate` (MacOS) or  `. .venv/bin/activate` (Ubuntu)
4. Install `flit`: `python3 -m pip install --upgrade flit`
5. Run `flit install -s` to install the local code as "editable".
6. Run `python3 -m pip freeze`.
7. Instead of displaying a list of installed modules, an exception is raised (as described above).

**Output (MacOS)**

```
577 [master] ~/github/tombaker/mklists> python3 -m venv .venv

578 [master] ~/github/tombaker/mklists> source .venv/bin/activate

(.venv) 579 [master] ~/github/tombaker/mklists> python3 -m pip install --upgrade flit
Collecting flit
  Using cached flit-3.0.0-py3-none-any.whl (48 kB)
... etc ...
Successfully installed certifi-2020.6.20 chardet-3.0.4 docutils-0.16 flit-3.0.0 flit-core-3.0.0 idna-2.10 pytoml-0.1.21 requests-2.24.0 urllib3-1.25.10
WARNING: You are using pip version 20.2.1; however, version 20.2.3 is available.
You should consider upgrading via the '/Users/tbaker/github/tombaker/mklists/.venv/bin/python3 -m pip install --upgrade pip' command.

(.venv) 580 [master] ~/github/tombaker/mklists> python3 -m pip install --upgrade pip
...
Successfully installed pip-20.2.3

(.venv) 581 [master] ~/github/tombaker/mklists> flit install -s
Extras to install for deps 'all': {'test', 'doc', '.none'}                                                                                                           I-flit.install
Installing requirements                                                                                                                                              I-flit.install
Collecting pytest
  Using cached pytest-6.1.1-py3-none-any.whl (272 kB)
... etc ...
Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1 ... etc ...
Symlinking mklists -> /Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/mklists                                                                I-flit.install
Writing script to /Users/tbaker/github/tombaker/mklists/.venv/bin/mklists                                                                                            I-flit.install

(.venv) 582 [master] ~/github/tombaker/mklists> python3 -m pip freeze
ERROR: Exception:
Traceback (most recent call last):
  File "/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py", line 228, in _main
    status = self.run(options, args)
  File "/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py", line 101, in run
    for line in freeze(**freeze_kwargs):
  File "/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py", line 67, in freeze
    req = FrozenRequirement.from_dist(dist)
  File "/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py", line 257, in from_dist
    req = direct_url_as_pep440_direct_reference(
  File "/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py", line 49, in direct_url_as_pep440_direct_reference
    assert not direct_url.info.editable
AssertionError
```

**Note** 

On 13 October, I described this issue on [Stackoverflow](https://stackoverflow.com/questions/64339735/python-virtual-environments-created-since-mid-august-raise-assertionerror-for)

--- 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/pip/_internal/utils/direct_url_helpers.py`
Content:
```
1 import logging
2 
3 from pip._internal.models.direct_url import (
4     DIRECT_URL_METADATA_NAME,
5     ArchiveInfo,
6     DirectUrl,
7     DirectUrlValidationError,
8     DirInfo,
9     VcsInfo,
10 )
11 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
12 from pip._internal.vcs import vcs
13 
14 try:
15     from json import JSONDecodeError
16 except ImportError:
17     # PY2
18     JSONDecodeError = ValueError  # type: ignore
19 
20 if MYPY_CHECK_RUNNING:
21     from typing import Optional
22 
23     from pip._vendor.pkg_resources import Distribution
24 
25     from pip._internal.models.link import Link
26 
27 logger = logging.getLogger(__name__)
28 
29 
30 def direct_url_as_pep440_direct_reference(direct_url, name):
31     # type: (DirectUrl, str) -> str
32     """Convert a DirectUrl to a pip requirement string."""
33     direct_url.validate()  # if invalid, this is a pip bug
34     requirement = name + " @ "
35     fragments = []
36     if isinstance(direct_url.info, VcsInfo):
37         requirement += "{}+{}@{}".format(
38             direct_url.info.vcs, direct_url.url, direct_url.info.commit_id
39         )
40     elif isinstance(direct_url.info, ArchiveInfo):
41         requirement += direct_url.url
42         if direct_url.info.hash:
43             fragments.append(direct_url.info.hash)
44     else:
45         assert isinstance(direct_url.info, DirInfo)
46         # pip should never reach this point for editables, since
47         # pip freeze inspects the editable project location to produce
48         # the requirement string
49         assert not direct_url.info.editable
50         requirement += direct_url.url
51     if direct_url.subdirectory:
52         fragments.append("subdirectory=" + direct_url.subdirectory)
53     if fragments:
54         requirement += "#" + "&".join(fragments)
55     return requirement
56 
57 
58 def direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False):
59     # type: (Link, Optional[str], bool) -> DirectUrl
60     if link.is_vcs:
61         vcs_backend = vcs.get_backend_for_scheme(link.scheme)
62         assert vcs_backend
63         url, requested_revision, _ = (
64             vcs_backend.get_url_rev_and_auth(link.url_without_fragment)
65         )
66         # For VCS links, we need to find out and add commit_id.
67         if link_is_in_wheel_cache:
68             # If the requested VCS link corresponds to a cached
69             # wheel, it means the requested revision was an
70             # immutable commit hash, otherwise it would not have
71             # been cached. In that case we don't have a source_dir
72             # with the VCS checkout.
73             assert requested_revision
74             commit_id = requested_revision
75         else:
76             # If the wheel was not in cache, it means we have
77             # had to checkout from VCS to build and we have a source_dir
78             # which we can inspect to find out the commit id.
79             assert source_dir
80             commit_id = vcs_backend.get_revision(source_dir)
81         return DirectUrl(
82             url=url,
83             info=VcsInfo(
84                 vcs=vcs_backend.name,
85                 commit_id=commit_id,
86                 requested_revision=requested_revision,
87             ),
88             subdirectory=link.subdirectory_fragment,
89         )
90     elif link.is_existing_dir():
91         return DirectUrl(
92             url=link.url_without_fragment,
93             info=DirInfo(),
94             subdirectory=link.subdirectory_fragment,
95         )
96     else:
97         hash = None
98         hash_name = link.hash_name
99         if hash_name:
100             hash = "{}={}".format(hash_name, link.hash)
101         return DirectUrl(
102             url=link.url_without_fragment,
103             info=ArchiveInfo(hash=hash),
104             subdirectory=link.subdirectory_fragment,
105         )
106 
107 
108 def dist_get_direct_url(dist):
109     # type: (Distribution) -> Optional[DirectUrl]
110     """Obtain a DirectUrl from a pkg_resource.Distribution.
111 
112     Returns None if the distribution has no `direct_url.json` metadata,
113     or if `direct_url.json` is invalid.
114     """
115     if not dist.has_metadata(DIRECT_URL_METADATA_NAME):
116         return None
117     try:
118         return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME))
119     except (
120         DirectUrlValidationError,
121         JSONDecodeError,
122         UnicodeDecodeError
123     ) as e:
124         logger.warning(
125             "Error parsing %s for %s: %s",
126             DIRECT_URL_METADATA_NAME,
127             dist.project_name,
128             e,
129         )
130         return None
131
```
--- 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/pip/_internal/utils/direct_url_helpers.py b/src/pip/_internal/utils/direct_url_helpers.py
--- a/src/pip/_internal/utils/direct_url_helpers.py
+++ b/src/pip/_internal/utils/direct_url_helpers.py
@@ -43,10 +43,6 @@
             fragments.append(direct_url.info.hash)
     else:
         assert isinstance(direct_url.info, DirInfo)
-        # pip should never reach this point for editables, since
-        # pip freeze inspects the editable project location to produce
-        # the requirement string
-        assert not direct_url.info.editable
         requirement += direct_url.url
     if direct_url.subdirectory:
         fragments.append("subdirectory=" + direct_url.subdirectory)

{"golden_diff": "diff --git a/src/pip/_internal/utils/direct_url_helpers.py b/src/pip/_internal/utils/direct_url_helpers.py\n--- a/src/pip/_internal/utils/direct_url_helpers.py\n+++ b/src/pip/_internal/utils/direct_url_helpers.py\n@@ -43,10 +43,6 @@\n             fragments.append(direct_url.info.hash)\n     else:\n         assert isinstance(direct_url.info, DirInfo)\n-        # pip should never reach this point for editables, since\n-        # pip freeze inspects the editable project location to produce\n-        # the requirement string\n-        assert not direct_url.info.editable\n         requirement += direct_url.url\n     if direct_url.subdirectory:\n         fragments.append(\"subdirectory=\" + direct_url.subdirectory)\n", "issue": "In virtual environment populated with `flit install -s` (editable), `python3 -m pip freeze` raises `AssertionError` on MacOS\n**Environment**\r\n\r\n* pip version: 20.2.3\r\n* Python version: 3.8\r\n* OS: MacOS 10.15.7 and Ubuntu 20.04 (tested on two different machines)\r\n\r\nI created the virtual environments with `python3 -m venv ...` and populated them with `flit install -s` (which installs a local script as \"editable\" analogously to `python3 -m pip install --editable .`.\r\n\r\n**Description**\r\n\r\nWhen I run `python3 -m pip freeze' within the virtual environment, the following exception is raised:\r\n```\r\nERROR: Exception:\r\nTraceback (most recent call last):\r\n  File \"/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py\", line 228, in _main\r\n    status = self.run(options, args)\r\n  File \"/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py\", line 101, in run\r\n    for line in freeze(**freeze_kwargs):\r\n  File \"/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py\", line 67, in freeze\r\n    req = FrozenRequirement.from_dist(dist)\r\n  File \"/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py\", line 257, in from_dist\r\n    req = direct_url_as_pep440_direct_reference(\r\n  File \"/Users/tbaker/venvs/dcapenv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py\", line 49, in direct_url_as_pep440_direct_reference\r\n    assert not direct_url.info.editable\r\nAssertionError\r\n```\r\n@sbidoul @chrahunt I note that this assertion error was introduced a few months ago (see #7612).\r\n\r\n**Expected behavior**\r\n\r\nI expected pip to display a list of installed modules, as it does when I run pip 20.2.3 within virtual environments created prior to mid-August, e.g.:\r\n```\r\nalabaster==0.7.12\r\nappdirs==1.4.4\r\nastroid==2.4.2\r\nattrs==19.3.0\r\nBabel==2.8.0\r\nblack==19.10b0\r\n```\r\n\r\n**How to Reproduce**\r\n\r\n1. Go to a Github repo with a Python script under development - or clone the small project [mklists](https://github.com/tombaker/mklists) that I used for this test (and note its [pyproject.toml](https://github.com/tombaker/mklists/blob/master/pyproject.toml).\r\n2. Create a virtual environment, e.g.: `python3 -m venv .venv`\r\n3. Activate the virtual environment, e.g.: `source .venv/bin/activate` (MacOS) or  `. .venv/bin/activate` (Ubuntu)\r\n4. Install `flit`: `python3 -m pip install --upgrade flit`\r\n5. Run `flit install -s` to install the local code as \"editable\".\r\n6. Run `python3 -m pip freeze`.\r\n7. Instead of displaying a list of installed modules, an exception is raised (as described above).\r\n\r\n**Output (MacOS)**\r\n\r\n```\r\n577 [master] ~/github/tombaker/mklists> python3 -m venv .venv\r\n\r\n578 [master] ~/github/tombaker/mklists> source .venv/bin/activate\r\n\r\n(.venv) 579 [master] ~/github/tombaker/mklists> python3 -m pip install --upgrade flit\r\nCollecting flit\r\n  Using cached flit-3.0.0-py3-none-any.whl (48 kB)\r\n... etc ...\r\nSuccessfully installed certifi-2020.6.20 chardet-3.0.4 docutils-0.16 flit-3.0.0 flit-core-3.0.0 idna-2.10 pytoml-0.1.21 requests-2.24.0 urllib3-1.25.10\r\nWARNING: You are using pip version 20.2.1; however, version 20.2.3 is available.\r\nYou should consider upgrading via the '/Users/tbaker/github/tombaker/mklists/.venv/bin/python3 -m pip install --upgrade pip' command.\r\n\r\n(.venv) 580 [master] ~/github/tombaker/mklists> python3 -m pip install --upgrade pip\r\n...\r\nSuccessfully installed pip-20.2.3\r\n\r\n(.venv) 581 [master] ~/github/tombaker/mklists> flit install -s\r\nExtras to install for deps 'all': {'test', 'doc', '.none'}                                                                                                           I-flit.install\r\nInstalling requirements                                                                                                                                              I-flit.install\r\nCollecting pytest\r\n  Using cached pytest-6.1.1-py3-none-any.whl (272 kB)\r\n... etc ...\r\nSuccessfully installed Jinja2-2.11.2 MarkupSafe-1.1.1 ... etc ...\r\nSymlinking mklists -> /Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/mklists                                                                I-flit.install\r\nWriting script to /Users/tbaker/github/tombaker/mklists/.venv/bin/mklists                                                                                            I-flit.install\r\n\r\n(.venv) 582 [master] ~/github/tombaker/mklists> python3 -m pip freeze\r\nERROR: Exception:\r\nTraceback (most recent call last):\r\n  File \"/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py\", line 228, in _main\r\n    status = self.run(options, args)\r\n  File \"/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py\", line 101, in run\r\n    for line in freeze(**freeze_kwargs):\r\n  File \"/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py\", line 67, in freeze\r\n    req = FrozenRequirement.from_dist(dist)\r\n  File \"/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py\", line 257, in from_dist\r\n    req = direct_url_as_pep440_direct_reference(\r\n  File \"/Users/tbaker/github/tombaker/mklists/.venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py\", line 49, in direct_url_as_pep440_direct_reference\r\n    assert not direct_url.info.editable\r\nAssertionError\r\n```\r\n\r\n**Note** \r\n\r\nOn 13 October, I described this issue on [Stackoverflow](https://stackoverflow.com/questions/64339735/python-virtual-environments-created-since-mid-august-raise-assertionerror-for)\n", "before_files": [{"content": "import logging\n\nfrom pip._internal.models.direct_url import (\n    DIRECT_URL_METADATA_NAME,\n    ArchiveInfo,\n    DirectUrl,\n    DirectUrlValidationError,\n    DirInfo,\n    VcsInfo,\n)\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\nfrom pip._internal.vcs import vcs\n\ntry:\n    from json import JSONDecodeError\nexcept ImportError:\n    # PY2\n    JSONDecodeError = ValueError  # type: ignore\n\nif MYPY_CHECK_RUNNING:\n    from typing import Optional\n\n    from pip._vendor.pkg_resources import Distribution\n\n    from pip._internal.models.link import Link\n\nlogger = logging.getLogger(__name__)\n\n\ndef direct_url_as_pep440_direct_reference(direct_url, name):\n    # type: (DirectUrl, str) -> str\n    \"\"\"Convert a DirectUrl to a pip requirement string.\"\"\"\n    direct_url.validate()  # if invalid, this is a pip bug\n    requirement = name + \" @ \"\n    fragments = []\n    if isinstance(direct_url.info, VcsInfo):\n        requirement += \"{}+{}@{}\".format(\n            direct_url.info.vcs, direct_url.url, direct_url.info.commit_id\n        )\n    elif isinstance(direct_url.info, ArchiveInfo):\n        requirement += direct_url.url\n        if direct_url.info.hash:\n            fragments.append(direct_url.info.hash)\n    else:\n        assert isinstance(direct_url.info, DirInfo)\n        # pip should never reach this point for editables, since\n        # pip freeze inspects the editable project location to produce\n        # the requirement string\n        assert not direct_url.info.editable\n        requirement += direct_url.url\n    if direct_url.subdirectory:\n        fragments.append(\"subdirectory=\" + direct_url.subdirectory)\n    if fragments:\n        requirement += \"#\" + \"&\".join(fragments)\n    return requirement\n\n\ndef direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False):\n    # type: (Link, Optional[str], bool) -> DirectUrl\n    if link.is_vcs:\n        vcs_backend = vcs.get_backend_for_scheme(link.scheme)\n        assert vcs_backend\n        url, requested_revision, _ = (\n            vcs_backend.get_url_rev_and_auth(link.url_without_fragment)\n        )\n        # For VCS links, we need to find out and add commit_id.\n        if link_is_in_wheel_cache:\n            # If the requested VCS link corresponds to a cached\n            # wheel, it means the requested revision was an\n            # immutable commit hash, otherwise it would not have\n            # been cached. In that case we don't have a source_dir\n            # with the VCS checkout.\n            assert requested_revision\n            commit_id = requested_revision\n        else:\n            # If the wheel was not in cache, it means we have\n            # had to checkout from VCS to build and we have a source_dir\n            # which we can inspect to find out the commit id.\n            assert source_dir\n            commit_id = vcs_backend.get_revision(source_dir)\n        return DirectUrl(\n            url=url,\n            info=VcsInfo(\n                vcs=vcs_backend.name,\n                commit_id=commit_id,\n                requested_revision=requested_revision,\n            ),\n            subdirectory=link.subdirectory_fragment,\n        )\n    elif link.is_existing_dir():\n        return DirectUrl(\n            url=link.url_without_fragment,\n            info=DirInfo(),\n            subdirectory=link.subdirectory_fragment,\n        )\n    else:\n        hash = None\n        hash_name = link.hash_name\n        if hash_name:\n            hash = \"{}={}\".format(hash_name, link.hash)\n        return DirectUrl(\n            url=link.url_without_fragment,\n            info=ArchiveInfo(hash=hash),\n            subdirectory=link.subdirectory_fragment,\n        )\n\n\ndef dist_get_direct_url(dist):\n    # type: (Distribution) -> Optional[DirectUrl]\n    \"\"\"Obtain a DirectUrl from a pkg_resource.Distribution.\n\n    Returns None if the distribution has no `direct_url.json` metadata,\n    or if `direct_url.json` is invalid.\n    \"\"\"\n    if not dist.has_metadata(DIRECT_URL_METADATA_NAME):\n        return None\n    try:\n        return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME))\n    except (\n        DirectUrlValidationError,\n        JSONDecodeError,\n        UnicodeDecodeError\n    ) as e:\n        logger.warning(\n            \"Error parsing %s for %s: %s\",\n            DIRECT_URL_METADATA_NAME,\n            dist.project_name,\n            e,\n        )\n        return None\n", "path": "src/pip/_internal/utils/direct_url_helpers.py"}], "after_files": [{"content": "import logging\n\nfrom pip._internal.models.direct_url import (\n    DIRECT_URL_METADATA_NAME,\n    ArchiveInfo,\n    DirectUrl,\n    DirectUrlValidationError,\n    DirInfo,\n    VcsInfo,\n)\nfrom pip._internal.utils.typing import MYPY_CHECK_RUNNING\nfrom pip._internal.vcs import vcs\n\ntry:\n    from json import JSONDecodeError\nexcept ImportError:\n    # PY2\n    JSONDecodeError = ValueError  # type: ignore\n\nif MYPY_CHECK_RUNNING:\n    from typing import Optional\n\n    from pip._vendor.pkg_resources import Distribution\n\n    from pip._internal.models.link import Link\n\nlogger = logging.getLogger(__name__)\n\n\ndef direct_url_as_pep440_direct_reference(direct_url, name):\n    # type: (DirectUrl, str) -> str\n    \"\"\"Convert a DirectUrl to a pip requirement string.\"\"\"\n    direct_url.validate()  # if invalid, this is a pip bug\n    requirement = name + \" @ \"\n    fragments = []\n    if isinstance(direct_url.info, VcsInfo):\n        requirement += \"{}+{}@{}\".format(\n            direct_url.info.vcs, direct_url.url, direct_url.info.commit_id\n        )\n    elif isinstance(direct_url.info, ArchiveInfo):\n        requirement += direct_url.url\n        if direct_url.info.hash:\n            fragments.append(direct_url.info.hash)\n    else:\n        assert isinstance(direct_url.info, DirInfo)\n        requirement += direct_url.url\n    if direct_url.subdirectory:\n        fragments.append(\"subdirectory=\" + direct_url.subdirectory)\n    if fragments:\n        requirement += \"#\" + \"&\".join(fragments)\n    return requirement\n\n\ndef direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False):\n    # type: (Link, Optional[str], bool) -> DirectUrl\n    if link.is_vcs:\n        vcs_backend = vcs.get_backend_for_scheme(link.scheme)\n        assert vcs_backend\n        url, requested_revision, _ = (\n            vcs_backend.get_url_rev_and_auth(link.url_without_fragment)\n        )\n        # For VCS links, we need to find out and add commit_id.\n        if link_is_in_wheel_cache:\n            # If the requested VCS link corresponds to a cached\n            # wheel, it means the requested revision was an\n            # immutable commit hash, otherwise it would not have\n            # been cached. In that case we don't have a source_dir\n            # with the VCS checkout.\n            assert requested_revision\n            commit_id = requested_revision\n        else:\n            # If the wheel was not in cache, it means we have\n            # had to checkout from VCS to build and we have a source_dir\n            # which we can inspect to find out the commit id.\n            assert source_dir\n            commit_id = vcs_backend.get_revision(source_dir)\n        return DirectUrl(\n            url=url,\n            info=VcsInfo(\n                vcs=vcs_backend.name,\n                commit_id=commit_id,\n                requested_revision=requested_revision,\n            ),\n            subdirectory=link.subdirectory_fragment,\n        )\n    elif link.is_existing_dir():\n        return DirectUrl(\n            url=link.url_without_fragment,\n            info=DirInfo(),\n            subdirectory=link.subdirectory_fragment,\n        )\n    else:\n        hash = None\n        hash_name = link.hash_name\n        if hash_name:\n            hash = \"{}={}\".format(hash_name, link.hash)\n        return DirectUrl(\n            url=link.url_without_fragment,\n            info=ArchiveInfo(hash=hash),\n            subdirectory=link.subdirectory_fragment,\n        )\n\n\ndef dist_get_direct_url(dist):\n    # type: (Distribution) -> Optional[DirectUrl]\n    \"\"\"Obtain a DirectUrl from a pkg_resource.Distribution.\n\n    Returns None if the distribution has no `direct_url.json` metadata,\n    or if `direct_url.json` is invalid.\n    \"\"\"\n    if not dist.has_metadata(DIRECT_URL_METADATA_NAME):\n        return None\n    try:\n        return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME))\n    except (\n        DirectUrlValidationError,\n        JSONDecodeError,\n        UnicodeDecodeError\n    ) as e:\n        logger.warning(\n            \"Error parsing %s for %s: %s\",\n            DIRECT_URL_METADATA_NAME,\n            dist.project_name,\n            e,\n        )\n        return None\n", "path": "src/pip/_internal/utils/direct_url_helpers.py"}]}