Skip to content

Commit 28ff6be

Browse files
committed
wip
1 parent aa613f8 commit 28ff6be

File tree

1 file changed

+73
-19
lines changed

1 file changed

+73
-19
lines changed

python/private/py_wheel_normalize_pep440.bzl

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -540,23 +540,75 @@ def _upper(*, epoch = 0, release, pre = "", post = "", dev = "", local = ""):
540540
release = release,
541541
)
542542

543+
def _pad_zeros(release, n):
544+
if len(release) >= n:
545+
return release
546+
547+
release = list(release)
548+
release += [0] * len(release)
549+
return tuple(release)
550+
551+
# TODO @aignas 2025-05-04: add tests for the comparison
543552
def _version_eq(left, right):
544553
if left.epoch != right.epoch:
545554
return False
546555

547-
# Check at most 3 terms and check the same number of terms
548-
check_len = min(min(len(left.release), len(right.release)), 3)
556+
if left.is_prefix:
557+
right_release = right.release[:len(left.release)]
558+
else:
559+
right_release = _pad_zeros(right.release, len(left.release))
549560

550-
return left.release[:check_len] == right.release[:check_len]
561+
if right.is_prefix:
562+
left_release = left.release[:len(right.release)]
563+
else:
564+
left_release = _pad_zeros(left.release, len(right.release))
551565

566+
if left_release != right_release:
567+
return False
568+
569+
if left.is_prefix or right.is_prefix:
570+
return True
571+
572+
return (
573+
left.pre == right.pre and
574+
left.post == right.post and
575+
left.dev == right.dev and
576+
left.local == right.local
577+
)
578+
579+
# TODO @aignas 2025-05-04: add tests for the comparison
552580
def _version_lt(left, right):
581+
if left.epoch > right.epoch:
582+
return False
553583
if left.epoch < right.epoch:
554584
return True
555-
elif left.epoch > right.epoch:
585+
586+
if left.is_prefix:
587+
right_release = right.release[:len(left.release)]
588+
else:
589+
right_release = _pad_zeros(right.release, len(left.release))
590+
591+
if right.is_prefix:
592+
left_release = left.release[:len(right.release)]
593+
else:
594+
left_release = _pad_zeros(left.release, len(right.release))
595+
596+
if left_release > right_release:
556597
return False
598+
elif left_release < right_release:
599+
return True
600+
601+
if left.is_prefix or right.is_prefix:
602+
return True
557603

558-
return left.release < right.release
604+
return (
605+
left.pre < right.pre and
606+
left.post < right.post and
607+
left.dev < right.dev and
608+
left.local < right.local
609+
)
559610

611+
# TODO @aignas 2025-05-04: add tests for the comparison
560612
def _version_gt(left, right):
561613
if left.epoch > right.epoch:
562614
return True
@@ -565,7 +617,7 @@ def _version_gt(left, right):
565617

566618
return left.release > right.release
567619

568-
def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = ""):
620+
def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "", is_prefix = False):
569621
epoch = epoch or 0
570622
_release = tuple([int(d) for d in release.split(".")])
571623
pre = pre or ""
@@ -580,6 +632,7 @@ def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "
580632
post = post,
581633
dev = dev,
582634
local = local,
635+
is_prefix = is_prefix,
583636
upper = lambda: _upper(
584637
epoch = epoch,
585638
release = _release,
@@ -588,14 +641,7 @@ def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "
588641
dev = dev,
589642
local = local,
590643
),
591-
key = lambda: (
592-
epoch,
593-
_release,
594-
pre,
595-
post,
596-
dev,
597-
local,
598-
),
644+
# TODO @aignas 2025-05-04: add tests for the comparison
599645
eq = lambda x: _version_eq(self, x), # buildifier: disable=uninitialized
600646
ne = lambda x: not _version_eq(self, x), # buildifier: disable=uninitialized
601647
lt = lambda x: _version_lt(self, x), # buildifier: disable=uninitialized
@@ -607,7 +653,9 @@ def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "
607653
return self
608654

609655
def parse_version(version):
610-
"""Escape the version component of a filename.
656+
"""Parse a PEP4408 compliant version
657+
658+
TODO: finish
611659
612660
See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
613661
and https://peps.python.org/pep-0440/
@@ -619,9 +667,7 @@ def parse_version(version):
619667
string containing the normalized version.
620668
"""
621669

622-
# TODO @aignas 2025-05-04: this is discarding '.*', but per spec this should be only done
623-
# for public version segments
624-
parser = _new(version.strip(" .*")) # PEP 440: Leading and Trailing Whitespace
670+
parser = _new(version.strip(" .*")) # PEP 440: Leading and Trailing Whitespace and .*
625671
accept(parser, _is("v"), "") # PEP 440: Preceding v character
626672

627673
parts = {}
@@ -637,7 +683,15 @@ def parse_version(version):
637683
for p, fn in fns:
638684
fn(parser)
639685
parts[p] = parser.context()["norm"]
640-
parser.context()["norm"] = ""
686+
parser.context()["norm"] = "" # Clear out the buffer so that it is easy to separate the fields
687+
688+
is_prefix = version.endswith(".*")
689+
parts["is_prefix"] = is_prefix
690+
if is_prefix and (parts["local"] or parts["post"] or parts["dev"] or parts["pre"]):
691+
# local version part has been obtained, but only public segments can have prefix
692+
# matches. Just return None.
693+
# https://peps.python.org/pep-0440/#public-version-identifiers
694+
return None
641695

642696
if parser.input[parser.context()["start"]:]:
643697
# If we fail to parse the version return None

0 commit comments

Comments
 (0)