Skip to content

Commit 48a497b

Browse files
committed
Add utilities to check PEP 610 to incoming link
1 parent 02b4f86 commit 48a497b

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/pip/_internal/models/link.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ class _CleanResult(NamedTuple):
259259

260260
def _clean_link(link: Link) -> _CleanResult:
261261
parsed = link._parsed_url
262-
netloc = parsed.netloc.rsplit("@", 1)[-1]
262+
netloc, _ = split_auth_from_netloc(parsed.netloc)
263263
# According to RFC 8089, an empty host in file: means localhost.
264264
if parsed.scheme == "file" and not netloc:
265265
netloc = "localhost"

src/pip/_internal/utils/direct_url_helpers.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from typing import Optional
1+
from typing import List, Optional
22

33
from pip._internal.models.direct_url import ArchiveInfo, DirectUrl, DirInfo, VcsInfo
4-
from pip._internal.models.link import Link
4+
from pip._internal.models.link import Link, links_equivalent
55
from pip._internal.utils.urls import path_to_url
66
from pip._internal.vcs import vcs
77

@@ -85,3 +85,42 @@ def direct_url_from_link(
8585
info=ArchiveInfo(hash=hash),
8686
subdirectory=link.subdirectory_fragment,
8787
)
88+
89+
90+
def _link_from_direct_url(direct_url: DirectUrl) -> Link:
91+
"""Create a link from given direct URL construct.
92+
93+
This function is designed specifically for ``link_matches_direct_url``, and
94+
does NOT losslessly reconstruct the original link that produced the
95+
DirectUrl. Namely:
96+
97+
* The auth part is ignored (since it does not affect link equivalency).
98+
* Only "subdirectory" and hash fragment parts are considered, and the
99+
ordering of the kept parts are not considered (since only their values
100+
affect link equivalency).
101+
102+
.. seealso:: ``pip._internal.models.link.links_equivalent()``
103+
"""
104+
url = direct_url.url
105+
hash_frag = ""
106+
107+
direct_url_info = direct_url.info
108+
if isinstance(direct_url_info, VcsInfo):
109+
url = f"{url}@{direct_url_info.requested_revision}"
110+
elif isinstance(direct_url_info, ArchiveInfo):
111+
hash_frag = direct_url_info.hash
112+
113+
fragment_parts: List[str] = []
114+
if direct_url.subdirectory is not None:
115+
fragment_parts.append(f"subdirectory={direct_url.subdirectory}")
116+
if hash_frag:
117+
fragment_parts.append(hash_frag)
118+
if fragment_parts:
119+
fragment = "&".join(fragment_parts)
120+
url = f"{url}#{fragment}"
121+
122+
return Link(url)
123+
124+
125+
def link_matches_direct_url(link: Link, direct_url: DirectUrl) -> bool:
126+
return links_equivalent(link, _link_from_direct_url(direct_url))

0 commit comments

Comments
 (0)