chore(lint): strip wheel/sdist size fields in the uv.lock normalizer (#3579)

pypi.org's simple index serves a size for every file while proxy
indexes may not, so each re-lock added or stripped 'size = N' across
~2,900 lines depending on which index resolved it. Make the sizeless
form canonical (the hash is the integrity check): the fixer now drops
size fields and --check flags them, so re-locks from either side
converge on one form.

Co-authored-by: Isaac

Signed-off-by: Dhruv Gupta <dhruv.gupta@databricks.com>
This commit is contained in:
Dhruv Gupta
2026-07-30 10:48:01 -07:00
committed by GitHub
parent 240634a947
commit 6b3ff8af35
2 changed files with 84 additions and 24 deletions
+30 -16
View File
@@ -1,4 +1,4 @@
"""Normalize the package index in ``uv.lock`` to the public PyPI URL.
"""Normalize ``uv.lock`` to the public PyPI index and canonical file metadata.
Local ``uv`` runs resolve against whatever index is configured on the
developer's machine (e.g. the Databricks PyPI proxy via ``UV_INDEX_URL``
@@ -9,14 +9,20 @@ PyPI (``https://pypi.org/simple``) so the lock is reproducible for
contributors who don't have the proxy — CI already pins
``UV_INDEX_URL: https://pypi.org/simple`` for the same reason.
This is a pre-commit *fixer*: it rewrites the registry URL in place and
The index also leaks through file metadata: pypi.org serves a size for
every wheel/sdist while proxy indexes may not, so each re-lock adds or
strips ``size = N`` across thousands of lines depending on which index
resolved it. The canonical form omits ``size`` (the hash is the
integrity check), so re-locks from either side stop ping-ponging.
This is a pre-commit *fixer*: it rewrites the lockfile in place and
exits non-zero when it changed anything, so the commit aborts and the
developer re-stages the normalized lockfile (mirroring
``end-of-file-fixer`` and friends). Only ``registry`` sources are
touched; ``git`` / ``path`` / ``editable`` sources are left alone.
Pass ``--check`` to validate without writing: it exits non-zero (and
names the offending URLs) when a file is *not* already canonical, but
names the offending entries) when a file is *not* already canonical, but
leaves it untouched. CI runs this mode against the committed lockfile
*before* any ``uv`` command — a plain ``uv run pre-commit`` can't catch a
committed proxy URL, because ``uv`` re-syncs the working tree to CI's
@@ -53,12 +59,18 @@ _DIRECT_URL_RE = re.compile(
r'(url = ")(https?://(?!files\.pythonhosted\.org)[^"]+?/packages/)([^"]*")'
)
# Matches the optional file-size field after a wheel/sdist hash, e.g.
# hash = "sha256:...", size = 116543, upload-time = "..."
# pypi.org's index serves sizes, proxy indexes may not; canonical form omits them.
_SIZE_RE = re.compile(r'(hash = "[^"]+"), size = \d+')
def non_canonical_registries(text: str) -> list[str]:
"""Return the registry URLs and direct-URL hosts in *text* that are not canonical.
def non_canonical_entries(text: str) -> list[str]:
"""Return the non-canonical registry URLs, direct-URL hosts, and size fields in *text*.
:param text: Full contents of a ``uv.lock`` file.
:returns: Each non-canonical URL, in order, with duplicates preserved.
:returns: Each non-canonical URL, in order, with duplicates preserved,
plus one summary entry when ``size`` fields are present.
"""
bad: list[str] = [
m.group(1)
@@ -66,19 +78,21 @@ def non_canonical_registries(text: str) -> list[str]:
if m.group(1) != _CANONICAL_INDEX
]
bad += [m.group(2) for m in _DIRECT_URL_RE.finditer(text)]
sizes = len(_SIZE_RE.findall(text))
if sizes:
bad.append(f"size field on {sizes} file entr{'y' if sizes == 1 else 'ies'}")
return bad
def normalize_text(text: str) -> str:
"""Return *text* with every registry and direct wheel/sdist URL rewritten to canonical hosts.
"""Return *text* with URLs rewritten to canonical hosts and ``size`` fields dropped.
:param text: Full contents of a ``uv.lock`` file.
:returns: The normalized text.
"""
return _DIRECT_URL_RE.sub(
rf"\g<1>{_CANONICAL_FILES_HOST}/packages/\g<3>",
_REGISTRY_RE.sub(rf"\g<1>{_CANONICAL_INDEX}\g<2>", text),
)
text = _REGISTRY_RE.sub(rf"\g<1>{_CANONICAL_INDEX}\g<2>", text)
text = _DIRECT_URL_RE.sub(rf"\g<1>{_CANONICAL_FILES_HOST}/packages/\g<3>", text)
return _SIZE_RE.sub(r"\1", text)
def main(argv: list[str]) -> int:
@@ -89,7 +103,7 @@ def main(argv: list[str]) -> int:
:returns: In fix mode, ``1`` when a file was modified (so the commit
aborts and the change is re-staged) else ``0``. In ``--check``
mode, ``1`` when any file is not already canonical (printing the
offending URLs) else ``0``; no file is written.
offenders) else ``0``; no file is written.
"""
check = "--check" in argv
files = [a for a in argv if a != "--check"]
@@ -97,13 +111,13 @@ def main(argv: list[str]) -> int:
if check:
ok = True
for name in files:
offenders = non_canonical_registries(Path(name).read_text())
offenders = non_canonical_entries(Path(name).read_text())
if offenders:
ok = False
unique = sorted(set(offenders))
print(
f"{name}: {len(offenders)} non-canonical registry "
f"source(s) (expected {_CANONICAL_INDEX}): {', '.join(unique)}"
f"{name}: {len(offenders)} non-canonical entry(s) "
f"(expected {_CANONICAL_INDEX}, no size fields): {', '.join(unique)}"
)
print(
"Fix with: python scripts/normalize_uv_lock_registry.py "
@@ -118,7 +132,7 @@ def main(argv: list[str]) -> int:
normalized = normalize_text(original)
if normalized != original:
path.write_text(normalized)
print(f"{name}: normalized package index to {_CANONICAL_INDEX}")
print(f"{name}: normalized to canonical form ({_CANONICAL_INDEX}, no size fields)")
changed = True
return 1 if changed else 0
+54 -8
View File
@@ -2,10 +2,13 @@
The pre-commit fixer rewrites every ``source = { registry = "<url>" }``
in ``uv.lock`` to public PyPI so a developer's local index/proxy never
leaks into the committed lockfile. These tests pin that contract:
arbitrary registry URLs are normalized, non-registry sources are left
alone, the fixer is idempotent, and ``main`` signals modifications via
its exit code (1 = changed → commit aborts and re-stages; 0 = clean).
leaks into the committed lockfile, and strips wheel/sdist ``size``
fields (served by pypi.org but not by proxy indexes) so re-locks from
either side agree on one canonical form. These tests pin that contract:
arbitrary registry URLs are normalized, size fields are dropped,
non-registry sources are left alone, the fixer is idempotent, and
``main`` signals modifications via its exit code (1 = changed → commit
aborts and re-stages; 0 = clean).
"""
from __future__ import annotations
@@ -126,7 +129,7 @@ def test_main_handles_multiple_files(tmp_path: Path) -> None:
assert b.read_text() == canonical
def test_non_canonical_registries_lists_offenders() -> None:
def test_non_canonical_entries_lists_offenders() -> None:
"""The check helper reports each non-canonical registry URL, in order."""
proxy = "https://pypi-proxy.cloud.databricks.com/simple"
text = (
@@ -134,13 +137,13 @@ def test_non_canonical_registries_lists_offenders() -> None:
f'source = {{ registry = "{_CANONICAL}" }}\n'
f'source = {{ registry = "{proxy}" }}\n'
)
assert _MOD.non_canonical_registries(text) == [proxy, proxy]
assert _MOD.non_canonical_entries(text) == [proxy, proxy]
def test_non_canonical_registries_empty_when_canonical() -> None:
def test_non_canonical_entries_empty_when_canonical() -> None:
"""A fully-canonical lockfile reports no offenders."""
text = f'source = {{ registry = "{_CANONICAL}" }}\n'
assert _MOD.non_canonical_registries(text) == []
assert _MOD.non_canonical_entries(text) == []
def test_main_check_fails_without_writing(tmp_path: Path) -> None:
@@ -166,3 +169,46 @@ def test_main_check_flag_position_independent(tmp_path: Path) -> None:
lock = tmp_path / "uv.lock"
lock.write_text(f'source = {{ registry = "{_CANONICAL}" }}\n')
assert _MOD.main([str(lock), "--check"]) == 0
# A registry file entry as uv writes it when the index serves sizes (pypi.org).
_SIZED_ENTRY = (
'sdist = { url = "https://files.pythonhosted.org/packages/ab/cd/pkg.tar.gz", '
'hash = "sha256:aaaa", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" }\n'
)
def test_normalize_text_strips_size_fields() -> None:
"""``size`` metadata is dropped; url, hash, and upload-time survive."""
result = _MOD.normalize_text(_SIZED_ENTRY)
assert "size = " not in result
assert 'hash = "sha256:aaaa", upload-time = "2026-01-28T10:17:05.322Z"' in result
def test_normalize_text_strips_size_field_without_upload_time() -> None:
"""A trailing ``size`` with no ``upload-time`` after it is also stripped."""
url = "https://files.pythonhosted.org/packages/ab/cd/p.whl"
text = f' {{ url = "{url}", hash = "sha256:bb", size = 7 }},\n'
assert _MOD.normalize_text(text) == f' {{ url = "{url}", hash = "sha256:bb" }},\n'
def test_non_canonical_entries_flags_size_fields() -> None:
"""Size fields are reported as one summary offender so ``--check`` fails."""
assert _MOD.non_canonical_entries(_SIZED_ENTRY * 2) == ["size field on 2 file entries"]
def test_main_check_fails_on_size_fields(tmp_path: Path) -> None:
"""``--check`` returns 1 for a lockfile carrying size metadata, without writing."""
lock = tmp_path / "uv.lock"
lock.write_text(_SIZED_ENTRY)
assert _MOD.main(["--check", str(lock)]) == 1
assert lock.read_text() == _SIZED_ENTRY
def test_main_strips_size_fields_and_returns_one(tmp_path: Path) -> None:
"""Fix mode strips sizes in place, returns 1, and is idempotent after."""
lock = tmp_path / "uv.lock"
lock.write_text(_SIZED_ENTRY)
assert _MOD.main([str(lock)]) == 1
assert "size = " not in lock.read_text()
assert _MOD.main([str(lock)]) == 0