I ended up writing my own solution to allow me to compare CalVer strings like below.
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
Full details on the operations are included the function's docstring. Note some of the limited rules around evaluating micros that cannot be converted to integers.
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