From 4029dbdd5573c944a125ec3b7ad7db7986e01663 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Wed, 25 Jun 2025 16:28:25 -0700 Subject: [PATCH 1/3] add test --- tests/version/version_test.bzl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/version/version_test.bzl b/tests/version/version_test.bzl index 589f9ac05d..aa1a209fa4 100644 --- a/tests/version/version_test.bzl +++ b/tests/version/version_test.bzl @@ -105,6 +105,14 @@ def _test_normalization(env): _tests.append(_test_normalization) +def _test_normalize_local(env): + # Verify a local with a [digit][non-digit] sequence parses ok + in_str = "0.1.0+brt.9e" + actual = version.normalize(in_str) + env.expect.that_str(actual).equals("xxx") + +_tests.append(_test_normalize_local) + def _test_ordering(env): want = [ # Taken from https://peps.python.org/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering From ba2d225f8fd6f2ea6f07995d6e5830cbb4af0737 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 6 Jul 2025 20:11:56 -0700 Subject: [PATCH 2/3] fix parsing --- python/private/version.bzl | 49 ++++++++++++++++++++++++++++++---- tests/version/version_test.bzl | 2 +- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/python/private/version.bzl b/python/private/version.bzl index f98165d391..99261e46ad 100644 --- a/python/private/version.bzl +++ b/python/private/version.bzl @@ -44,7 +44,13 @@ def _in(reference): return lambda token: token in reference def _ctx(start): - return {"norm": "", "start": start} + """Creates a context, which is state for parsing (or sub-parsing).""" + return { + # The result value from parsing + "norm": "", + # Where in the parser's input string this context starts. + "start": start, + } def _open_context(self): """Open an new parsing ctx. @@ -60,7 +66,16 @@ def _open_context(self): return self.contexts[-1] def _accept(self, key = None): - """Close the current ctx successfully and merge the results.""" + """Close the current ctx successfully and merge the results. + + Args: + self: {type}`Parser} + key: {type}`str | None` the key to store the result in + the most recent context. If not set, the key is "norm". + + Returns: + {type}`bool` always True + """ finished = self.contexts.pop() self.contexts[-1]["norm"] += finished["norm"] if key: @@ -79,7 +94,14 @@ def _discard(self, key = None): return False def _new(input): - """Create a new normalizer""" + """Create a new parser + + Args: + input: {type}`str` input to parse + + Returns: + {type}`Parser` a struct for a parser object. + """ self = struct( input = input, contexts = [_ctx(0)], @@ -167,7 +189,7 @@ def accept_placeholder(parser): return parser.accept() def accept_digits(parser): - """Accept multiple digits (or placeholders). + """Accept multiple digits (or placeholders), up to a non-digit/placeholder. Args: parser: The normalizer. @@ -275,7 +297,24 @@ def accept_separator_alnum(parser): Returns: whether a separator and an alphanumeric string were accepted. """ - parser.open_context() + + # Input is "0.1.0+brt.9e" + ctx = parser.open_context() + + if not accept(parser, _in([".", "-", "_"]), "."): + return parser.discard() + + if accept_alnum(parser): + # First character is separator; skip it. + value = ctx["norm"][1:] + + # PEP 440: Integer Normalization + if value.isdigit(): + value = str(int(value)) + ctx["norm"] = ctx["norm"][0] + value + return parser.accept() + + return parser.discard() # PEP 440: Local version segments if ( diff --git a/tests/version/version_test.bzl b/tests/version/version_test.bzl index aa1a209fa4..7ddb6cc851 100644 --- a/tests/version/version_test.bzl +++ b/tests/version/version_test.bzl @@ -109,7 +109,7 @@ def _test_normalize_local(env): # Verify a local with a [digit][non-digit] sequence parses ok in_str = "0.1.0+brt.9e" actual = version.normalize(in_str) - env.expect.that_str(actual).equals("xxx") + env.expect.that_str(actual).equals(in_str) _tests.append(_test_normalize_local) From a5be4c76dfaaf1471f1d4f5430e07d049de586b6 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Sun, 6 Jul 2025 20:23:52 -0700 Subject: [PATCH 3/3] format/lint --- python/private/version.bzl | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/python/private/version.bzl b/python/private/version.bzl index 99261e46ad..8b5fef7b2a 100644 --- a/python/private/version.bzl +++ b/python/private/version.bzl @@ -297,10 +297,9 @@ def accept_separator_alnum(parser): Returns: whether a separator and an alphanumeric string were accepted. """ - - # Input is "0.1.0+brt.9e" ctx = parser.open_context() + # PEP 440: Local version segments if not accept(parser, _in([".", "-", "_"]), "."): return parser.discard() @@ -316,15 +315,6 @@ def accept_separator_alnum(parser): return parser.discard() - # PEP 440: Local version segments - if ( - accept(parser, _in([".", "-", "_"]), ".") and - (accept_digits(parser) or accept_alnum(parser)) - ): - return parser.accept() - - return parser.discard() - def accept_separator_alnum_sequence(parser): """Accept a sequence of separator+alphanumeric.