From 83b5151f228b15a9e2f9ea9bb42ad0b7065013ae Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Tue, 15 Sep 2026 19:57:08 +0200 Subject: [PATCH] lib.version.Version.next(): Step the last part Range expansion needs a bound that steps the last existing part of a version, add that. next() increments the last part, whatever it is: next of '1' is '2', of '1.0' is '1.1', of '1.2.3' is '1.2.4', of '1.2.3-45' is '1.2.3-46'. Tests written by AI. Signed-off-by: Jan Lindemann Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1 --- src/python/jw/pkg/lib/version/Version.py | 25 +++++++++++++++++++++ test/unit/python/jw/pkg/lib/version/test.py | 23 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/python/jw/pkg/lib/version/Version.py b/src/python/jw/pkg/lib/version/Version.py index 8f81f666..aee96cc3 100644 --- a/src/python/jw/pkg/lib/version/Version.py +++ b/src/python/jw/pkg/lib/version/Version.py @@ -220,3 +220,28 @@ class Version: # export f'{self.major}.{self.minor + 1}.0', self.__lookup_version, ) + + @property + def next(self) -> Version: + """The next version in the series: the last part + incremented. next of '1' is '2', of '1.0' is '1.1', of + '1.2.3' is '1.2.4', of '1.2.3-45' is '1.2.3-46'. The + separators of the spec are kept. Like in + next_binary_compatible(), only the last part's leading + digits count: a suffixed part such as '4blah' steps to + '5'. A part without leading digits raises Version.Error. + """ + untemplated = self.__id(untemplate = True, throw = True) + parts = re.split('([.-])', untemplated) + m = re.match('[0-9]+', parts[-1]) + if not m: + raise Version.Error( + f'Cannot step version "{self.__spec}": the last ' + f'part "{parts[-1]}" has no leading digits' + ) + parts[-1] = str(int(m.group()) + 1) + return Version( + self.__name, + ''.join(parts), + self.__lookup_version, + ) diff --git a/test/unit/python/jw/pkg/lib/version/test.py b/test/unit/python/jw/pkg/lib/version/test.py index 2c87c198..b3525225 100644 --- a/test/unit/python/jw/pkg/lib/version/test.py +++ b/test/unit/python/jw/pkg/lib/version/test.py @@ -193,6 +193,29 @@ for spec in ['1.2.3-rc1', '1.2.3']: except Version.Error: pass +# next steps the last existing part, whatever it is +for spec, expected in [ + ('1', '2'), + ('1.0', '1.1'), + ('1.2.3', '1.2.4'), + ('1.2.3-45', '1.2.3-46'), + ('1.2.3-4blah', '1.2.3-5'), + ('1.2.3.4', '1.2.3.5'), + ('1.2.3rc1', '1.2.4'), + ('VERSION', '1.2.4'), +]: + v = Version('foo', spec, app.get_version) + assert str(v.next) == expected, spec + +# A last part without leading digits cannot be stepped +for spec in ['1.0-rc1', '1.2.alpha']: + v = Version('foo', spec) + try: + v.next + assert False, f'Should have raised for {spec!r}' + except Version.Error: + pass + # constructor d = Dependency('foo-devel = 1.0') assert d.base_name == 'foo'