繁体   English   中英

在 python 中,如何比较两个 CalVer 字符串以确定一个大于、小于或等于另一个?

[英]In python, how can you compare two CalVer strings to determine if one is greater than, lesser than, or equal to, the other?

我偶尔需要根据各种依赖的版本调整我的 python 脚本。 在我的情况下,最常见的情况是,python 代码库与可能运行多年版本的前端 javascript 一起工作。 如果 javascript 依赖项的版本大于 A,则 python 应该执行 B。如果依赖项的版本小于 X,则 python 应该执行 Y,等等。

这些依赖项是日历版本的 (CalVer)。 虽然我找到了许多用于维护项目自己的 CalVer 的工具,但我无法找到现成的解决方案来以这种方式评估 CalVers。

if "YY.MM.DD" > "YY.MM.DD.MICRO":
    # Do this thing
else:
    # Do that thing

比较日期很容易,但是当MICRO版本混合在一起时,事情变得更加复杂。

我最终编写了自己的解决方案,以允许我比较 CalVer 字符串,如下所示。

subject = "2021.01.31"
test = "2021.01.30.dev1"

if calver_evaluate(operator="gte", subject=subject, test=test):
   # if "2021.01.31" >= "2021.01.30.dev1"
   result = True

subject = "2021.01.31.0012"
test = "2021.01.31.1012"

if calver_evaluate(operator="gte", subject=subject, test=test):
   # if "2021.01.31.0012" >= "2021.01.30.1012"
   result = False

有关操作的完整详细信息包含在函数的文档字符串中。 请注意一些关于评估无法转换为整数的微的有限规则。

import datetime

def calver_evaluate(operator=None, subject=None, test=None):
    """Evaluates two calver strings based on the operator.

    Params
    ------
    operator : str
        Defines how to evaluate the subject and test params. Acceptable values are:
        - "gt" or ">" for greater than
        - "gte" or ">=" for greater than or equal to
        - "e", "eq", "equal", "=", or "==" for equal to
        - "lt" or "<" for less than
        - "lte" or "<=" for less than or equal to
    subject : str
        A calver string formatted as YYYY.0M.0D.MICRO (recommended) or YY.MM.DD.MICRO.
        https://calver.org/calendar_versioning.html
    test : str
        A calver string to evaluate against the subject, formatted as YYYY.0M.0D.MICRO 
        (recommended) or YY.MM.DD.MICRO.
        https://calver.org/calendar_versioning.html

    Returns
    -------
    bool
        The results of the `subject`:`test` evaluation using the `operator`.

    Notes
    -----
    The MICRO segment of the calver strings are only considered in the following
    scenarios.
        1. One calver has a MICRO value and the other does not. The calver without a 
        MICRO value is evaluated as `0`, making the calver *with* the MICRO, no matter
        what the value, as the greater of the two.
        `2021.01.01 == 2021.01.01.0`, therefore `2021.01.01.2 > 2021.01.01` and
        `2021.01.01.dev1 > 2021.01.01`
        2. Both calvers have MICRO values that are numeric and able to be converted to
        integers.
        3. Both calvers have string MICRO values **and** the operator selected is 
        "equals".

    """
    if not operator or not subject or not test:
        raise Exception("calver_evaluate: Missing keyword argument.")

    allowed = ["lt","<","lte","<=","e","eq","equal","=","==","gte",">=","gt",">"]
    if operator not in allowed:
        raise Exception("calver_evaluate: Unrecognized evaluation operator.")

    sparts = subject.split(".")
    syear = int(sparts[0]) if int(sparts[0]) > 100 else int(sparts[0]) + 2000
    smonth = int(sparts[1])
    sday = int(sparts[2])
    sdate = datetime.date(syear, smonth, sday)
    smicro = sparts[3] if len(sparts) > 3 else 0

    tparts = test.split(".")
    tyear = int(tparts[0]) if int(tparts[0]) > 100 else int(tparts[0]) + 2000
    tmonth = int(tparts[1])
    tday = int(tparts[2])
    tdate = datetime.date(tyear, tmonth, tday)
    tmicro = tparts[3] if len(tparts) > 3 else 0

    if unicode(smicro).isnumeric() and unicode(tmicro).isnumeric():
        smicro = int(smicro)
        tmicro = int(tmicro)
    elif smicro == 0:
        tmicro = 1
    elif tmicro == 0:
        smicro = 1

    lt = ["lt","<"]
    lte = ["lte","<="]
    equal = ["e","eq","equal","=","=="]
    gte = ["gte",">="]
    gt = ["gt",">"]

    check_micro = (
        (
            isinstance(smicro, int) and isinstance(tmicro, int) and
            (smicro > 0 or tmicro > 0)
        ) or
        (
            operator in equal and 
            not isinstance(smicro, int) and 
            not isinstance(tmicro, int)
        )
    )

    def evaluate_micro(operator, smicro, tmicro):
        if operator in lt:
            if smicro < tmicro:
                return True
        elif operator in lte:
            if smicro <= tmicro:
                return True
        elif operator in equal:
            if smicro == tmicro:
                return True
        elif operator in gte:
            if smicro >= tmicro:
                return True
        elif operator in gt:
            if smicro > tmicro:
                return True

        return False

    if operator in lt and sdate <= tdate:
        if sdate < tdate:
            return True
        elif sdate == tdate and check_micro:
            return evaluate_micro(operator, smicro, tmicro) 

    elif operator in lte and sdate <= tdate:
        if sdate == tdate and check_micro:
            return evaluate_micro(operator, smicro, tmicro) 
        return True

    elif operator in equal:
        if sdate == tdate:
            if check_micro:
                return evaluate_micro(operator, smicro, tmicro) 
            return True

    elif operator in gte and sdate >= tdate:
        if sdate == tdate and check_micro:
            return evaluate_micro(operator, smicro, tmicro) 
        return True

    elif operator in gt and sdate >= tdate:
        if sdate > tdate:
            return True
        elif sdate == tdate and check_micro:
            return evaluate_micro(operator, smicro, tmicro) 

    return False

Python 打包机构 ( PyPA ) 维护packaging库,其中包括根据PEP 440 (“版本标识和依赖规范”)实现版本处理,包括日历版本控制。

示例(取自丹尼斯的回答):

>>> from packaging import version
>>> version.parse('2021.01.31') >= version.parse('2021.01.30.dev1')
True
>>> version.parse('2021.01.31.0012') >= version.parse('2021.01.31.1012')
False

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM