setup to reduce code duplication

This commit is contained in:
Manuel Barkhau 2020-09-08 20:59:52 +00:00
parent e053af589e
commit 3cbf0e82b1
10 changed files with 271 additions and 267 deletions

View file

@ -7,7 +7,7 @@
import typing as typ
from .patterns import compile_pattern
import pycalver.patterns as v1patterns
class PatternMatch(typ.NamedTuple):
@ -15,37 +15,33 @@ class PatternMatch(typ.NamedTuple):
lineno : int # zero based
line : str
pattern: str
pattern: v1patterns.Pattern
span : typ.Tuple[int, int]
match : str
PatternMatches = typ.Iterable[PatternMatch]
RegexpPatterns = typ.List[typ.Pattern[str]]
def _iter_for_pattern(lines: typ.List[str], pattern: str) -> PatternMatches:
# The pattern is escaped, so that everything besides the format
# string variables is treated literally.
pattern_re = compile_pattern(pattern)
def _iter_for_pattern(lines: typ.List[str], pattern: v1patterns.Pattern) -> PatternMatches:
for lineno, line in enumerate(lines):
match = pattern_re.search(line)
match = pattern.regexp.search(line)
if match:
yield PatternMatch(lineno, line, pattern, match.span(), match.group(0))
def iter_matches(lines: typ.List[str], patterns: typ.List[str]) -> PatternMatches:
def iter_matches(lines: typ.List[str], patterns: typ.List[v1patterns.Pattern]) -> PatternMatches:
"""Iterate over all matches of any pattern on any line.
>>> import pycalver.patterns as v1patterns
>>> lines = ["__version__ = 'v201712.0002-alpha'"]
>>> patterns = ["{pycalver}", "{pep440_pycalver}"]
>>> patterns = [v1patterns.compile_pattern(p) for p in patterns]
>>> matches = list(iter_matches(lines, patterns))
>>> assert matches[0] == PatternMatch(
... lineno = 0,
... line = "__version__ = 'v201712.0002-alpha'",
... pattern= "{pycalver}",
... pattern= v1patterns.compile_pattern("{pycalver}"),
... span = (15, 33),
... match = "v201712.0002-alpha",
... )

View file

@ -177,7 +177,18 @@ PART_FORMATS = {
}
class Pattern(typ.NamedTuple):
raw : str # "{pycalver}", "{year}.{month}", "YYYY0M.BUILD"
regexp: typ.Pattern[str]
Patterns = typ.List[typ.Pattern[str]]
def _replace_pattern_parts(pattern: str) -> str:
# The pattern is escaped, so that everything besides the format
# string variables is treated literally.
for part_name, part_pattern in PART_PATTERNS.items():
named_part_pattern = f"(?P<{part_name}>{part_pattern})"
placeholder = "\u005c{" + part_name + "\u005c}"
@ -192,9 +203,10 @@ def compile_pattern_str(pattern: str) -> str:
return _replace_pattern_parts(pattern)
def compile_pattern(pattern: str) -> typ.Pattern[str]:
def compile_pattern(pattern: str) -> Pattern:
pattern_str = compile_pattern_str(pattern)
return re.compile(pattern_str)
pattern_re = re.compile(pattern_str)
return Pattern(pattern, pattern_re)
def _init_composite_patterns() -> None:

View file

@ -94,9 +94,11 @@ def rewrite_lines(
new_lines = old_lines[:]
found_patterns = set()
for match in parse.iter_matches(old_lines, pattern_strs):
found_patterns.add(match.pattern)
replacement = v1version.format_version(new_vinfo, match.pattern)
patterns = [v1patterns.compile_pattern(p) for p in pattern_strs]
matches = parse.iter_matches(old_lines, patterns)
for match in matches:
found_patterns.add(match.pattern.raw)
replacement = v1version.format_version(new_vinfo, match.pattern.raw)
span_l, span_r = match.span
new_line = match.line[:span_l] + replacement + match.line[span_r:]
new_lines[match.lineno] = new_line

View file

@ -318,11 +318,12 @@ def parse_version_info(version_str: str, pattern: str = "{pycalver}") -> Version
>>> vnfo = parse_version_info("1.23.456", pattern="{semver}")
>>> assert vnfo == _parse_version_info({'MAJOR': "1", 'MINOR': "23", 'PATCH': "456"})
"""
regex = v1patterns.compile_pattern(pattern)
match = regex.match(version_str)
pattern_tup = v1patterns.compile_pattern(pattern)
match = pattern_tup.regexp.match(version_str)
if match is None:
err_msg = (
f"Invalid version string '{version_str}' for pattern '{pattern}'/'{regex.pattern}'"
f"Invalid version string '{version_str}' "
f"for pattern '{pattern}'/'{pattern_tup.regexp.pattern}'"
)
raise PatternError(err_msg)

View file

@ -33,6 +33,8 @@
import re
import typing as typ
import pycalver.patterns as v1patterns
# https://regex101.com/r/fnj60p/10
PYCALVER_PATTERN = r"""
\b
@ -192,9 +194,10 @@ def compile_pattern_str(pattern: str) -> str:
return _replace_pattern_parts(pattern)
def compile_pattern(pattern: str) -> typ.Pattern[str]:
def compile_pattern(pattern: str) -> v1patterns.Pattern:
pattern_str = compile_pattern_str(pattern)
return re.compile(pattern_str)
pattern_re = re.compile(pattern_str)
return v1patterns.Pattern(pattern, pattern_re)
def _init_composite_patterns() -> None:

View file

@ -9,43 +9,40 @@ import io
import typing as typ
import logging
import pycalver2.version as v2version
import pycalver2.patterns as v2patterns
from pycalver import parse
from pycalver import config
from pycalver import rewrite as v1rewrite
from pycalver2 import version
from pycalver2 import patterns
logger = logging.getLogger("pycalver2.rewrite")
def rewrite_lines(
pattern_strs: typ.List[str],
new_vinfo : version.VersionInfo,
new_vinfo : v2version.VersionInfo,
old_lines : typ.List[str],
) -> typ.List[str]:
"""TODO reenable doctest"""
pass
# 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 = 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"']
>>> pattern_strs = ['__version__ = "{pep440_version}"']
>>> rewrite_lines(pattern_strs, new_vinfo, ['__version__ = "201809.2b0"'])
['__version__ = "201811.123b0"']
"""
# >>> pattern_strs = ['__version__ = "{pep440_version}"']
# >>> rewrite_lines(pattern_strs, new_vinfo, ['__version__ = "201809.2b0"'])
# ['__version__ = "201811.123b0"']
# """
new_lines = old_lines[:]
found_patterns = set()
# re_patterns = [patterns.compile_pattern(p) for p in pattern_strs]
# matches = parse.iter_matches(old_lines, re_patterns)
matches = parse.iter_matches(old_lines, pattern_strs)
patterns = [v2patterns.compile_pattern(p) for p in pattern_strs]
matches = parse.iter_matches(old_lines, patterns)
for match in matches:
found_patterns.add(match.pattern)
replacement = version.format_version(new_vinfo, match.pattern)
found_patterns.add(match.pattern.raw)
replacement = v2version.format_version(new_vinfo, match.pattern.raw)
span_l, span_r = match.span
new_line = match.line[:span_l] + replacement + match.line[span_r:]
new_lines[match.lineno] = new_line
@ -54,7 +51,7 @@ def rewrite_lines(
if non_matched_patterns:
for non_matched_pattern in non_matched_patterns:
logger.error(f"No match for pattern '{non_matched_pattern}'")
compiled_pattern_str = patterns.compile_pattern_str(non_matched_pattern)
compiled_pattern_str = v2patterns.compile_pattern_str(non_matched_pattern)
logger.error(f"Pattern compiles to regex '{compiled_pattern_str}'")
raise v1rewrite.NoPatternMatch("Invalid pattern(s)")
else:
@ -63,28 +60,26 @@ def rewrite_lines(
def rfd_from_content(
pattern_strs: typ.List[str],
new_vinfo : version.VersionInfo,
new_vinfo : v2version.VersionInfo,
content : str,
) -> v1rewrite.RewrittenFileData:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# r"""Rewrite pattern occurrences with version string.
r"""Rewrite pattern occurrences with version string.
>>> new_vinfo = version.parse_version_info("v201809.0123")
>>> pattern_strs = ['__version__ = "{pycalver}"']
>>> content = '__version__ = "v201809.0001-alpha"'
>>> rfd = rfd_from_content(pattern_strs, new_vinfo, content)
>>> rfd.new_lines
['__version__ = "v201809.0123"']
>>>
>>> new_vinfo = version.parse_version_info("v1.2.3", "v{semver}")
>>> pattern_strs = ['__version__ = "v{semver}"']
>>> content = '__version__ = "v1.2.2"'
>>> rfd = rfd_from_content(pattern_strs, new_vinfo, content)
>>> rfd.new_lines
['__version__ = "v1.2.3"']
"""
# >>> new_vinfo = version.parse_version_info("v201809.0123")
# >>> pattern_strs = ['__version__ = "{pycalver}"']
# >>> content = '__version__ = "v201809.0001-alpha"'
# >>> rfd = rfd_from_content(pattern_strs, new_vinfo, content)
# >>> rfd.new_lines
# ['__version__ = "v201809.0123"']
# >>>
# >>> new_vinfo = version.parse_version_info("v1.2.3", "v{semver}")
# >>> pattern_strs = ['__version__ = "v{semver}"']
# >>> content = '__version__ = "v1.2.2"'
# >>> rfd = rfd_from_content(pattern_strs, new_vinfo, content)
# >>> rfd.new_lines
# ['__version__ = "v1.2.3"']
# """
line_sep = v1rewrite.detect_line_sep(content)
old_lines = content.split(line_sep)
new_lines = rewrite_lines(pattern_strs, new_vinfo, old_lines)
@ -93,30 +88,28 @@ def rfd_from_content(
def iter_rewritten(
file_patterns: config.PatternsByGlob,
new_vinfo : version.VersionInfo,
new_vinfo : v2version.VersionInfo,
) -> typ.Iterable[v1rewrite.RewrittenFileData]:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# r'''Iterate over files with version string replaced.
r'''Iterate over files with version string replaced.
>>> file_patterns = {"src/pycalver/__init__.py": ['__version__ = "{pycalver}"']}
>>> new_vinfo = version.parse_version_info("v201809.0123")
>>> rewritten_datas = iter_rewritten(file_patterns, new_vinfo)
>>> rfd = list(rewritten_datas)[0]
>>> assert rfd.new_lines == [
... '# This file is part of the pycalver project',
... '# https://gitlab.com/mbarkhau/pycalver',
... '#',
... '# Copyright (c) 2019 Manuel Barkhau (mbarkhau@gmail.com) - MIT License',
... '# SPDX-License-Identifier: MIT',
... '"""PyCalVer: CalVer for Python Packages."""',
... '',
... '__version__ = "v201809.0123"',
... '',
... ]
>>>
'''
# >>> file_patterns = {"src/pycalver/__init__.py": ['__version__ = "{pycalver}"']}
# >>> new_vinfo = version.parse_version_info("v201809.0123")
# >>> rewritten_datas = iter_rewritten(file_patterns, new_vinfo)
# >>> rfd = list(rewritten_datas)[0]
# >>> assert rfd.new_lines == [
# ... '# This file is part of the pycalver project',
# ... '# https://gitlab.com/mbarkhau/pycalver',
# ... '#',
# ... '# Copyright (c) 2019 Manuel Barkhau (mbarkhau@gmail.com) - MIT License',
# ... '# SPDX-License-Identifier: MIT',
# ... '"""PyCalVer: CalVer for Python Packages."""',
# ... '',
# ... '__version__ = "v201809.0123"',
# ... '',
# ... ]
# >>>
# '''
fobj: typ.IO[str]
@ -128,23 +121,24 @@ def iter_rewritten(
yield rfd._replace(path=str(file_path))
def diff(new_vinfo: version.VersionInfo, file_patterns: config.PatternsByGlob) -> str:
"""TODO reenable doctest"""
pass
def diff(
new_vinfo : v2version.VersionInfo,
file_patterns: config.PatternsByGlob,
) -> str:
# TODO reenable doctest
# r"""Generate diffs of rewritten files.
r"""Generate diffs of rewritten files.
>>> new_vinfo = version.parse_version_info("v201809.0123")
>>> file_patterns = {"src/pycalver/__init__.py": ['__version__ = "{pycalver}"']}
>>> diff_str = diff(new_vinfo, file_patterns)
>>> lines = diff_str.split("\n")
>>> lines[:2]
['--- src/pycalver/__init__.py', '+++ src/pycalver/__init__.py']
>>> assert lines[6].startswith('-__version__ = "v2')
>>> assert not lines[6].startswith('-__version__ = "v201809.0123"')
>>> lines[7]
'+__version__ = "v201809.0123"'
"""
# >>> new_vinfo = version.parse_version_info("v201809.0123")
# >>> file_patterns = {"src/pycalver/__init__.py": ['__version__ = "{pycalver}"']}
# >>> diff_str = diff(new_vinfo, file_patterns)
# >>> lines = diff_str.split("\n")
# >>> lines[:2]
# ['--- src/pycalver/__init__.py', '+++ src/pycalver/__init__.py']
# >>> assert lines[6].startswith('-__version__ = "v2')
# >>> assert not lines[6].startswith('-__version__ = "v201809.0123"')
# >>> lines[7]
# '+__version__ = "v201809.0123"'
# """
full_diff = ""
fobj: typ.IO[str]
@ -172,7 +166,7 @@ def diff(new_vinfo: version.VersionInfo, file_patterns: config.PatternsByGlob) -
return full_diff
def rewrite(file_patterns: config.PatternsByGlob, new_vinfo: version.VersionInfo) -> None:
def rewrite(file_patterns: config.PatternsByGlob, new_vinfo: v2version.VersionInfo) -> None:
"""Rewrite project files, updating each with the new version."""
fobj: typ.IO[str]

View file

@ -108,29 +108,27 @@ def _quarter_from_month(month: int) -> int:
def cal_info(date: dt.date = None) -> CalendarInfo:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Generate calendar components for current date.
"""Generate calendar components for current date.
# >>> from datetime import date
>>> from datetime import date
# >>> c = cal_info(date(2019, 1, 5))
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
# (2019, 1, 1, 5, 5, 0, 0)
>>> c = cal_info(date(2019, 1, 5))
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
(2019, 1, 1, 5, 5, 0, 0)
# >>> c = cal_info(date(2019, 1, 6))
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
# (2019, 1, 1, 6, 6, 0, 1)
>>> c = cal_info(date(2019, 1, 6))
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
(2019, 1, 1, 6, 6, 0, 1)
# >>> c = cal_info(date(2019, 1, 7))
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
# (2019, 1, 1, 7, 7, 1, 1)
>>> c = cal_info(date(2019, 1, 7))
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
(2019, 1, 1, 7, 7, 1, 1)
>>> c = cal_info(date(2019, 4, 7))
>>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
(2019, 2, 4, 7, 97, 13, 14)
"""
# >>> c = cal_info(date(2019, 4, 7))
# >>> (c.year_y, c.quarter, c.month, c.dom, c.doy, c.iso_week, c.us_week)
# (2019, 2, 4, 7, 97, 13, 14)
# """
if date is None:
date = TODAY
@ -250,22 +248,20 @@ def _parse_field_values(field_values: FieldValues) -> VersionInfo:
def _is_calver(nfo: typ.Union[CalendarInfo, VersionInfo]) -> bool:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Check pattern for any calendar based parts.
"""Check pattern for any calendar based parts.
# >>> _is_calver(cal_info())
# True
>>> _is_calver(cal_info())
True
# >>> vnfo = _parse_version_info({'year': "2018", 'month': "11", 'bid': "0018"})
# >>> _is_calver(vnfo)
# 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
"""
# >>> 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):
@ -325,48 +321,45 @@ def _parse_pattern_groups(pattern_groups: PatternGroups) -> FieldValues:
def _parse_version_info(pattern_groups: PatternGroups) -> VersionInfo:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Parse normalized VersionInfo from groups of a matched pattern.
"""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", '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({'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", '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)
"""
# >>> 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 = "{pycalver}") -> VersionInfo:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Parse normalized VersionInfo.
"""Parse normalized VersionInfo.
# >>> vnfo = parse_version_info("v201712.0033-beta", pattern="{pycalver}")
# >>> assert vnfo == _parse_version_info({'year': 2017, 'month': 12, 'bid': "0033", 'tag': "beta"})
>>> vnfo = parse_version_info("v201712.0033-beta", pattern="{pycalver}")
>>> assert vnfo == _parse_version_info({'year': 2017, 'month': 12, 'bid': "0033", 'tag': "beta"})
>>> vnfo = parse_version_info("1.23.456", pattern="{semver}")
>>> assert vnfo == _parse_version_info({'MAJOR': "1", 'MINOR': "23", 'PATCH': "456"})
"""
regex = v2patterns.compile_pattern(pattern)
match = regex.match(version_str)
# >>> vnfo = parse_version_info("1.23.456", pattern="{semver}")
# >>> assert vnfo == _parse_version_info({'MAJOR': "1", 'MINOR': "23", 'PATCH': "456"})
# """
pattern_tup = v2patterns.compile_pattern(pattern)
match = pattern_tup.regexp.match(version_str)
if match is None:
err_msg = (
f"Invalid version string '{version_str}' for pattern '{pattern}'/'{regex.pattern}'"
f"Invalid version string '{version_str}' "
f"for pattern '{pattern}'/'{pattern_tup.regexp.pattern}'"
)
raise PatternError(err_msg)
@ -374,20 +367,18 @@ def parse_version_info(version_str: str, pattern: str = "{pycalver}") -> Version
def is_valid(version_str: str, pattern: str = "{pycalver}") -> bool:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Check if a version matches a pattern.
"""Check if a version matches a pattern.
>>> is_valid("v201712.0033-beta", pattern="{pycalver}")
True
>>> is_valid("v201712.0033-beta", pattern="{semver}")
False
>>> is_valid("1.2.3", pattern="{semver}")
True
>>> is_valid("v201712.0033-beta", pattern="{semver}")
False
"""
# >>> is_valid("v201712.0033-beta", pattern="{pycalver}")
# True
# >>> is_valid("v201712.0033-beta", pattern="{semver}")
# False
# >>> is_valid("1.2.3", pattern="{semver}")
# True
# >>> is_valid("v201712.0033-beta", pattern="{semver}")
# False
# """
try:
parse_version_info(version_str, pattern)
return True
@ -454,77 +445,75 @@ def _compile_format_template(pattern: str, kwargs: TemplateKwargs) -> str:
def format_version(vinfo: VersionInfo, pattern: str) -> str:
"""TODO reenable doctest"""
pass
# TODO reenable doctest
# """Generate version string.
"""Generate version string.
# >>> import datetime as dt
# >>> vinfo = parse_version_info("v201712.0033-beta", pattern="{pycalver}")
# >>> vinfo_a = vinfo._replace(**cal_info(date=dt.date(2017, 1, 1))._asdict())
# >>> vinfo_b = vinfo._replace(**cal_info(date=dt.date(2017, 12, 31))._asdict())
>>> import datetime as dt
>>> vinfo = parse_version_info("v201712.0033-beta", pattern="{pycalver}")
>>> vinfo_a = vinfo._replace(**cal_info(date=dt.date(2017, 1, 1))._asdict())
>>> vinfo_b = vinfo._replace(**cal_info(date=dt.date(2017, 12, 31))._asdict())
# >>> format_version(vinfo_a, pattern="v{yy}.{BID}{release}")
# 'v17.33-beta'
# >>> format_version(vinfo_a, pattern="vYY.BUILD[-TAG]")
# 'v17.33-beta'
# >>> format_version(vinfo_a, pattern="YYYY0M.BUILD[PYTAG]")
# '201701.33b0'
>>> format_version(vinfo_a, pattern="v{yy}.{BID}{release}")
'v17.33-beta'
>>> format_version(vinfo_a, pattern="vYY.BUILD[-TAG]")
'v17.33-beta'
>>> format_version(vinfo_a, pattern="YYYY0M.BUILD[PYTAG]")
'201701.33b0'
# >>> format_version(vinfo_a, pattern="{pycalver}")
# 'v201701.0033-beta'
# >>> format_version(vinfo_b, pattern="{pycalver}")
# 'v201712.0033-beta'
>>> format_version(vinfo_a, pattern="{pycalver}")
'v201701.0033-beta'
>>> format_version(vinfo_b, pattern="{pycalver}")
'v201712.0033-beta'
# >>> format_version(vinfo_a, pattern="v{year}w{iso_week}.{BID}{release}")
# 'v2017w00.33-beta'
# >>> format_version(vinfo_a, pattern="vYYYYwWW.BUILD[-TAG]")
# 'v2017w00.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}w{iso_week}.{BID}{release}")
'v2017w00.33-beta'
>>> format_version(vinfo_a, pattern="vYYYYwWW.BUILD[-TAG]")
'v2017w00.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}")
# 'v2017d001.0033-beta'
# >>> format_version(vinfo_b, pattern="v{year}d{doy}.{bid}{release}")
# '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="v{year}d{doy}.{bid}{release}")
'v2017d001.0033-beta'
>>> format_version(vinfo_b, pattern="v{year}d{doy}.{bid}{release}")
'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]")
# 'v2016w52.0033-beta'
>>> format_version(vinfo_a, pattern="vGGGGwVV.BUILD[-TAG]")
'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}")
# 'v2017w52.33-final'
# >>> format_version(vinfo_c, pattern="v{year}w{iso_week}.{BID}{release}")
# '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{year}w{iso_week}.{BID}-{tag}")
'v2017w52.33-final'
>>> format_version(vinfo_c, pattern="v{year}w{iso_week}.{BID}{release}")
'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}")
# 'v1.2.34'
# >>> format_version(vinfo_c, pattern="vMAJOR.MINOR.PATCH")
# 'v1.2.34'
>>> format_version(vinfo_c, pattern="v{MAJOR}.{MINOR}.{PATCH}")
'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')
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAG")
'v1.0.0-final'
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH[-TAG]")
'v1.0.0'
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.PATCH[-TAG]]")
'v1.0'
>>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.MICRO[-TAG]]")
'v1.0'
>>> format_version(vinfo_d, pattern="vMAJOR[.MINOR[.PATCH[-TAG]]]")
'v1'
"""
# >>> vinfo_d = vinfo_b._replace(major=1, minor=0, patch=0, tag='final')
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH-TAG")
# 'v1.0.0-final'
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR.PATCH[-TAG]")
# 'v1.0.0'
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.PATCH[-TAG]]")
# 'v1.0'
# >>> format_version(vinfo_d, pattern="vMAJOR.MINOR[.MICRO[-TAG]]")
# 'v1.0'
# >>> format_version(vinfo_d, pattern="vMAJOR[.MINOR[.PATCH[-TAG]]]")
# 'v1'
# """
kwargs = _derive_template_kwargs(vinfo)
format_tmpl = _compile_format_template(pattern, kwargs)

View file

@ -1,3 +1,4 @@
import pycalver.patterns as v1patterns
from pycalver import parse
SETUP_PY_FIXTURE = """
@ -11,17 +12,17 @@ setuptools.setup(
def test_default_parse_patterns():
lines = SETUP_PY_FIXTURE.splitlines()
patterns = ["{pycalver}", "{pep440_pycalver}"]
matches = list(parse.iter_matches(lines, patterns))
lines = SETUP_PY_FIXTURE.splitlines()
patterns = ["{pycalver}", "{pep440_pycalver}"]
re_patterns = [v1patterns.compile_pattern(p) for p in patterns]
matches = list(parse.iter_matches(lines, re_patterns))
assert len(matches) == 2
assert matches[0].lineno == 3
assert matches[1].lineno == 6
assert matches[0].pattern == patterns[0]
assert matches[1].pattern == patterns[1]
assert matches[0].pattern == re_patterns[0]
assert matches[1].pattern == re_patterns[1]
assert matches[0].match == "v201712.0002-alpha"
assert matches[1].match == "201712.2a0"
@ -30,16 +31,16 @@ def test_default_parse_patterns():
def test_explicit_parse_patterns():
lines = SETUP_PY_FIXTURE.splitlines()
patterns = ["__version__ = '{pycalver}'", "version='{pep440_pycalver}'"]
matches = list(parse.iter_matches(lines, patterns))
patterns = ["__version__ = '{pycalver}'", "version='{pep440_pycalver}'"]
re_patterns = [v1patterns.compile_pattern(p) for p in patterns]
matches = list(parse.iter_matches(lines, re_patterns))
assert len(matches) == 2
assert matches[0].lineno == 3
assert matches[1].lineno == 6
assert matches[0].pattern == patterns[0]
assert matches[1].pattern == patterns[1]
assert matches[0].pattern == re_patterns[0]
assert matches[1].pattern == re_patterns[1]
assert matches[0].match == "__version__ = 'v201712.0002-alpha'"
assert matches[1].match == "version='201712.2a0'"
@ -57,16 +58,17 @@ README_RST_FIXTURE = """
def test_badge_parse_patterns():
lines = README_RST_FIXTURE.splitlines()
patterns = ["badge/CalVer-{calver}{build}-{release}-blue.svg", ":alt: CalVer {pycalver}"]
patterns = ["badge/CalVer-{calver}{build}-{release}-blue.svg", ":alt: CalVer {pycalver}"]
re_patterns = [v1patterns.compile_pattern(p) for p in patterns]
matches = list(parse.iter_matches(lines, re_patterns))
matches = list(parse.iter_matches(lines, patterns))
assert len(matches) == 2
assert matches[0].lineno == 3
assert matches[1].lineno == 5
assert matches[0].pattern == patterns[0]
assert matches[1].pattern == patterns[1]
assert matches[0].pattern == re_patterns[0]
assert matches[1].pattern == re_patterns[1]
assert matches[0].match == "badge/CalVer-v201809.0002--beta-blue.svg"
assert matches[1].match == ":alt: CalVer v201809.0002-beta"

View file

@ -67,8 +67,8 @@ PATTERN_CASES = [
@pytest.mark.parametrize("pattern_str, line, expected", PATTERN_CASES)
def test_patterns(pattern_str, line, expected):
pattern_re = v1patterns.compile_pattern(pattern_str)
result = pattern_re.search(line)
pattern = v1patterns.compile_pattern(pattern_str)
result = pattern.regexp.search(line)
if result is None:
assert expected is None, (pattern_str, line)
else:
@ -84,10 +84,10 @@ CLI_MAIN_FIXTURE = """
def test_pattern_escapes():
pattern = 'click.version_option(version="{pycalver}")'
pattern_re = v1patterns.compile_pattern(pattern)
match = pattern_re.search(CLI_MAIN_FIXTURE)
expected = 'click.version_option(version="v201812.0123-beta")'
pattern_str = 'click.version_option(version="{pycalver}")'
pattern = v1patterns.compile_pattern(pattern_str)
match = pattern.regexp.search(CLI_MAIN_FIXTURE)
expected = 'click.version_option(version="v201812.0123-beta")'
assert match.group(0) == expected
@ -97,8 +97,8 @@ package_metadata = {"name": "mypackage", "version": "v201812.0123-beta"}
def test_curly_escapes():
pattern = 'package_metadata = {"name": "mypackage", "version": "{pycalver}"}'
pattern_re = v1patterns.compile_pattern(pattern)
match = pattern_re.search(CURLY_BRACE_FIXTURE)
expected = 'package_metadata = {"name": "mypackage", "version": "v201812.0123-beta"}'
pattern_str = 'package_metadata = {"name": "mypackage", "version": "{pycalver}"}'
pattern = v1patterns.compile_pattern(pattern_str)
match = pattern.regexp.search(CURLY_BRACE_FIXTURE)
expected = 'package_metadata = {"name": "mypackage", "version": "v201812.0123-beta"}'
assert match.group(0) == expected

View file

@ -136,15 +136,18 @@ def test_part_field_mapping():
b_names = set(patterns.PART_PATTERNS.keys())
c_names = set(patterns.COMPOSITE_PART_PATTERNS.keys())
extra_names = a_names - b_names
assert not any(extra_names)
missing_names = b_names - a_names
assert missing_names == c_names
a_extra_names = a_names - b_names
assert not any(a_extra_names), sorted(a_extra_names)
b_extra_names = b_names - (a_names | c_names)
assert not any(b_extra_names), sorted(b_extra_names)
a_fields = set(version.PATTERN_PART_FIELDS.values())
b_fields = set(version.VersionInfo._fields)
assert a_fields == b_fields
a_extra_fields = a_fields - b_fields
b_extra_fields = b_fields - a_fields
assert not any(a_extra_fields), sorted(a_extra_fields)
assert not any(b_extra_fields), sorted(b_extra_fields)
def vnfo(**field_values):
@ -152,6 +155,8 @@ def vnfo(**field_values):
PARSE_VERSION_TEST_CASES = [
# TODO (mb 2020-09-06): add tests for new style patterns
# ["YYYY.MM.DD" , "2017.06.07", vnfo(year="2017", month="06", dom="07")],
["{year}.{month}.{dom}" , "2017.06.07", vnfo(year="2017", month="06", dom="07")],
["{year}.{month}.{dom_short}" , "2017.06.7" , vnfo(year="2017", month="06", dom="7" )],
["{year}.{month}.{dom_short}" , "2017.06.7" , vnfo(year="2017", month="06", dom="7" )],
@ -169,8 +174,8 @@ PARSE_VERSION_TEST_CASES = [
@pytest.mark.parametrize("pattern_str, line, expected_vinfo", PARSE_VERSION_TEST_CASES)
def test_parse_versions(pattern_str, line, expected_vinfo):
pattern_re = patterns.compile_pattern(pattern_str)
version_match = pattern_re.search(line)
pattern = patterns.compile_pattern(pattern_str)
version_match = pattern.regexp.search(line)
if expected_vinfo is None:
assert version_match is None