@@ -55,25 +55,37 @@ class LinkHash:
55
55
name : str
56
56
value : str
57
57
58
- _hash_re = re .compile (
58
+ _hash_url_fragment_re = re .compile (
59
59
# NB: we do not validate that the second group (.*) is a valid hex
60
60
# digest. Instead, we simply keep that string in this class, and then check it
61
61
# against Hashes when hash-checking is needed. This is easier to debug than
62
62
# proactively discarding an invalid hex digest, as we handle incorrect hashes
63
63
# and malformed hashes in the same place.
64
- r"({choices})=(. *)" .format (
64
+ r"[#&] ({choices})=([^&] *)" .format (
65
65
choices = "|" .join (re .escape (hash_name ) for hash_name in _SUPPORTED_HASHES )
66
66
),
67
67
)
68
68
69
69
def __post_init__ (self ) -> None :
70
- assert self ._hash_re .match (f"{ self .name } ={ self .value } " )
70
+ assert self .name in _SUPPORTED_HASHES
71
+
72
+ @classmethod
73
+ def parse_pep658_hash (cls , dist_info_metadata : str ) -> Optional ["LinkHash" ]:
74
+ """Parse a PEP 658 data-dist-info-metadata hash."""
75
+ if dist_info_metadata == "true" :
76
+ return None
77
+ name , sep , value = dist_info_metadata .partition ("=" )
78
+ if not sep :
79
+ return None
80
+ if name not in _SUPPORTED_HASHES :
81
+ return None
82
+ return cls (name = name , value = value )
71
83
72
84
@classmethod
73
85
@functools .lru_cache (maxsize = None )
74
- def split_hash_name_and_value (cls , url : str ) -> Optional ["LinkHash" ]:
86
+ def find_hash_url_fragment (cls , url : str ) -> Optional ["LinkHash" ]:
75
87
"""Search a string for a checksum algorithm name and encoded output value."""
76
- match = cls ._hash_re .search (url )
88
+ match = cls ._hash_url_fragment_re .search (url )
77
89
if match is None :
78
90
return None
79
91
name , value = match .groups ()
@@ -217,7 +229,7 @@ def __init__(
217
229
# trying to set a new value.
218
230
self ._url = url
219
231
220
- link_hash = LinkHash .split_hash_name_and_value (url )
232
+ link_hash = LinkHash .find_hash_url_fragment (url )
221
233
hashes_from_link = {} if link_hash is None else link_hash .as_dict ()
222
234
if hashes is None :
223
235
self ._hashes = hashes_from_link
@@ -402,15 +414,10 @@ def metadata_link(self) -> Optional["Link"]:
402
414
if self .dist_info_metadata is None :
403
415
return None
404
416
metadata_url = f"{ self .url_without_fragment } .metadata"
405
- # If data-dist-info-metadata="true" is set, then the metadata file exists,
406
- # but there is no information about its checksum or anything else.
407
- if self .dist_info_metadata != "true" :
408
- link_hash = LinkHash .split_hash_name_and_value (self .dist_info_metadata )
409
- else :
410
- link_hash = None
411
- if link_hash is None :
417
+ metadata_link_hash = LinkHash .parse_pep658_hash (self .dist_info_metadata )
418
+ if metadata_link_hash is None :
412
419
return Link (metadata_url )
413
- return Link (metadata_url , hashes = link_hash .as_dict ())
420
+ return Link (metadata_url , hashes = metadata_link_hash .as_dict ())
414
421
415
422
def as_hashes (self ) -> Hashes :
416
423
return Hashes ({k : [v ] for k , v in self ._hashes .items ()})
0 commit comments