diff --git a/src/pycalver2/rewrite.py b/src/pycalver2/rewrite.py index 49cd6bb..5816485 100644 --- a/src/pycalver2/rewrite.py +++ b/src/pycalver2/rewrite.py @@ -23,18 +23,23 @@ def rewrite_lines( new_vinfo : v2version.VersionInfo, old_lines : typ.List[str], ) -> typ.List[str]: - # TODO reenable doctest - # """Replace occurances of pattern_strs in old_lines with new_vinfo. + """Replace occurances of pattern_strs in old_lines with new_vinfo. - # >>> new_vinfo = version.parse_version_info("v201811.0123-beta") - # >>> pattern_strs = ['__version__ = "{pycalver}"'] - # >>> rewrite_lines(pattern_strs, new_vinfo, ['__version__ = "v201809.0002-beta"']) - # ['__version__ = "v201811.0123-beta"'] + >>> new_vinfo = v2version.parse_version_info("v201811.0123-beta") + >>> pattern_strs = ['__version__ = "vYYYY0M.BUILD[-TAG]"'] + >>> old_lines = ['__version__ = "v201809.0002-alpha" '] + >>> rewrite_lines(pattern_strs, new_vinfo, old_lines) + ['__version__ = "v201811.0123-beta" '] - # >>> pattern_strs = ['__version__ = "{pep440_version}"'] - # >>> rewrite_lines(pattern_strs, new_vinfo, ['__version__ = "201809.2b0"']) - # ['__version__ = "201811.123b0"'] - # """ + >>> old_lines = ['__version__ = "v201809.0002-alpha" # comment'] + >>> rewrite_lines(pattern_strs, new_vinfo, old_lines) + ['__version__ = "v201811.0123-beta" # comment'] + + >>> pattern_strs = ['__version__ = "YYYY0M.BLD[PYTAGNUM]"'] + >>> old_lines = ['__version__ = "201809.2a0"'] + >>> rewrite_lines(pattern_strs, new_vinfo, old_lines) + ['__version__ = "201811.123b0"'] + """ new_lines = old_lines[:] found_patterns = set() diff --git a/src/pycalver2/version.py b/src/pycalver2/version.py index 95f5155..6d9fe71 100644 --- a/src/pycalver2/version.py +++ b/src/pycalver2/version.py @@ -411,10 +411,70 @@ def _make_segments(pattern: str) -> typ.List[str]: pattern_segs_r.append(seg_r) pattern_segs_l.append(pattern_rest) + return pattern_segs_l + list(reversed(pattern_segs_r)) - # NOTE (mb 2020-09-18): The pivot makes subsequent code a bit more simple - pivot = [""] - return pattern_segs_l + pivot + list(reversed(pattern_segs_r)) + +def _clear_zero_segments( + formatted_segs: typ.List[str], is_zero_segment: typ.List[bool] +) -> typ.List[str]: + non_zero_segs = list(formatted_segs) + + has_val_to_right = False + for idx, is_zero in reversed(list(enumerate(is_zero_segment))): + is_optional = 0 < idx < len(formatted_segs) - 1 + if is_optional: + if is_zero and not has_val_to_right: + non_zero_segs[idx] = "" + else: + has_val_to_right = True + + return non_zero_segs + + +def _format_segments( + vinfo : VersionInfo, + pattern_segs: typ.List[str], +) -> typ.List[str]: + kwargs = _format_part_values(vinfo) + part_values = sorted(kwargs.items(), key=lambda item: -len(item[0])) + + is_zero_segment = [True] * len(pattern_segs) + + formatted_segs_l: typ.List[str] = [] + formatted_segs_r: typ.List[str] = [] + + idx_l = 0 + idx_r = len(pattern_segs) - 1 + while idx_l <= idx_r: + # NOTE (mb 2020-09-18): All segments are optional, + # except the most left and the most right, + # i.e the ones NOT surrounded by braces. + # Empty string is a valid segment. + is_optional = idx_l > 0 + + seg_l = pattern_segs[idx_l] + seg_r = pattern_segs[idx_r] + + for part, part_value in part_values: + if part in seg_l: + seg_l = seg_l.replace(part, part_value) + if not (is_optional and str(part_value) == ZERO_VALUES.get(part)): + is_zero_segment[idx_l] = False + + if part in seg_r: + seg_r = seg_r.replace(part, part_value) + if not (is_optional and str(part_value) == ZERO_VALUES[part]): + is_zero_segment[idx_r] = False + + formatted_segs_l.append(seg_l) + if idx_l < idx_r: + formatted_segs_r.append(seg_r) + + idx_l += 1 + idx_r -= 1 + + formatted_segs = formatted_segs_l + list(reversed(formatted_segs_r)) + return _clear_zero_segments(formatted_segs, is_zero_segment) def format_version(vinfo: VersionInfo, pattern: str) -> str: @@ -500,57 +560,13 @@ def format_version(vinfo: VersionInfo, pattern: str) -> str: >>> vinfo_d = vinfo_b._replace(major=1, minor=0, patch=0, tag='rc', num=2) >>> format_version(vinfo_d, pattern="vMAJOR[.MINOR[.PATCH[-TAG[NUM]]]]") 'v1.0.0-rc2' + + >>> vinfo_d = vinfo_b._replace(major=1, minor=0, patch=0, tag='rc', num=2) + >>> format_version(vinfo_d, pattern='__version__ = "vMAJOR[.MINOR[.PATCH[-TAG[NUM]]]]"') + '__version__ = "v1.0.0-rc2"' """ - kwargs = _format_part_values(vinfo) - part_values = sorted(kwargs.items(), key=lambda item: -len(item[0])) - - pattern_segs = _make_segments(pattern) - - iszero_segment = [True] * len(pattern_segs) - formatted_segs_l: typ.List[str] = [] - formatted_segs_r: typ.List[str] = [] - - used_part_values = [] - - idx_l = 0 - idx_r = len(pattern_segs) - 1 - while idx_l < idx_r: - # NOTE (mb 2020-09-18): All segments are optional, - # except the most left and the most right, - # i.e the ones NOT surrounded by braces. - # Empty string is a valid segment. - is_optional = idx_l > 0 - - seg_l = pattern_segs[idx_l] - seg_r = pattern_segs[idx_r] - - for part, part_value in part_values: - if part in seg_l: - used_part_values.append(part + "=" + part_value) - seg_l = seg_l.replace(part, part_value) - if not (is_optional and str(part_value) == ZERO_VALUES.get(part)): - iszero_segment[idx_l] = False - - if part in seg_r: - used_part_values.append(part + "=" + part_value) - seg_r = seg_r.replace(part, part_value) - if not (is_optional and str(part_value) == ZERO_VALUES[part]): - iszero_segment[idx_r] = False - - formatted_segs_l.append(seg_l) - formatted_segs_r.append(seg_r) - - idx_l += 1 - idx_r -= 1 - - formatted_segs = formatted_segs_l + list(reversed(formatted_segs_r)) - - has_val_to_right = False - for idx, is_zero in reversed(list(enumerate(iszero_segment))): - if is_zero and not has_val_to_right: - formatted_segs[idx] = "" - else: - has_val_to_right = True + pattern_segs = _make_segments(pattern) + formatted_segs = _format_segments(vinfo, pattern_segs) return "".join(formatted_segs) diff --git a/test/test_version.py b/test/test_version.py index 696fec7..43f3720 100644 --- a/test/test_version.py +++ b/test/test_version.py @@ -205,6 +205,17 @@ def test_v2_parse_versions(): assert vnfo == v2version._parse_version_info(fvals) +def test_make_segments(): + segs = v2version._make_segments("vYYYY0M.BUILD[-TAG[NUM]]") + assert segs == ["vYYYY0M.BUILD", "-TAG", "NUM", "", ""] + + segs = v2version._make_segments('__version__ = "YYYY0M.BLD[PYTAGNUM]"') + assert segs == ['__version__ = "YYYY0M.BLD', 'PYTAGNUM', '"'] + + segs = v2version._make_segments('__version__ = "YYYY.BUILD[-TAG]"') + assert segs == ['__version__ = "YYYY.BUILD', '-TAG', '"'] + + def test_v2_format_version(): pattern = "vYYYY0M.BUILD[-TAG[NUM]]" in_version = "v200701.0033-beta" @@ -218,3 +229,12 @@ def test_v2_format_version(): result = v2version.format_version(vinfo, pattern="vYY.BLD[-TAG]") assert result == "v7.33-beta" + + result = v2version.format_version(vinfo, pattern="vYY.BLD-TAG") + assert result == "v7.33-beta" + + result = v2version.format_version(vinfo, pattern='__version__ = "YYYY.BUILD[-TAG]"') + assert result == '__version__ = "2007.0033-beta"' + + result = v2version.format_version(vinfo, pattern='__version__ = "YYYY.BLD"') + assert result == '__version__ = "2007.33"'