查找语义版本是否是另一个版本的超集 python

find if a semantic version is superset of of another version python

我有一个用例,其中我有一个 Java maven 语义范围列表,试图找到我可以在我的应用程序中排除的版本列表。

示例:

SemVersion1 = "[,1.8.8.1)"
SemVersion2 = "[,1.8.8.2)"
SemVersion3 = "[,1.8.8.3)"
SemVersion4 = "[1.0.0, 1.4.4)"
SemVersion5 = "[,1.3.11),[,1.7.0), [,1.8.0)"

如何过滤各种 SemVersion 以仅保留包含所有其他版本的版本。在这种情况下,将选取 SemVersion3,因为它包含所有版本。

在python中考虑这样的事情:

        output = []
        for a in SemVersions:
            is_redundent = False
            for b in a:
              if affected_versions[a].issuperset(affected_versions[b]):
              is_redundent = True
              break
        if not is_redundent:
          output.append(b)

问题是我需要给 SemVersions 充气才能得到 affected_versions,有没有更简单的方法。

步骤:

  1. 将您的范围转换为更严格的表示法以消除 ',1.2.3.4' 和“1.0,2.3.4”(我们需要最后一步的精确下限)
  2. 将您的字符串转换为实际的 Version 对象以便于比较(您也可以转换为数字元组,但它们会在包含非数字字符的版本上中断)

from packaging.version import Version
from functools import cmp_to_key
from collections import defaultdict

def adj_lengths(s, c=3):
    """Add missing .0 to a version up to a predefined count '.'-count.
    Example:  '9.0.2' with c == 3 -> '9.0.2.0'"""

    cnt = s.count(".")
    if c>cnt:
        s = s + ".0"*(c-cnt)
    return s


def split_mult(s):
    """Make versions more precise by replacing implicit range starts.
    Uses adj_lengths to add missing .0 to equalize version lengths.
    Handles splitting multiple given ranges as well. 
    Returns iterable.
    Example: '[,1.3.11),[,1.7.0), [,1.8.0)' 
             -> (['0.0.0.0', '1.3.11.0'],['0.0.0.0', '1.7.0.0'], ['0.0.0.0', '1.8.0.0'])"""

    s = s.replace("[,",f"[0,")
    s1 = [ adj_lengths(b) for b in (t.strip("[()] ") for t in s.split(","))]

    yield from [ s1[i:i+2] for i in range(0,len(s1),2)]


def make_version(l):
    """Transform text-list into Version-tuple."""

    return ( Version(l[0]), Version(l[1]) )

计划:

vers = ["[,1.8.8.1)",   
        "[,1.8.8.2)",   
        "[,1.8.8.3)",  
        "[1.0.0, 1.4.4)", 
        "[,1.3.11),[,1.7.0), [,1.8.0)"]

# preprocessing to make them nicer
vers2 = []
for tmp in (split_mult(a) for a in vers) :
    vers2.extend( (make_version(k) for k in tmp) )
print(vers2)

# bring into order
vers2.sort()

# use the lower bound as key - append alle upper bounds to a defaultdict(list)  
d = defaultdict(list)
for fr,to in vers2:
    d[fr].append(to)

# simplify lower bound:[list of upper bounds] to (lower bound, max(upper bound list values))
vers3 = [ (k,max(v)) for k,v in d.items()]

# eliminate range that lie inside the 1st elements range
for item in vers3[1:][:]:
    if item[0] >= vers3[0][0] and item[1] <= vers3[0][1]:
        vers3.remove(item)

print(vers3)

输出:

[(<Version('0.0.0.0')>, <Version('1.8.8.3')>)]

如果结果范围不止一个,则必须对每个元素执行最后一步 - 而不仅仅是第一个,f.e。当您在最后一步中的数据如下:

[(<Version('0.0.0.0')>, <Version('1.8.8.3')>), 
 (<Version('1.0.0.0')>, <Version('2.8.8.3')>), 
 (<Version('1.2.0.0')>, <Version('1.8.8.3')>), ] # last elem inside before-last elem