Use latest Pyodide version for each python version (#17372)

## Summary

This changes how the `download-metadata.json` file is generated for
Pyodide.

Previously, if we have a different Pyodide version with a same Python
version, the older Pyodide version is selected.

For example, say we have

- Pyodide 0.29.0 with Python 3.13.2
- Pyodide 0.28.3 with Python 3.13.2

then, pyodide 0.28.3 was stored in `download-metadata.json` as we
iterate in decending order with overwriting the value that was
previously written.

I fixed it by picking up the latest Pyodide version for each Python
version.

## Test Plan

Ran `uv run -- crates/uv-python/fetch-download-metadata.py` locally, and
verified the output:

```
2026-01-09 15:39:23 INFO Fetching Pyodide checksums: 0/4
2026-01-09 15:39:24 INFO Selected cpython-3.13.2-emscripten-wasm32-musl (0.29.1)
2026-01-09 15:39:24 INFO Selected cpython-3.12.7-emscripten-wasm32-musl (0.27.7)
2026-01-09 15:39:24 INFO Selected cpython-3.12.1-emscripten-wasm32-musl (0.26.4)
2026-01-09 15:39:24 INFO Selected cpython-3.11.3-emscripten-wasm32-musl (0.25.1)
```
This commit is contained in:
Gyeongjae Choi
2026-01-13 08:59:26 +09:00
committed by GitHub
parent f1e5667d2f
commit 7b497d48bd

View File

@@ -597,41 +597,41 @@ class PyodideFinder(Finder):
releases = release_resp.json()
metadata = meta_resp.json()["releases"]
maj_minor_seen = set()
results = []
results = {}
for release in releases:
pyodide_version = release["tag_name"]
meta = metadata.get(pyodide_version, None)
if meta is None:
continue
maj_min = pyodide_version.rpartition(".")[0]
# Only keep latest
if maj_min in maj_minor_seen:
continue
maj_minor_seen.add(maj_min)
python_version = Version.from_str(meta["python_version"])
# Find xbuildenv asset
for asset in release["assets"]:
if asset["name"].startswith("xbuildenv"):
break
else:
# not found: should not happen but just in case
continue
url = asset["browser_download_url"]
results.append(
PythonDownload(
release=0,
version=python_version,
triple=self.TRIPLE,
flavor=pyodide_version,
implementation=self.implementation,
filename=asset["name"],
url=url,
build=pyodide_version,
)
download = PythonDownload(
release=0,
version=python_version,
triple=self.TRIPLE,
flavor=pyodide_version,
implementation=self.implementation,
filename=asset["name"],
url=url,
build=pyodide_version,
)
return results
# Only keep latest Pyodide version of each Python version
# arch/platform are all the same for Pyodide (wasm32, emscripten)
if python_version not in results:
results[python_version] = download
return list(results.values())
async def _fetch_checksums(self, downloads: list[PythonDownload], n: int) -> None:
for idx, batch in enumerate(batched(downloads, n)):