簡體   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