Skip to content

Commit

Permalink
Merge pull request #133 from chriskuehl/pep658
Browse files Browse the repository at this point in the history
Add support for PEP658 core metadata
  • Loading branch information
chriskuehl authored Oct 3, 2023
2 parents dd4b67e + 1a2868b commit 41b38c6
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 3 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,20 @@ format listed above of one filename per line, format your file with one JSON
object per line, like this:

```json
{"filename": "dumb-init-1.1.2.tar.gz", "hash": "md5=<hash>", "requires_dist": ["cfgv"], "requires_python": ">=3.6", "uploaded_by": "ckuehl", "upload_timestamp": 1512539924, "yanked_reason": null}
{"filename": "dumb-init-1.1.2.tar.gz", "hash": "sha256=<hash>", "requires_python": ">=3.6", "uploaded_by": "ckuehl", "upload_timestamp": 1512539924, "yanked_reason": null, "core_metadata": "sha256=<hash>"}
```

| Key | Required? | Description |
| -------------------- | --------- | ----------- |
| `filename` | Yes | Name of the file |
| `hash` | No | Hash of the file in the format `<hashalgo>=<hashvalue>` |
| `requires_python` | No | Python requirement string for the package ([PEP345](https://peps.python.org/pep-0345/#requires-python)) |
| `core_metadata` | No | Either string `"true"` or a string in the format `<hashalgo>=<hashvalue>` to indicate metadata is available for this file by appending `.metadata` to the file URL ([PEP658](https://peps.python.org/pep-0658/), [PEP714](https://peps.python.org/pep-0714/)) |
| `uploaded_by` | No | Freeform text to indicate an uploader of the package; only shown on web UI |
| `upload_timestamp` | No | UNIX timestamp to indicate upload time of the package |
| `yanked_reason` | No | Freeform text to indicate the package is yanked for the given reason ([PEP592](https://peps.python.org/pep-0592/)) |
| `requires_dist` | No | _(Deprecated)_ Array of requires_dist dependencies ([PEP345](https://peps.python.org/pep-0345/#requires-python)), used only in the JSON API; consider using `core_metadata` instead |

The `filename` key is required. All other keys are optional and will be used to
provide additional information in your generated repository. This extended
information can be useful to determine, for example, who uploaded a package.
Expand Down
3 changes: 3 additions & 0 deletions dumb_pypi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class Package(NamedTuple):
hash: str | None
requires_dist: tuple[str, ...] | None
requires_python: str | None
core_metadata: str | None
upload_timestamp: int | None
uploaded_by: str | None
yanked_reason: str | None
Expand Down Expand Up @@ -197,6 +198,7 @@ def create(
upload_timestamp: int | None = None,
uploaded_by: str | None = None,
yanked_reason: str | None = None,
core_metadata: str | None = None,
) -> Package:
if not re.match(r'[a-zA-Z0-9_\-\.\+]+$', filename) or '..' in filename:
raise ValueError(f'Unsafe package name: {filename}')
Expand All @@ -210,6 +212,7 @@ def create(
hash=hash,
requires_dist=tuple(requires_dist) if requires_dist is not None else None,
requires_python=requires_python,
core_metadata=core_metadata,
upload_timestamp=upload_timestamp,
uploaded_by=uploaded_by,
yanked_reason=yanked_reason,
Expand Down
3 changes: 3 additions & 0 deletions dumb_pypi/templates/package.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ <h1>{{package_name}}</h1>
{%- if file.requires_python %}
data-requires-python="{{file.requires_python}}"
{%- endif %}
{%- if file.core_metadata %}
data-core-metadata="{{file.core_metadata}}"
{%- endif %}
{%- if file.yanked_reason %}
data-yanked="{{file.yanked_reason}}"
{%- endif %}
Expand Down
16 changes: 15 additions & 1 deletion testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import subprocess
import sys
import tempfile
import zipfile
from typing import NamedTuple

from dumb_pypi import main
Expand All @@ -26,6 +27,7 @@ def as_json(self):
return json.dumps({
'filename': self.filename,
'requires_python': self.requires_python,
'core_metadata': 'true' if self.filename.endswith('.whl') else None,
})


Expand All @@ -50,4 +52,16 @@ def make_package(package: FakePackage, path: str) -> None:

subprocess.check_call((sys.executable, setup_py) + args, cwd=td)
created, = os.listdir(os.path.join(td, 'dist'))
shutil.move(os.path.join(td, 'dist', created), os.path.join(path, package.filename))
dest = os.path.join(path, package.filename)
shutil.move(os.path.join(td, 'dist', created), dest)

# Extract PEP658 metadata.
if dest.endswith('.whl'):
with zipfile.ZipFile(dest) as zf:
metadata_path, = (
name
for name in zf.namelist()
if name.endswith('.dist-info/METADATA')
)
with open(f'{dest}.metadata', 'wb') as f:
f.write(zf.read(metadata_path))
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import requests


PIP_TEST_VERSION = '23.1.2'
PIP_TEST_VERSION = '23.2.1'


UrlAndPath = collections.namedtuple('UrlAndPath', ('url', 'path'))
Expand Down
19 changes: 19 additions & 0 deletions tests/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,22 @@ def test_pip_respects_requires_python(tmpdir, tmpweb, pip):
)
downloaded_package, = tmpdir.listdir(fil=os.path.isfile)
assert downloaded_package.basename == 'foo-2.tar.gz'


def test_pip_uses_core_metadata(capfd, tmpdir, tmpweb, pip):
install_packages(
tmpweb.path,
(FakePackage('foo-1-py2.py3-none-any.whl'),)
)
pip_download(
pip,
tmpweb.url + '/simple',
tmpdir.strpath,
'foo',
)
downloaded_package, = tmpdir.listdir(fil=os.path.isfile)
assert downloaded_package.basename == 'foo-1-py2.py3-none-any.whl'
assert (
f'Obtaining dependency information for foo from {tmpweb.url}/pool/foo-1-py2.py3-none-any.whl.metadata'
in capfd.readouterr().out
)
2 changes: 2 additions & 0 deletions tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def test_input_json_all_info():
hash='sha256=deadbeef',
requires_dist=['aspy.yaml'],
requires_python='>=3.6',
core_metadata="sha256=badc0ffee",
uploaded_by='asottile',
upload_timestamp=1528586805,
yanked_reason='Wrong Python Pinning',
Expand All @@ -177,6 +178,7 @@ def test_input_json_all_info():
'hash': 'sha256=deadbeef',
'requires_dist': ('aspy.yaml',),
'requires_python': '>=3.6',
'core_metadata': 'sha256=badc0ffee',
'uploaded_by': 'asottile',
'upload_timestamp': 1528586805,
'yanked_reason': 'Wrong Python Pinning',
Expand Down

0 comments on commit 41b38c6

Please sign in to comment.