Skip to content

Commit ddf0706

Browse files
committed
feat: generate provenance_url.json when installing packages(PEP 710)
Signed-off-by: Frost Ming <[email protected]>
1 parent 810c6c6 commit ddf0706

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

src/pdm/installers/installers.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import json
43
import os
54
import stat
65
from functools import cached_property
@@ -151,7 +150,7 @@ def _get_link_method(cache_method: str) -> LinkMethod:
151150
def install_wheel(
152151
wheel: Path,
153152
environment: BaseEnvironment,
154-
direct_url: dict[str, Any] | None = None,
153+
additional_metadata: dict[str, bytes] | None = None,
155154
install_links: bool = False,
156155
rename_pth: bool = False,
157156
) -> str:
@@ -169,9 +168,8 @@ def install_wheel(
169168
else:
170169
link_method = _get_link_method(cache_method)
171170

172-
additional_metadata: dict[str, bytes] = {}
173-
if direct_url is not None:
174-
additional_metadata["direct_url.json"] = json.dumps(direct_url, indent=2).encode()
171+
if additional_metadata is None:
172+
additional_metadata = {}
175173

176174
destination = InstallDestination(
177175
scheme_dict=environment.get_paths(dist_name),

src/pdm/installers/manager.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import json
34
from typing import TYPE_CHECKING
45

56
from pdm import termui
@@ -29,10 +30,16 @@ def __init__(
2930
def install(self, candidate: Candidate) -> Distribution:
3031
"""Install a candidate into the environment, return the distribution"""
3132
prepared = candidate.prepare(self.environment)
33+
wheel = prepared.build()
34+
additional_metadata: dict[str, bytes] = {}
35+
if direct_url := prepared.direct_url():
36+
additional_metadata["direct_url.json"] = json.dumps(direct_url, indent=2).encode("utf-8")
37+
elif provenance_url := prepared.provenance_url():
38+
additional_metadata["provenance_url.json"] = json.dumps(provenance_url, indent=2).encode("utf-8")
3239
dist_info = install_wheel(
33-
prepared.build(),
40+
wheel,
3441
self.environment,
35-
direct_url=prepared.direct_url(),
42+
additional_metadata=additional_metadata,
3643
install_links=self.use_install_cache and not candidate.req.editable,
3744
rename_pth=self.rename_pth,
3845
)

src/pdm/models/candidates.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import dataclasses
44
import hashlib
55
import os
6+
import posixpath
67
import re
78
import warnings
89
from functools import cached_property
@@ -21,6 +22,7 @@
2122
from pdm.models.reporter import BaseReporter
2223
from pdm.models.requirements import (
2324
FileRequirement,
25+
NamedRequirement,
2426
Requirement,
2527
VcsRequirement,
2628
_egg_info_re,
@@ -47,6 +49,9 @@
4749
from pdm.environments import BaseEnvironment
4850

4951

52+
ALLOWED_HASHES = hashlib.algorithms_guaranteed - {"shake_128", "shake_256", "sha1", "md5"}
53+
54+
5055
def _dist_info_files(whl_zip: ZipFile) -> list[str]:
5156
"""Identify the .dist-info folder inside a wheel ZipFile."""
5257
res = []
@@ -335,7 +340,9 @@ def revision(self) -> str:
335340
)
336341

337342
def direct_url(self) -> dict[str, Any] | None:
338-
"""PEP 610 direct_url.json data"""
343+
"""PEP 610 direct_url.json data
344+
https://peps.python.org/pep-0610/
345+
"""
339346
req = self.req
340347
if isinstance(req, VcsRequirement):
341348
if req.editable:
@@ -383,6 +390,29 @@ def direct_url(self) -> dict[str, Any] | None:
383390
else:
384391
return None
385392

393+
def provenance_url(self) -> dict[str, Any] | None:
394+
"""PEP 710 provenance_url.json data
395+
https://peps.python.org/pep-0710/
396+
"""
397+
req = self.req
398+
if not isinstance(req, NamedRequirement):
399+
return None
400+
assert self.link is not None
401+
comes_from = self.link.comes_from # e.g. https://pypi.org/simple/requests/
402+
if comes_from is None: # can't determine the index_url
403+
return None
404+
# FIXME: what about find-links source?
405+
index_url = posixpath.dirname(comes_from.rstrip("/")) + "/"
406+
return {
407+
"url": self.link.url_without_fragment,
408+
"index_url": index_url,
409+
"archive_info": {
410+
"hashes": {
411+
name: hashes[0] for name, hashes in (self.link.hash_option or {}).items() if name in ALLOWED_HASHES
412+
},
413+
},
414+
}
415+
386416
def build(self) -> Path:
387417
"""Call PEP 517 build hook to build the candidate into a wheel"""
388418
self._obtain(allow_all=False)

0 commit comments

Comments
 (0)