mirror of
https://github.com/TECHNOFAB11/bumpver.git
synced 2025-12-12 22:40:09 +01:00
add v2 parsing
This commit is contained in:
parent
d4bd8a5931
commit
5940fdbc40
3 changed files with 435 additions and 322 deletions
|
|
@ -3,30 +3,33 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2018-2020 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
|
# Copyright (c) 2018-2020 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
# """Compose Regular Expressions from Patterns.
|
"""Compose Regular Expressions from Patterns.
|
||||||
|
|
||||||
# >>> pattern = compile_pattern("vYYYY0M.BUILD[-TAG]")
|
>>> pattern = compile_pattern("vYYYY0M.BUILD[-TAG]")
|
||||||
# >>> version_info = pattern.regexp.match("v201712.0123-alpha")
|
>>> version_info = pattern.regexp.match("v201712.0123-alpha")
|
||||||
# >>> assert version_info == {
|
>>> assert version_info.groupdict() == {
|
||||||
# ... "version": "v201712.0123-alpha",
|
... "version": "v201712.0123-alpha",
|
||||||
# ... "YYYY" : "2017",
|
... "year_y" : "2017",
|
||||||
# ... "0M" : "12",
|
... "month" : "12",
|
||||||
# ... "BUILD" : "0123",
|
... "bid" : "0123",
|
||||||
# ... "TAG" : "alpha",
|
... "tag" : "alpha",
|
||||||
# ... }
|
... }
|
||||||
# >>>
|
>>>
|
||||||
# >>> version_info = pattern.regexp.match("201712.1234")
|
>>> version_info = pattern.regexp.match("201712.1234")
|
||||||
# >>> assert version_info is None
|
>>> assert version_info is None
|
||||||
|
|
||||||
# >>> version_info = pattern.regexp.match("v201712.1234")
|
>>> version_info = pattern.regexp.match("v201713.1234")
|
||||||
# >>> assert version_info == {
|
>>> assert version_info is None
|
||||||
# ... "version": "v201712.0123-alpha",
|
|
||||||
# ... "YYYY" : "2017",
|
>>> version_info = pattern.regexp.match("v201712.1234")
|
||||||
# ... "0M" : "12",
|
>>> assert version_info.groupdict() == {
|
||||||
# ... "BUILD" : "0123",
|
... "version": "v201712.1234",
|
||||||
# ... "TAG" : None,
|
... "year_y" : "2017",
|
||||||
# ... }
|
... "month" : "12",
|
||||||
# """
|
... "bid" : "1234",
|
||||||
|
... "tag" : None,
|
||||||
|
... }
|
||||||
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import typing as typ
|
import typing as typ
|
||||||
|
|
@ -42,43 +45,52 @@ PATTERN_ESCAPES = [
|
||||||
("?" , "\u005c?"),
|
("?" , "\u005c?"),
|
||||||
("{" , "\u005c{"),
|
("{" , "\u005c{"),
|
||||||
("}" , "\u005c}"),
|
("}" , "\u005c}"),
|
||||||
("[" , "\u005c["),
|
# ("[" , "\u005c["), # [braces] are used for optional parts
|
||||||
("]" , "\u005c]"),
|
# ("]" , "\u005c]"),
|
||||||
("(" , "\u005c("),
|
("(", "\u005c("),
|
||||||
(")" , "\u005c)"),
|
(")", "\u005c)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# NOTE (mb 2020-09-17): For patterns with different options, the longer
|
||||||
|
# patterns should be first/left (e.g. for 'MM', `1[0-2]` before `[1-9]`).
|
||||||
|
# This ensures that the longest match is done rather than the shortest.
|
||||||
|
# To have a consistent ordering, we always put the pattern that matches
|
||||||
|
# the larger number first (even if the patterns would otherwise be the
|
||||||
|
# same size).
|
||||||
|
|
||||||
PART_PATTERNS = {
|
PART_PATTERNS = {
|
||||||
# Based on calver.org
|
# Based on calver.org
|
||||||
'YYYY': r"[1-9][0-9]{3}",
|
'YYYY': r"[1-9][0-9]{3}",
|
||||||
'YY' : r"[1-9][0-9]?",
|
'YY' : r"[1-9][0-9]?",
|
||||||
'0Y' : r"[0-9]{2}",
|
'0Y' : r"[0-9]{2}",
|
||||||
'Q' : r"[1-4]",
|
|
||||||
'MM' : r"(?:[1-9]|1[0-2])",
|
|
||||||
'0M' : r"(?:0[1-9]|1[0-2])",
|
|
||||||
'DD' : r"(?:[1-9]|[1-2][0-9]|3[0-1])",
|
|
||||||
'0D' : r"(?:0[1-9]|[1-2][0-9]|3[0-1])",
|
|
||||||
'JJJ' : r"(?:[1-9]|[1-9][0-9]|[1-2][0-9][0-9]|3[0-5][0-9]|36[0-6])",
|
|
||||||
'00J' : r"(?:00[1-9]|0[1-9][0-9]|[1-2][0-9][0-9]|3[0-5][0-9]|36[0-6])",
|
|
||||||
# week numbering parts
|
|
||||||
'WW' : r"(?:[0-9]|[1-4][0-9]|5[0-2])",
|
|
||||||
'0W' : r"(?:[0-4][0-9]|5[0-2])",
|
|
||||||
'UU' : r"(?:[0-9]|[1-4][0-9]|5[0-2])",
|
|
||||||
'0U' : r"(?:[0-4][0-9]|5[0-2])",
|
|
||||||
'VV' : r"(?:[1-9]|[1-4][0-9]|5[0-3])",
|
|
||||||
'0V' : r"(?:0[1-9]|[1-4][0-9]|5[0-3])",
|
|
||||||
'GGGG': r"[1-9][0-9]{3}",
|
'GGGG': r"[1-9][0-9]{3}",
|
||||||
'GG' : r"[1-9][0-9]?",
|
'GG' : r"[1-9][0-9]?",
|
||||||
'0G' : r"[0-9]{2}",
|
'0G' : r"[0-9]{2}",
|
||||||
|
'Q' : r"[1-4]",
|
||||||
|
'MM' : r"(?:1[0-2]|[1-9])",
|
||||||
|
'0M' : r"(?:1[0-2]|0[1-9])",
|
||||||
|
'DD' : r"(?:3[0-1]|[1-2][0-9]|[1-9])",
|
||||||
|
'0D' : r"(?:3[0-1]|[1-2][0-9]|0[1-9])",
|
||||||
|
'JJJ' : r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|[1-9][0-9]|[1-9])",
|
||||||
|
'00J' : r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|0[1-9][0-9]|00[1-9])",
|
||||||
|
# week numbering parts
|
||||||
|
'WW': r"(?:5[0-2]|[1-4][0-9]|[0-9])",
|
||||||
|
'0W': r"(?:5[0-2]|[0-4][0-9])",
|
||||||
|
'UU': r"(?:5[0-2]|[1-4][0-9]|[0-9])",
|
||||||
|
'0U': r"(?:5[0-2]|[0-4][0-9])",
|
||||||
|
'VV': r"(?:5[0-3]|[1-4][0-9]|[1-9])",
|
||||||
|
'0V': r"(?:5[0-3]|[1-4][0-9]|0[1-9])",
|
||||||
# non calver parts
|
# non calver parts
|
||||||
'MAJOR': r"[0-9]+",
|
'MAJOR': r"[0-9]+",
|
||||||
'MINOR': r"[0-9]+",
|
'MINOR': r"[0-9]+",
|
||||||
'PATCH': r"[0-9]+",
|
'PATCH': r"[0-9]+",
|
||||||
'MICRO': r"[0-9]+",
|
'MICRO': r"[0-9]+",
|
||||||
'BUILD': r"[0-9]+",
|
'BUILD': r"[0-9]+",
|
||||||
'TAG' : r"(?:alpha|beta|dev|rc|post|final)",
|
'TAG' : r"(?:alpha|beta|dev|pre|rc|post|final)",
|
||||||
'PYTAG': r"(?:a|b|dev|rc|post)?[0-9]*",
|
'PYTAG': r"(?:a|b|dev|rc|post)",
|
||||||
|
'NUM' : r"[0-9]+",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PATTERN_PART_FIELDS = {
|
PATTERN_PART_FIELDS = {
|
||||||
'YYYY' : 'year_y',
|
'YYYY' : 'year_y',
|
||||||
|
|
@ -109,17 +121,118 @@ PATTERN_PART_FIELDS = {
|
||||||
'VV' : 'week_v',
|
'VV' : 'week_v',
|
||||||
'0V' : 'week_v',
|
'0V' : 'week_v',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FieldValue = typ.Union[str, int]
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_num(val: FieldValue) -> str:
|
||||||
|
return str(val)
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_yy(year_y: FieldValue) -> str:
|
||||||
|
return str(int(str(year_y)[-2:]))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0y(year_y: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(str(year_y)[-2:]))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_gg(year_g: FieldValue) -> str:
|
||||||
|
return str(int(str(year_g)[-2:]))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0g(year_g: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(str(year_g)[-2:]))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0m(month: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(month))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0d(dom: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(dom))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_00j(doy: FieldValue) -> str:
|
||||||
|
return "{0:03}".format(int(doy))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0w(week_w: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(week_w))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0u(week_u: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(week_u))
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_0v(week_v: FieldValue) -> str:
|
||||||
|
return "{0:02}".format(int(week_v))
|
||||||
|
|
||||||
|
|
||||||
|
PART_FORMATS: typ.Dict[str, typ.Callable[[FieldValue], str]] = {
|
||||||
|
'YYYY' : _fmt_num,
|
||||||
|
'YY' : _fmt_yy,
|
||||||
|
'0Y' : _fmt_0y,
|
||||||
|
'GGGG' : _fmt_num,
|
||||||
|
'GG' : _fmt_gg,
|
||||||
|
'0G' : _fmt_0g,
|
||||||
|
'Q' : _fmt_num,
|
||||||
|
'MM' : _fmt_num,
|
||||||
|
'0M' : _fmt_0m,
|
||||||
|
'DD' : _fmt_num,
|
||||||
|
'0D' : _fmt_0d,
|
||||||
|
'JJJ' : _fmt_num,
|
||||||
|
'00J' : _fmt_00j,
|
||||||
|
'MAJOR': _fmt_num,
|
||||||
|
'MINOR': _fmt_num,
|
||||||
|
'PATCH': _fmt_num,
|
||||||
|
'MICRO': _fmt_num,
|
||||||
|
'BUILD': _fmt_num,
|
||||||
|
'TAG' : _fmt_num,
|
||||||
|
'PYTAG': _fmt_num,
|
||||||
|
'NUM' : _fmt_num,
|
||||||
|
'WW' : _fmt_num,
|
||||||
|
'0W' : _fmt_0w,
|
||||||
|
'UU' : _fmt_num,
|
||||||
|
'0U' : _fmt_0u,
|
||||||
|
'VV' : _fmt_num,
|
||||||
|
'0V' : _fmt_0v,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _replace_pattern_parts(pattern: str) -> str:
|
def _replace_pattern_parts(pattern: str) -> str:
|
||||||
# The pattern is escaped, so that everything besides the format
|
# The pattern is escaped, so that everything besides the format
|
||||||
# string variables is treated literally.
|
# string variables is treated literally.
|
||||||
|
if "[" in pattern and "]" in pattern:
|
||||||
|
pattern = pattern.replace("[", "(?:")
|
||||||
|
pattern = pattern.replace("]", ")?")
|
||||||
|
|
||||||
|
part_patterns_by_index: typ.Dict[typ.Tuple[int, int], typ.Tuple[int, int, str]] = {}
|
||||||
for part_name, part_pattern in PART_PATTERNS.items():
|
for part_name, part_pattern in PART_PATTERNS.items():
|
||||||
named_part_pattern = f"(?P<{part_name}>{part_pattern})"
|
start_idx = pattern.find(part_name)
|
||||||
placeholder = "\u005c{" + part_name + "\u005c}"
|
if start_idx < 0:
|
||||||
pattern = pattern.replace(placeholder, named_part_pattern)
|
continue
|
||||||
return pattern
|
|
||||||
|
field = PATTERN_PART_FIELDS[part_name]
|
||||||
|
named_part_pattern = f"(?P<{field}>{part_pattern})"
|
||||||
|
end_idx = start_idx + len(part_name)
|
||||||
|
sort_key = (-end_idx, -len(part_name))
|
||||||
|
part_patterns_by_index[sort_key] = (start_idx, end_idx, named_part_pattern)
|
||||||
|
|
||||||
|
# NOTE (mb 2020-09-17): The sorting is done so that we process items:
|
||||||
|
# - right before left
|
||||||
|
# - longer before shorter
|
||||||
|
last_start_idx = len(pattern) + 1
|
||||||
|
result_pattern = pattern
|
||||||
|
for _, (start_idx, end_idx, named_part_pattern) in sorted(part_patterns_by_index.items()):
|
||||||
|
if end_idx <= last_start_idx:
|
||||||
|
result_pattern = (
|
||||||
|
result_pattern[:start_idx] + named_part_pattern + result_pattern[end_idx:]
|
||||||
|
)
|
||||||
|
last_start_idx = start_idx
|
||||||
|
|
||||||
|
return "(?P<version>" + result_pattern + ")"
|
||||||
|
|
||||||
|
|
||||||
def compile_pattern_str(pattern: str) -> str:
|
def compile_pattern_str(pattern: str) -> str:
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,11 @@ import datetime as dt
|
||||||
import lexid
|
import lexid
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
# import pycalver.patterns as v1patterns
|
|
||||||
import pycalver2.patterns as v2patterns
|
import pycalver2.patterns as v2patterns
|
||||||
|
|
||||||
|
# import pycalver.version as v1version
|
||||||
|
# import pycalver.patterns as v1patterns
|
||||||
|
|
||||||
logger = logging.getLogger("pycalver.version")
|
logger = logging.getLogger("pycalver.version")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,11 +36,44 @@ ZERO_VALUES = {
|
||||||
'major': "0",
|
'major': "0",
|
||||||
'minor': "0",
|
'minor': "0",
|
||||||
'patch': "0",
|
'patch': "0",
|
||||||
'TAG' : "final",
|
'tag' : "final",
|
||||||
'PYTAG': "",
|
'pytag': "",
|
||||||
|
'num' : "0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TAG_BY_PEP440_TAG = {
|
||||||
|
'a' : 'alpha',
|
||||||
|
'b' : 'beta',
|
||||||
|
"" : 'final',
|
||||||
|
'rc' : 'rc',
|
||||||
|
'dev' : 'dev',
|
||||||
|
'post': 'post',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PEP440_TAG_BY_TAG = {
|
||||||
|
'alpha': "a",
|
||||||
|
'beta' : "b",
|
||||||
|
'final': "",
|
||||||
|
'pre' : "rc",
|
||||||
|
'rc' : "rc",
|
||||||
|
'dev' : "dev",
|
||||||
|
'post' : "post",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert set(TAG_BY_PEP440_TAG.keys()) == set(PEP440_TAG_BY_TAG.values())
|
||||||
|
assert set(TAG_BY_PEP440_TAG.values()) < set(PEP440_TAG_BY_TAG.keys())
|
||||||
|
|
||||||
|
# PEP440_TAGS_REVERSE = {
|
||||||
|
# "a" : 'alpha',
|
||||||
|
# "b" : 'beta',
|
||||||
|
# "rc" : 'rc',
|
||||||
|
# "dev" : 'dev',
|
||||||
|
# "post": 'post',
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
class CalendarInfo(typ.NamedTuple):
|
class CalendarInfo(typ.NamedTuple):
|
||||||
"""Container for calendar components of version strings."""
|
"""Container for calendar components of version strings."""
|
||||||
|
|
||||||
|
|
@ -79,27 +114,26 @@ def _quarter_from_month(month: int) -> int:
|
||||||
|
|
||||||
|
|
||||||
def cal_info(date: dt.date = None) -> CalendarInfo:
|
def cal_info(date: dt.date = None) -> CalendarInfo:
|
||||||
# TODO reenable doctest
|
"""Generate calendar components for current date.
|
||||||
# """Generate calendar components for current date.
|
|
||||||
|
|
||||||
# >>> from datetime import date
|
>>> import datetime as dt
|
||||||
|
|
||||||
# >>> c = cal_info(date(2019, 1, 5))
|
>>> c = cal_info(dt.date(2019, 1, 5))
|
||||||
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
|
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.week_w, c.week_u, c.week_v)
|
||||||
# (2019, 1, 1, 5, 5, 0, 0)
|
(2019, 1, 1, 5, 5, 0, 0, 1)
|
||||||
|
|
||||||
# >>> c = cal_info(date(2019, 1, 6))
|
>>> c = cal_info(dt.date(2019, 1, 6))
|
||||||
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
|
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.week_w, c.week_u, c.week_v)
|
||||||
# (2019, 1, 1, 6, 6, 0, 1)
|
(2019, 1, 1, 6, 6, 0, 1, 1)
|
||||||
|
|
||||||
# >>> c = cal_info(date(2019, 1, 7))
|
>>> c = cal_info(dt.date(2019, 1, 7))
|
||||||
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
|
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.week_w, c.week_u, c.week_v)
|
||||||
# (2019, 1, 1, 7, 7, 1, 1)
|
(2019, 1, 1, 7, 7, 1, 1, 2)
|
||||||
|
|
||||||
# >>> c = cal_info(date(2019, 4, 7))
|
>>> c = cal_info(dt.date(2019, 4, 7))
|
||||||
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
|
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.week_w, c.week_u, c.week_v)
|
||||||
# (2019, 2, 4, 7, 97, 13, 14)
|
(2019, 2, 4, 7, 97, 13, 14, 14)
|
||||||
# """
|
"""
|
||||||
if date is None:
|
if date is None:
|
||||||
date = TODAY
|
date = TODAY
|
||||||
|
|
||||||
|
|
@ -118,59 +152,105 @@ def cal_info(date: dt.date = None) -> CalendarInfo:
|
||||||
return CalendarInfo(**kwargs)
|
return CalendarInfo(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
MaybeInt = typ.Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class VersionInfo(typ.NamedTuple):
|
class VersionInfo(typ.NamedTuple):
|
||||||
"""Container for parsed version string."""
|
"""Container for parsed version string."""
|
||||||
|
|
||||||
year_y : typ.Optional[int]
|
year_y : MaybeInt
|
||||||
year_g : typ.Optional[int]
|
year_g : MaybeInt
|
||||||
quarter: typ.Optional[int]
|
quarter: MaybeInt
|
||||||
month : typ.Optional[int]
|
month : MaybeInt
|
||||||
dom : typ.Optional[int]
|
dom : MaybeInt
|
||||||
doy : typ.Optional[int]
|
doy : MaybeInt
|
||||||
week_w : typ.Optional[int]
|
week_w : MaybeInt
|
||||||
week_u : typ.Optional[int]
|
week_u : MaybeInt
|
||||||
week_v : typ.Optional[int]
|
week_v : MaybeInt
|
||||||
major : int
|
major : int
|
||||||
minor : int
|
minor : int
|
||||||
patch : int
|
patch : int
|
||||||
bid : str
|
bid : str
|
||||||
tag : str
|
tag : str
|
||||||
pytag : str
|
pytag : str
|
||||||
|
num : MaybeInt
|
||||||
|
|
||||||
|
|
||||||
|
VALID_FIELD_KEYS = set(VersionInfo._fields) | {'version'}
|
||||||
|
|
||||||
FieldKey = str
|
FieldKey = str
|
||||||
MatchGroupKey = str
|
MatchGroupKey = str
|
||||||
MatchGroupStr = str
|
MatchGroupStr = str
|
||||||
|
|
||||||
PatternGroups = typ.Dict[MatchGroupKey, MatchGroupStr]
|
PatternGroups = typ.Dict[FieldKey, MatchGroupStr]
|
||||||
FieldValues = typ.Dict[FieldKey , MatchGroupStr]
|
FieldValues = typ.Dict[FieldKey, MatchGroupStr]
|
||||||
|
|
||||||
|
|
||||||
def _parse_field_values(field_values: FieldValues) -> VersionInfo:
|
def _parse_version_info(field_values: FieldValues) -> VersionInfo:
|
||||||
|
"""Parse normalized VersionInfo from groups of a matched pattern.
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2018", 'month': "11", 'bid': "0099"})
|
||||||
|
>>> (vnfo.year_y, vnfo.month, vnfo.quarter, vnfo.bid, vnfo.tag)
|
||||||
|
(2018, 11, 4, '0099', 'final')
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2018", 'doy': "11", 'bid': "099", 'tag': "beta"})
|
||||||
|
>>> (vnfo.year_y, vnfo.month, vnfo.dom, vnfo.doy, vnfo.bid, vnfo.tag)
|
||||||
|
(2018, 1, 11, 11, '099', 'beta')
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2018", 'month': "6", 'dom': "15"})
|
||||||
|
>>> (vnfo.year_y, vnfo.month, vnfo.dom, vnfo.doy)
|
||||||
|
(2018, 6, 15, 166)
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'major': "1", 'minor': "23", 'patch': "45"})
|
||||||
|
>>> (vnfo.major, vnfo.minor, vnfo.patch)
|
||||||
|
(1, 23, 45)
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'major': "1", 'minor': "023", 'patch': "0045"})
|
||||||
|
>>> (vnfo.major, vnfo.minor, vnfo.patch)
|
||||||
|
(1, 23, 45)
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2021", 'week_w': "02"})
|
||||||
|
>>> (vnfo.year_y, vnfo.week_w)
|
||||||
|
(2021, 2)
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2021", 'week_u': "02"})
|
||||||
|
>>> (vnfo.year_y, vnfo.week_u)
|
||||||
|
(2021, 2)
|
||||||
|
>>> vnfo = _parse_version_info({'year_g': "2021", 'week_v': "02"})
|
||||||
|
>>> (vnfo.year_g, vnfo.week_v)
|
||||||
|
(2021, 2)
|
||||||
|
|
||||||
|
>>> vnfo = _parse_version_info({'year_y': "2021", 'month': "01", 'dom': "03"})
|
||||||
|
>>> (vnfo.year_y, vnfo.month, vnfo.dom, vnfo.tag)
|
||||||
|
(2021, 1, 3, 'final')
|
||||||
|
>>> (vnfo.year_y, vnfo.week_w,vnfo.year_y, vnfo.week_u,vnfo.year_g, vnfo.week_v)
|
||||||
|
(2021, 0, 2021, 1, 2020, 53)
|
||||||
|
"""
|
||||||
|
for key in field_values:
|
||||||
|
assert key in VALID_FIELD_KEYS, key
|
||||||
|
|
||||||
fvals = field_values
|
fvals = field_values
|
||||||
tag = fvals.get('tag')
|
tag = fvals.get('tag' , "final")
|
||||||
if tag is None:
|
pytag = fvals.get('pytag', "")
|
||||||
tag = "final"
|
|
||||||
|
|
||||||
tag = TAG_ALIASES.get(tag, tag)
|
if tag and not pytag:
|
||||||
assert tag is not None
|
pytag = PEP440_TAG_BY_TAG[tag]
|
||||||
# TODO (mb 2020-09-06): parts of course
|
elif pytag and not tag:
|
||||||
pytag = "TODO"
|
tag = TAG_BY_PEP440_TAG[pytag]
|
||||||
|
|
||||||
bid = fvals['bid'] if 'bid' in fvals else "1001"
|
num: MaybeInt = int(fvals['num']) if 'num' in fvals else None
|
||||||
|
|
||||||
year_y = int(fvals['year_y']) if 'year_y' in fvals else None
|
|
||||||
year_g = int(fvals['year_g']) if 'year_g' in fvals else None
|
|
||||||
doy = int(fvals['doy' ]) if 'doy' in fvals else None
|
|
||||||
|
|
||||||
date: typ.Optional[dt.date] = None
|
date: typ.Optional[dt.date] = None
|
||||||
|
|
||||||
month: typ.Optional[int] = None
|
year_y: MaybeInt = int(fvals['year_y']) if 'year_y' in fvals else None
|
||||||
dom : typ.Optional[int] = None
|
year_g: MaybeInt = int(fvals['year_g']) if 'year_g' in fvals else None
|
||||||
|
|
||||||
week_w: typ.Optional[int] = None
|
month: MaybeInt = int(fvals['month']) if 'month' in fvals else None
|
||||||
week_u: typ.Optional[int] = None
|
doy : MaybeInt = int(fvals['doy' ]) if 'doy' in fvals else None
|
||||||
week_v: typ.Optional[int] = None
|
dom : MaybeInt = int(fvals['dom' ]) if 'dom' in fvals else None
|
||||||
|
|
||||||
|
week_w: MaybeInt = int(fvals['week_w']) if 'week_w' in fvals else None
|
||||||
|
week_u: MaybeInt = int(fvals['week_u']) if 'week_u' in fvals else None
|
||||||
|
week_v: MaybeInt = int(fvals['week_v']) if 'week_v' in fvals else None
|
||||||
|
|
||||||
if year_y and doy:
|
if year_y and doy:
|
||||||
date = _date_from_doy(year_y, doy)
|
date = _date_from_doy(year_y, doy)
|
||||||
|
|
@ -180,26 +260,31 @@ def _parse_field_values(field_values: FieldValues) -> VersionInfo:
|
||||||
month = int(fvals['month']) if 'month' in fvals else None
|
month = int(fvals['month']) if 'month' in fvals else None
|
||||||
dom = int(fvals['dom' ]) if 'dom' in fvals else None
|
dom = int(fvals['dom' ]) if 'dom' in fvals else None
|
||||||
|
|
||||||
quarter = int(fvals['quarter']) if 'quarter' in fvals else None
|
|
||||||
if quarter is None and month:
|
|
||||||
quarter = _quarter_from_month(month)
|
|
||||||
|
|
||||||
if year_y and month and dom:
|
if year_y and month and dom:
|
||||||
date = dt.date(year_y, month, dom)
|
date = dt.date(year_y, month, dom)
|
||||||
|
|
||||||
if date:
|
if date:
|
||||||
# derive all fields from other previous values
|
# derive all fields from other previous values
|
||||||
|
year_y = int(date.strftime("%Y"), base=10)
|
||||||
|
year_g = int(date.strftime("%G"), base=10)
|
||||||
|
month = int(date.strftime("%m"), base=10)
|
||||||
|
dom = int(date.strftime("%d"), base=10)
|
||||||
doy = int(date.strftime("%j"), base=10)
|
doy = int(date.strftime("%j"), base=10)
|
||||||
week_w = int(date.strftime("%W"), base=10)
|
week_w = int(date.strftime("%W"), base=10)
|
||||||
week_u = int(date.strftime("%U"), base=10)
|
week_u = int(date.strftime("%U"), base=10)
|
||||||
week_v = int(date.strftime("%V"), base=10)
|
week_v = int(date.strftime("%V"), base=10)
|
||||||
year_g = int(date.strftime("%G"), base=10)
|
|
||||||
|
quarter = int(fvals['quarter']) if 'quarter' in fvals else None
|
||||||
|
if quarter is None and month:
|
||||||
|
quarter = _quarter_from_month(month)
|
||||||
|
|
||||||
major = int(fvals['major']) if 'major' in fvals else 0
|
major = int(fvals['major']) if 'major' in fvals else 0
|
||||||
minor = int(fvals['minor']) if 'minor' in fvals else 0
|
minor = int(fvals['minor']) if 'minor' in fvals else 0
|
||||||
patch = int(fvals['patch']) if 'patch' in fvals else 0
|
patch = int(fvals['patch']) if 'patch' in fvals else 0
|
||||||
|
|
||||||
return VersionInfo(
|
bid = fvals['bid'] if 'bid' in fvals else "1000"
|
||||||
|
|
||||||
|
vnfo = VersionInfo(
|
||||||
year_y=year_y,
|
year_y=year_y,
|
||||||
year_g=year_g,
|
year_g=year_g,
|
||||||
quarter=quarter,
|
quarter=quarter,
|
||||||
|
|
@ -215,47 +300,9 @@ def _parse_field_values(field_values: FieldValues) -> VersionInfo:
|
||||||
bid=bid,
|
bid=bid,
|
||||||
tag=tag,
|
tag=tag,
|
||||||
pytag=pytag,
|
pytag=pytag,
|
||||||
|
num=num,
|
||||||
)
|
)
|
||||||
|
return vnfo
|
||||||
|
|
||||||
def _is_calver(nfo: typ.Union[CalendarInfo, VersionInfo]) -> bool:
|
|
||||||
# TODO reenable doctest
|
|
||||||
# """Check pattern for any calendar based parts.
|
|
||||||
|
|
||||||
# >>> _is_calver(cal_info())
|
|
||||||
# True
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'year': "2018", 'month': "11", 'bid': "0018"})
|
|
||||||
# >>> _is_calver(vnfo)
|
|
||||||
# True
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'MAJOR': "1", 'MINOR': "023", 'PATCH': "45"})
|
|
||||||
# >>> _is_calver(vnfo)
|
|
||||||
# False
|
|
||||||
# """
|
|
||||||
for field in CalendarInfo._fields:
|
|
||||||
maybe_val: typ.Any = getattr(nfo, field, None)
|
|
||||||
if isinstance(maybe_val, int):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
TAG_ALIASES: typ.Dict[str, str] = {
|
|
||||||
'a' : "alpha",
|
|
||||||
'b' : "beta",
|
|
||||||
'pre': "rc",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PEP440_TAGS: typ.Dict[str, str] = {
|
|
||||||
'alpha': "a",
|
|
||||||
'beta' : "b",
|
|
||||||
'final': "",
|
|
||||||
'rc' : "rc",
|
|
||||||
'dev' : "dev",
|
|
||||||
'post' : "post",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VersionInfoKW = typ.Dict[str, typ.Union[str, int, None]]
|
VersionInfoKW = typ.Dict[str, typ.Union[str, int, None]]
|
||||||
|
|
@ -265,65 +312,17 @@ class PatternError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _parse_pattern_groups(pattern_groups: PatternGroups) -> FieldValues:
|
|
||||||
for part_name in pattern_groups.keys():
|
|
||||||
is_valid_part_name = (
|
|
||||||
part_name in v2patterns.COMPOSITE_PART_PATTERNS or part_name in PATTERN_PART_FIELDS
|
|
||||||
)
|
|
||||||
if not is_valid_part_name:
|
|
||||||
err_msg = f"Invalid part '{part_name}'"
|
|
||||||
raise PatternError(err_msg)
|
|
||||||
|
|
||||||
field_value_items = [
|
|
||||||
(field_name, pattern_groups[part_name])
|
|
||||||
for part_name, field_name in PATTERN_PART_FIELDS.items()
|
|
||||||
if part_name in pattern_groups.keys()
|
|
||||||
]
|
|
||||||
|
|
||||||
all_fields = [field_name for field_name, _ in field_value_items]
|
|
||||||
unique_fields = set(all_fields)
|
|
||||||
duplicate_fields = [f for f in unique_fields if all_fields.count(f) > 1]
|
|
||||||
|
|
||||||
if any(duplicate_fields):
|
|
||||||
err_msg = f"Multiple parts for same field {duplicate_fields}."
|
|
||||||
raise PatternError(err_msg)
|
|
||||||
|
|
||||||
return dict(field_value_items)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_version_info(pattern_groups: PatternGroups) -> VersionInfo:
|
|
||||||
# TODO reenable doctest
|
|
||||||
# """Parse normalized VersionInfo from groups of a matched pattern.
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'year': "2018", 'month': "11", 'bid': "0099"})
|
|
||||||
# >>> (vnfo.year_y, vnfo.month, vnfo.quarter, vnfo.bid, vnfo.tag)
|
|
||||||
# (2018, 11, 4, '0099', 'final')
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'year': "2018", 'doy': "11", 'bid': "099", 'tag': "b"})
|
|
||||||
# >>> (vnfo.year_y, vnfo.month, vnfo.dom, vnfo.bid, vnfo.tag)
|
|
||||||
# (2018, 1, 11, '099', 'beta')
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'MAJOR': "1", 'MINOR': "23", 'PATCH': "45"})
|
|
||||||
# >>> (vnfo.major, vnfo.minor, vnfo.patch)
|
|
||||||
# (1, 23, 45)
|
|
||||||
|
|
||||||
# >>> vnfo = _parse_version_info({'MAJOR': "1", 'MMM': "023", 'PPPP': "0045"})
|
|
||||||
# >>> (vnfo.major, vnfo.minor, vnfo.patch)
|
|
||||||
# (1, 23, 45)
|
|
||||||
# """
|
|
||||||
field_values = _parse_pattern_groups(pattern_groups)
|
|
||||||
return _parse_field_values(field_values)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_version_info(version_str: str, pattern: str = "vYYYY0M.BUILD[-TAG]") -> VersionInfo:
|
def parse_version_info(version_str: str, pattern: str = "vYYYY0M.BUILD[-TAG]") -> VersionInfo:
|
||||||
# """Parse normalized VersionInfo.
|
"""Parse normalized VersionInfo.
|
||||||
|
|
||||||
# >>> vnfo = parse_version_info("v201712.0033-beta", pattern="vYYYY0M.BUILD[-TAG]")
|
>>> vnfo = parse_version_info("v201712.0033-beta", pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
# >>> assert vnfo == _parse_version_info({'year': 2017, 'month': 12, 'bid': "0033", 'tag': "beta"})
|
>>> fvals = {'year_y': 2017, 'month': 12, 'bid': "0033", 'tag': "beta"}
|
||||||
|
>>> assert vnfo == _parse_version_info(fvals)
|
||||||
|
|
||||||
# >>> vnfo = parse_version_info("1.23.456", pattern="MAJOR.MINOR.PATCH")
|
>>> vnfo = parse_version_info("1.23.456", pattern="MAJOR.MINOR.PATCH")
|
||||||
# >>> assert vnfo == _parse_version_info({'MAJOR': "1", 'MINOR': "23", 'PATCH': "456"})
|
>>> fvals = {'major': "1", 'minor': "23", 'patch': "456"}
|
||||||
# """
|
>>> assert vnfo == _parse_version_info(fvals)
|
||||||
|
"""
|
||||||
pattern_tup = v2patterns.compile_pattern(pattern)
|
pattern_tup = v2patterns.compile_pattern(pattern)
|
||||||
match = pattern_tup.regexp.match(version_str)
|
match = pattern_tup.regexp.match(version_str)
|
||||||
if match is None:
|
if match is None:
|
||||||
|
|
@ -332,23 +331,23 @@ def parse_version_info(version_str: str, pattern: str = "vYYYY0M.BUILD[-TAG]") -
|
||||||
f"for pattern '{pattern}'/'{pattern_tup.regexp.pattern}'"
|
f"for pattern '{pattern}'/'{pattern_tup.regexp.pattern}'"
|
||||||
)
|
)
|
||||||
raise PatternError(err_msg)
|
raise PatternError(err_msg)
|
||||||
|
else:
|
||||||
return _parse_version_info(match.groupdict())
|
field_values = match.groupdict()
|
||||||
|
return _parse_version_info(field_values)
|
||||||
|
|
||||||
|
|
||||||
def is_valid(version_str: str, pattern: str = "{pycalver}") -> bool:
|
def is_valid(version_str: str, pattern: str = "vYYYY0M.BUILD[-TAG]") -> bool:
|
||||||
# TODO reenable doctest
|
"""Check if a version matches a pattern.
|
||||||
# """Check if a version matches a pattern.
|
|
||||||
|
|
||||||
# >>> is_valid("v201712.0033-beta", pattern="{pycalver}")
|
>>> is_valid("v201712.0033-beta", pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
# True
|
True
|
||||||
# >>> is_valid("v201712.0033-beta", pattern="{semver}")
|
>>> is_valid("v201712.0033-beta", pattern="MAJOR.MINOR.PATCH")
|
||||||
# False
|
False
|
||||||
# >>> is_valid("1.2.3", pattern="{semver}")
|
>>> is_valid("1.2.3", pattern="MAJOR.MINOR.PATCH")
|
||||||
# True
|
True
|
||||||
# >>> is_valid("v201712.0033-beta", pattern="{semver}")
|
>>> is_valid("v201712.0033-beta", pattern="MAJOR.MINOR.PATCH")
|
||||||
# False
|
False
|
||||||
# """
|
"""
|
||||||
try:
|
try:
|
||||||
parse_version_info(version_str, pattern)
|
parse_version_info(version_str, pattern)
|
||||||
return True
|
return True
|
||||||
|
|
@ -359,140 +358,106 @@ def is_valid(version_str: str, pattern: str = "{pycalver}") -> bool:
|
||||||
TemplateKwargs = typ.Dict[str, typ.Union[str, int, None]]
|
TemplateKwargs = typ.Dict[str, typ.Union[str, int, None]]
|
||||||
|
|
||||||
|
|
||||||
def _derive_template_kwargs(vinfo: VersionInfo) -> TemplateKwargs:
|
def _format_part_values(vinfo: VersionInfo) -> typ.Dict[str, str]:
|
||||||
"""Generate kwargs for template from minimal VersionInfo.
|
"""Generate kwargs for template from minimal VersionInfo.
|
||||||
|
|
||||||
The VersionInfo Tuple only has the minimal representation
|
The VersionInfo Tuple only has the minimal representation
|
||||||
of a parsed version, not the values suitable for formatting.
|
of a parsed version, not the values suitable for formatting.
|
||||||
It may for example have month=9, but not the formatted
|
It may for example have month=9, but not the formatted
|
||||||
representation '09' for '0M'.
|
representation '09' for '0M'.
|
||||||
|
|
||||||
|
>>> vinfo = parse_version_info("v200709.1033-beta", pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
|
>>> kwargs = _format_part_values(vinfo)
|
||||||
|
>>> (kwargs['YYYY'], kwargs['0M'], kwargs['BUILD'], kwargs['TAG'])
|
||||||
|
('2007', '09', '1033', 'beta')
|
||||||
|
>>> (kwargs['YY'], kwargs['0Y'], kwargs['MM'], kwargs['PYTAG'])
|
||||||
|
('7', '07', '9', 'b')
|
||||||
"""
|
"""
|
||||||
kwargs: TemplateKwargs = vinfo._asdict()
|
vnfo_kwargs: TemplateKwargs = vinfo._asdict()
|
||||||
|
kwargs : typ.Dict[str, str] = {}
|
||||||
|
|
||||||
tag = vinfo.tag
|
for part, field in v2patterns.PATTERN_PART_FIELDS.items():
|
||||||
kwargs['TAG'] = tag
|
field_val = vnfo_kwargs[field]
|
||||||
if tag == 'final':
|
if field_val is None:
|
||||||
kwargs['PYTAG'] = ""
|
continue
|
||||||
else:
|
|
||||||
kwargs['PYTAG'] = PEP440_TAGS[tag] + "0"
|
|
||||||
|
|
||||||
year_y = vinfo.year_y
|
format_fn = v2patterns.PART_FORMATS[part]
|
||||||
if year_y:
|
kwargs[part] = format_fn(field_val)
|
||||||
kwargs['0Y' ] = str(year_y)[-2:]
|
|
||||||
kwargs['YY' ] = int(str(year_y)[-2:])
|
|
||||||
kwargs['YYYY'] = year_y
|
|
||||||
|
|
||||||
year_g = vinfo.year_g
|
|
||||||
if year_g:
|
|
||||||
kwargs['0G' ] = str(year_g)[-2:]
|
|
||||||
kwargs['GG' ] = int(str(year_g)[-2:])
|
|
||||||
kwargs['GGGG'] = year_g
|
|
||||||
|
|
||||||
kwargs['BUILD'] = int(vinfo.bid, 10)
|
|
||||||
|
|
||||||
for part_name, field in ID_FIELDS_BY_PART.items():
|
|
||||||
val = kwargs[field]
|
|
||||||
if part_name.lower() == field.lower():
|
|
||||||
if isinstance(val, str):
|
|
||||||
kwargs[part_name] = int(val, base=10)
|
|
||||||
else:
|
|
||||||
kwargs[part_name] = val
|
|
||||||
else:
|
|
||||||
assert len(set(part_name)) == 1
|
|
||||||
padded_len = len(part_name)
|
|
||||||
kwargs[part_name] = str(val).zfill(padded_len)
|
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
def _compile_format_template(pattern: str, kwargs: TemplateKwargs) -> str:
|
|
||||||
# NOTE (mb 2020-09-04): Some parts are optional, we need the kwargs to
|
|
||||||
# determine if part is set to its zero value
|
|
||||||
format_tmpl = pattern
|
|
||||||
for part_name, full_part_format in v2patterns.FULL_PART_FORMATS.items():
|
|
||||||
format_tmpl = format_tmpl.replace("{" + part_name + "}", full_part_format)
|
|
||||||
return format_tmpl
|
|
||||||
|
|
||||||
|
|
||||||
def format_version(vinfo: VersionInfo, pattern: str) -> str:
|
def format_version(vinfo: VersionInfo, pattern: str) -> str:
|
||||||
# TODO reenable doctest
|
"""Generate version string.
|
||||||
# """Generate version string.
|
|
||||||
|
|
||||||
# >>> import datetime as dt
|
>>> import datetime as dt
|
||||||
# >>> vinfo = parse_version_info("v201712.0033-beta", pattern="{pycalver}")
|
>>> vinfo = parse_version_info("v200712.0033-beta", pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
# >>> vinfo_a = vinfo._replace(**cal_info(date=dt.date(2017, 1, 1))._asdict())
|
>>> vinfo_a = vinfo._replace(**cal_info(date=dt.date(2007, 1, 1))._asdict())
|
||||||
# >>> vinfo_b = vinfo._replace(**cal_info(date=dt.date(2017, 12, 31))._asdict())
|
>>> vinfo_b = vinfo._replace(**cal_info(date=dt.date(2007, 12, 31))._asdict())
|
||||||
|
|
||||||
# >>> format_version(vinfo_a, pattern="v{yy}.{BID}{release}")
|
>>> format_version(vinfo_a, pattern="vYY.BUILD[-TAG]")
|
||||||
# 'v17.33-beta'
|
'v7.33-beta'
|
||||||
# >>> format_version(vinfo_a, pattern="vYY.BUILD[-TAG]")
|
>>> format_version(vinfo_a, pattern="v0Y.BUILD[-TAG]")
|
||||||
# 'v17.33-beta'
|
'v07.33-beta'
|
||||||
# >>> format_version(vinfo_a, pattern="YYYY0M.BUILD[PYTAG]")
|
>>> format_version(vinfo_a, pattern="YYYY0M.BUILD[PYTAG][NUM]")
|
||||||
# '201701.33b0'
|
'201701.33b0'
|
||||||
|
|
||||||
# >>> format_version(vinfo_a, pattern="{pycalver}")
|
>>> format_version(vinfo_a, pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
# 'v201701.0033-beta'
|
'v201701.0033-beta'
|
||||||
# >>> format_version(vinfo_b, pattern="{pycalver}")
|
>>> format_version(vinfo_b, pattern="vYYYY0M.BUILD[-TAG]")
|
||||||
# 'v201712.0033-beta'
|
'v201712.0033-beta'
|
||||||
|
|
||||||
# >>> format_version(vinfo_a, pattern="v{year}w{iso_week}.{BID}{release}")
|
>>> format_version(vinfo_a, pattern="vYYYYwWW.BUILD[-TAG]")
|
||||||
# 'v2017w00.33-beta'
|
'v2017w00.33-beta'
|
||||||
# >>> format_version(vinfo_a, pattern="vYYYYwWW.BUILD[-TAG]")
|
>>> format_version(vinfo_b, pattern="vYYYYwWW.BUILD[-TAG]")
|
||||||
# 'v2017w00.33-beta'
|
'v2017w52.33-beta'
|
||||||
# >>> format_version(vinfo_b, pattern="v{year}w{iso_week}.{BID}{release}")
|
|
||||||
# 'v2017w52.33-beta'
|
|
||||||
# >>> format_version(vinfo_b, pattern="vYYYYwWW.BUILD[-TAG]")
|
|
||||||
# 'v2017w52.33-beta'
|
|
||||||
|
|
||||||
# >>> format_version(vinfo_a, pattern="v{year}d{doy}.{bid}{release}")
|
>>> format_version(vinfo_a, pattern="vYYYYdJJJ.BUILD[-TAG]")
|
||||||
# 'v2017d001.0033-beta'
|
'v2017d001.0033-beta'
|
||||||
# >>> format_version(vinfo_b, pattern="v{year}d{doy}.{bid}{release}")
|
>>> format_version(vinfo_b, pattern="vYYYYdJJJ.BUILD[-TAG]")
|
||||||
# 'v2017d365.0033-beta'
|
'v2017d365.0033-beta'
|
||||||
# >>> format_version(vinfo_a, pattern="vYYYYdJJJ.BUILD[-TAG]")
|
|
||||||
# 'v2017d001.0033-beta'
|
|
||||||
# >>> format_version(vinfo_b, pattern="vYYYYdJJJ.BUILD[-TAG]")
|
|
||||||
# 'v2017d365.0033-beta'
|
|
||||||
|
|
||||||
# >>> format_version(vinfo_a, pattern="vGGGGwVV.BUILD[-TAG]")
|
>>> format_version(vinfo_a, pattern="vGGGGwVV.BUILD[-TAG]")
|
||||||
# 'v2016w52.0033-beta'
|
'v2016w52.0033-beta'
|
||||||
|
|
||||||
# >>> vinfo_c = vinfo_b._replace(major=1, minor=2, patch=34, tag='final')
|
>>> vinfo_c = vinfo_b._replace(major=1, minor=2, patch=34, tag='final')
|
||||||
|
|
||||||
# >>> format_version(vinfo_c, pattern="v{year}w{iso_week}.{BID}-{tag}")
|
>>> format_version(vinfo_c, pattern="vYYYYwWW.BUILD-TAG")
|
||||||
# 'v2017w52.33-final'
|
'v2017w52.33-final'
|
||||||
# >>> format_version(vinfo_c, pattern="v{year}w{iso_week}.{BID}{release}")
|
>>> format_version(vinfo_c, pattern="vYYYYwWW.BUILD[-TAG]")
|
||||||
# 'v2017w52.33'
|
'v2017w52.33'
|
||||||
# >>> format_version(vinfo_c, pattern="vYYYYwWW.BUILD-TAG")
|
|
||||||
# 'v2017w52.33-final'
|
|
||||||
# >>> format_version(vinfo_c, pattern="vYYYYwWW.BUILD[-TAG]")
|
|
||||||
# 'v2017w52.33'
|
|
||||||
|
|
||||||
# >>> format_version(vinfo_c, pattern="v{MAJOR}.{MINOR}.{PATCH}")
|
>>> format_version(vinfo_c, pattern="vMAJOR.MINOR.PATCH")
|
||||||
# 'v1.2.34'
|
'v1.2.34'
|
||||||
# >>> format_version(vinfo_c, pattern="vMAJOR.MINOR.PATCH")
|
|
||||||
# 'v1.2.34'
|
|
||||||
|
|
||||||
# >>> vinfo_d = vinfo_b._replace(major=1, minor=0, patch=0, tag='final')
|
>>> vinfo_d = vinfo_b._replace(major=1, minor=0, patch=0, tag='final')
|
||||||
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAG")
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAGNUM")
|
||||||
# 'v1.0.0-final'
|
'v1.0.0-final0'
|
||||||
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH[-TAG]")
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAG[NUM]")
|
||||||
# 'v1.0.0'
|
'v1.0.0-final'
|
||||||
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.PATCH[-TAG]]")
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAG")
|
||||||
# 'v1.0'
|
'v1.0.0-final'
|
||||||
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.MICRO[-TAG]]")
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH[-TAG]")
|
||||||
# 'v1.0'
|
'v1.0.0'
|
||||||
# >>> format_version(vinfo_d, pattern="vMAJOR[.MINOR[.PATCH[-TAG]]]")
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.PATCH[-TAG]]")
|
||||||
# 'v1'
|
'v1.0'
|
||||||
# """
|
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.MICRO[-TAG]]")
|
||||||
kwargs = _derive_template_kwargs(vinfo)
|
'v1.0'
|
||||||
format_tmpl = _compile_format_template(pattern, kwargs)
|
>>> format_version(vinfo_d, pattern="vMAJOR[.MINOR[.PATCH[-TAG]]]")
|
||||||
|
'v1'
|
||||||
|
"""
|
||||||
|
kwargs = _format_part_values(vinfo)
|
||||||
|
part_values = sorted(kwargs.items(), key=lambda item: -len(item[0]))
|
||||||
|
version = pattern
|
||||||
|
for part, value in part_values:
|
||||||
|
version = version.replace(part, value)
|
||||||
|
|
||||||
return format_tmpl.format(**kwargs)
|
return version
|
||||||
|
|
||||||
|
|
||||||
def incr(
|
def incr(
|
||||||
old_version: str,
|
old_version: str,
|
||||||
pattern : str = "{pycalver}",
|
pattern : str = "vYYYY0M.BUILD[-TAG]",
|
||||||
*,
|
*,
|
||||||
release: str = None,
|
release: str = None,
|
||||||
major : bool = False,
|
major : bool = False,
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,25 @@ V2_PART_PATTERN_CASES = [
|
||||||
(['0V'], "53", "53"),
|
(['0V'], "53", "53"),
|
||||||
(['0V'], "54", None),
|
(['0V'], "54", None),
|
||||||
(['MAJOR', 'MINOR', 'PATCH', 'MICRO'], "0", "0"),
|
(['MAJOR', 'MINOR', 'PATCH', 'MICRO'], "0", "0"),
|
||||||
# ('TAG', ""),
|
(['TAG' ], "alpha" , "alpha"),
|
||||||
# ('PYTAG', ""),
|
(['TAG' ], "alfa" , None),
|
||||||
|
(['TAG' ], "beta" , "beta"),
|
||||||
|
(['TAG' ], "dev" , "dev"),
|
||||||
|
(['TAG' ], "rc" , "rc"),
|
||||||
|
(['TAG' ], "post" , "post"),
|
||||||
|
(['TAG' ], "final" , "final"),
|
||||||
|
(['TAG' ], "latest", None),
|
||||||
|
(['PYTAG'], "a" , "a"),
|
||||||
|
(['PYTAG'], "b" , "b"),
|
||||||
|
(['PYTAG'], "dev" , "dev"),
|
||||||
|
(['PYTAG'], "rc" , "rc"),
|
||||||
|
(['PYTAG'], "post" , "post"),
|
||||||
|
(['PYTAG'], "post" , "post"),
|
||||||
|
(['PYTAG'], "x" , None),
|
||||||
|
(['NUM' ], "a" , None),
|
||||||
|
(['NUM' ], "0" , "0"),
|
||||||
|
(['NUM' ], "1" , "1"),
|
||||||
|
(['NUM' ], "10" , "10"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -191,16 +208,16 @@ def test_re_pattern_parts(part_name, line, expected):
|
||||||
assert result_val == expected, (part_name, line)
|
assert result_val == expected, (part_name, line)
|
||||||
|
|
||||||
|
|
||||||
PATTERN_CASES = [
|
PATTERN_V1_CASES = [
|
||||||
(r"v{year}.{month}.{MINOR}" , "v2017.11.1" , "v2017.11.1"),
|
(r"v{year}.{month}.{MINOR}" , "v2017.11.1" , "v2017.11.1"),
|
||||||
(r"v{year}.{month}.{MINOR}" , "v2017.07.12", "v2017.07.12"),
|
(r"v{year}.{month}.{MINOR}" , "v2017.07.12", "v2017.07.12"),
|
||||||
(r"v{year}.{month_short}.{MINOR}", "v2017.11.1" , "v2017.11.1"),
|
(r"v{year}.{month_short}.{PATCH}", "v2017.11.1" , "v2017.11.1"),
|
||||||
(r"v{year}.{month_short}.{MINOR}", "v2017.7.12" , "v2017.7.12"),
|
(r"v{year}.{month_short}.{PATCH}", "v2017.7.12" , "v2017.7.12"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("pattern_str, line, expected", PATTERN_CASES)
|
@pytest.mark.parametrize("pattern_str, line, expected", PATTERN_V1_CASES)
|
||||||
def test_patterns(pattern_str, line, expected):
|
def test_patterns_v1(pattern_str, line, expected):
|
||||||
pattern = v1patterns.compile_pattern(pattern_str)
|
pattern = v1patterns.compile_pattern(pattern_str)
|
||||||
result = pattern.regexp.search(line)
|
result = pattern.regexp.search(line)
|
||||||
if result is None:
|
if result is None:
|
||||||
|
|
@ -210,6 +227,24 @@ def test_patterns(pattern_str, line, expected):
|
||||||
assert result_val == expected, (pattern_str, line)
|
assert result_val == expected, (pattern_str, line)
|
||||||
|
|
||||||
|
|
||||||
|
PATTERN_V2_CASES = [
|
||||||
|
("vYYYY.0M.MINOR" , "v2017.11.1" , "v2017.11.1"),
|
||||||
|
("vYYYY.0M.MINOR" , "v2017.07.12", "v2017.07.12"),
|
||||||
|
("YYYY.MM[.PATCH]", "2017.11.1" , "2017.11.1"),
|
||||||
|
("YYYY.MM[.PATCH]", "2017.7.12" , "2017.7.12"),
|
||||||
|
("YYYY.MM[.PATCH]", "2017.7" , "2017.7"),
|
||||||
|
("YYYY0M.BUILD" , "201707.1000", "201707.1000"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("pattern_str, line, expected", PATTERN_V2_CASES)
|
||||||
|
def test_patterns_v2(pattern_str, line, expected):
|
||||||
|
pattern = v2patterns.compile_pattern(pattern_str)
|
||||||
|
result = pattern.regexp.search(line)
|
||||||
|
result_val = None if result is None else result.group(0)
|
||||||
|
assert result_val == expected, (pattern_str, line, pattern.regexp.pattern)
|
||||||
|
|
||||||
|
|
||||||
CLI_MAIN_FIXTURE = """
|
CLI_MAIN_FIXTURE = """
|
||||||
@click.group()
|
@click.group()
|
||||||
@click.version_option(version="v201812.0123-beta")
|
@click.version_option(version="v201812.0123-beta")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue