allow globs in file_patterns

This commit is contained in:
Manuel Barkhau 2019-02-21 15:41:06 +01:00
parent 710019ee44
commit 1e633a2a7d
10 changed files with 136 additions and 43 deletions

View file

@ -143,7 +143,7 @@ setup.cfg =
current_version = {pycalver}
setup.py =
version="{pep440_pycalver}"
myproject/__init__.py =
src/myproject_v*/__init__.py =
__version__ = "{pycalver}"
README.md =
[PyCalVer {calver}{build}{release}]
@ -167,8 +167,14 @@ INFO - New Version: v201902.0002-beta
+[![Version v201902.0002][version_img]][version_ref]
[![PyPI Releases][pypi_img]][pypi_ref]
--- myproject/__init__.py
+++ myproject/__init__.py
--- src/myproject_v1/__init__.py
+++ src/myproject_v1/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "v201901.0001-beta"
+__version__ = "v201902.0002-beta"
--- src/myproject_v2/__init__.py
+++ src/myproject_v2/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "v201901.0001-beta"
+__version__ = "v201902.0002-beta"

View file

@ -20,7 +20,8 @@ from . import version
log = logging.getLogger("pycalver.config")
PatternsByFilePath = typ.Dict[str, typ.List[str]]
Patterns = typ.List[str]
PatternsByGlob = typ.Dict[str, Patterns]
SUPPORTED_CONFIGS = ["setup.cfg", "pyproject.toml", "pycalver.toml"]
@ -84,7 +85,7 @@ class Config(typ.NamedTuple):
tag : bool
push : bool
file_patterns: PatternsByFilePath
file_patterns: PatternsByGlob
def _debug_str(cfg: Config) -> str:
@ -182,6 +183,10 @@ def _parse_toml(cfg_buffer: typ.IO[str]) -> RawConfig:
def _normalize_file_patterns(raw_cfg: RawConfig) -> FilePatterns:
"""Create consistent representation of file_patterns.
The result the same, regardless of the config format.
"""
version_str : str = raw_cfg['current_version']
version_pattern: str = raw_cfg['version_pattern']
pep440_version : str = version.to_pep440(version_str)

View file

@ -6,9 +6,11 @@
"""Rewrite files, updating occurences of version strings."""
import io
import glob
import difflib
import logging
import typing as typ
import pathlib2 as pl
from . import parse
from . import config
@ -88,8 +90,17 @@ def rfd_from_content(patterns: typ.List[str], new_version: str, content: str) ->
return RewrittenFileData("<path>", line_sep, old_lines, new_lines)
def _iter_file_paths(
file_patterns: config.PatternsByGlob
) -> typ.Iterable[typ.Tuple[pl.Path, config.Patterns]]:
for globstr, patterns in file_patterns.items():
for file_path_str in glob.glob(globstr):
file_path = pl.Path(file_path_str)
yield (file_path, patterns)
def iter_rewritten(
file_patterns: config.PatternsByFilePath, new_version: str
file_patterns: config.PatternsByGlob, new_version: str
) -> typ.Iterable[RewrittenFileData]:
r'''Iterate over files with version string replaced.
@ -111,12 +122,12 @@ def iter_rewritten(
'''
fh: typ.IO[str]
for filepath, patterns in file_patterns.items():
with io.open(filepath, mode="rt", encoding="utf-8") as fh:
for file_path, patterns in _iter_file_paths(file_patterns):
with file_path.open(mode="rt", encoding="utf-8") as fh:
content = fh.read()
rfd = rfd_from_content(patterns, new_version, content)
yield rfd._replace(path=filepath)
yield rfd._replace(path=str(file_path))
def diff_lines(rfd: RewrittenFileData) -> typ.List[str]:
@ -137,7 +148,7 @@ def diff_lines(rfd: RewrittenFileData) -> typ.List[str]:
return list(lines)
def diff(new_version: str, file_patterns: config.PatternsByFilePath) -> str:
def diff(new_version: str, file_patterns: config.PatternsByGlob) -> str:
r"""Generate diffs of rewritten files.
>>> file_patterns = {"src/pycalver/__init__.py": ['__version__ = "{pycalver}"']}
@ -152,22 +163,21 @@ def diff(new_version: str, file_patterns: config.PatternsByFilePath) -> str:
"""
full_diff = ""
file_path: str
fh : typ.IO[str]
fh: typ.IO[str]
for file_path, patterns in sorted(file_patterns.items()):
with io.open(file_path, mode="rt", encoding="utf-8") as fh:
for file_path, patterns in sorted(_iter_file_paths(file_patterns)):
with file_path.open(mode="rt", encoding="utf-8") as fh:
content = fh.read()
rfd = rfd_from_content(patterns, new_version, content)
rfd = rfd._replace(path=file_path)
rfd = rfd._replace(path=str(file_path))
full_diff += "\n".join(diff_lines(rfd)) + "\n"
full_diff = full_diff.rstrip("\n")
return full_diff
def rewrite(new_version: str, file_patterns: config.PatternsByFilePath) -> None:
def rewrite(new_version: str, file_patterns: config.PatternsByGlob) -> None:
"""Rewrite project files, updating each with the new version."""
fh: typ.IO[str]

View file

@ -11,3 +11,5 @@ setup.py =
version="{pep440_version}"
README.rst =
img.shields.io/badge/PyCalVer-{calver}{build}--{release}-blue
src/module_v*/__init__.py =
__version__ = "{version}"

View file

@ -0,0 +1,2 @@
__version__ = "v201307.0456-beta"

View file

@ -0,0 +1,2 @@
__version__ = "v201307.0456-beta"

View file

@ -1,5 +1,4 @@
import os
import io
import time
import shutil
import pathlib2 as pl
@ -166,19 +165,19 @@ def test_incr_invalid(runner):
def _add_project_files(*files):
if "README.md" in files:
with io.open("README.md", mode="wt", encoding="utf-8") as fh:
with pl.Path("README.md").open(mode="wt", encoding="utf-8") as fh:
fh.write("Hello World v201701.0002-alpha !\n")
if "setup.cfg" in files:
with io.open("setup.cfg", mode="wt", encoding="utf-8") as fh:
with pl.Path("setup.cfg").open(mode="wt", encoding="utf-8") as fh:
fh.write(SETUP_CFG_FIXTURE)
if "pycalver.toml" in files:
with io.open("pycalver.toml", mode="wt", encoding="utf-8") as fh:
with pl.Path("pycalver.toml").open(mode="wt", encoding="utf-8") as fh:
fh.write(PYCALVER_TOML_FIXTURE)
if "pyproject.toml" in files:
with io.open("pyproject.toml", mode="wt", encoding="utf-8") as fh:
with pl.Path("pyproject.toml").open(mode="wt", encoding="utf-8") as fh:
fh.write(PYPROJECT_TOML_FIXTURE)
@ -221,7 +220,7 @@ def test_novcs_nocfg_init(runner, caplog, capsys):
assert "File not found" in log.message
assert os.path.exists("pycalver.toml")
with io.open("pycalver.toml", mode="r", encoding="utf-8") as fh:
with pl.Path("pycalver.toml").open(mode="r", encoding="utf-8") as fh:
cfg_content = fh.read()
base_str = config.DEFAULT_TOML_BASE_TMPL.format(initial_version=config._initial_version())
@ -248,7 +247,7 @@ def test_novcs_setupcfg_init(runner):
result = runner.invoke(pycalver.cli, ['init', "--verbose"])
assert result.exit_code == 0
with io.open("setup.cfg", mode="r", encoding="utf-8") as fh:
with pl.Path("setup.cfg").open(mode="r", encoding="utf-8") as fh:
cfg_content = fh.read()
base_str = config.DEFAULT_CONFIGPARSER_BASE_TMPL.format(
@ -268,7 +267,7 @@ def test_novcs_pyproject_init(runner):
result = runner.invoke(pycalver.cli, ['init', "--verbose"])
assert result.exit_code == 0
with io.open("pyproject.toml", mode="r", encoding="utf-8") as fh:
with pl.Path("pyproject.toml").open(mode="r", encoding="utf-8") as fh:
cfg_content = fh.read()
base_str = config.DEFAULT_TOML_BASE_TMPL.format(initial_version=config._initial_version())
@ -367,14 +366,14 @@ def test_novcs_bump(runner):
calver = config._initial_version()[:7]
with io.open("README.md") as fh:
with pl.Path("README.md").open() as fh:
content = fh.read()
assert calver + ".0002-alpha !\n" in content
result = runner.invoke(pycalver.cli, ['bump', "--verbose", "--release", "beta"])
assert result.exit_code == 0
with io.open("README.md") as fh:
with pl.Path("README.md").open() as fh:
content = fh.read()
assert calver + ".0003-beta !\n" in content
@ -391,7 +390,7 @@ def test_git_bump(runner):
calver = config._initial_version()[:7]
with io.open("README.md") as fh:
with pl.Path("README.md").open() as fh:
content = fh.read()
assert calver + ".0002-alpha !\n" in content
@ -408,6 +407,6 @@ def test_hg_bump(runner):
calver = config._initial_version()[:7]
with io.open("README.md") as fh:
with pl.Path("README.md").open() as fh:
content = fh.read()
assert calver + ".0002-alpha !\n" in content

View file

@ -182,7 +182,12 @@ def test_parse_project_cfg():
assert cfg.tag is True
assert cfg.push is True
assert set(cfg.file_patterns.keys()) == {"setup.py", "README.rst", "setup.cfg"}
assert set(cfg.file_patterns.keys()) == {
"setup.py",
"README.rst",
"setup.cfg",
"src/module_v*/__init__.py",
}
def test_parse_toml_file(tmpdir):

View file

@ -1,5 +1,8 @@
from pycalver import config
from pycalver import rewrite
from . import util
REWRITE_FIXTURE = """
# SPDX-License-Identifier: MIT
@ -29,3 +32,38 @@ def test_rewrite_final():
assert "v201911.0003" not in "\n".join(old_lines)
assert "None" not in "\n".join(new_lines)
assert "v201911.0003-final" in "\n".join(new_lines)
def test_iter_file_paths():
with util.Project(project="a") as project:
ctx = config.init_project_ctx(project.dir)
cfg = config.parse(ctx)
assert cfg
file_paths = {
str(file_path) for file_path, patterns in rewrite._iter_file_paths(cfg.file_patterns)
}
assert file_paths == {
"pycalver.toml",
"README.md",
}
def test_iter_file_globs():
with util.Project(project="b") as project:
ctx = config.init_project_ctx(project.dir)
cfg = config.parse(ctx)
assert cfg
file_paths = {
str(file_path) for file_path, patterns in rewrite._iter_file_paths(cfg.file_patterns)
}
assert file_paths == {
"setup.cfg",
"setup.py",
"README.rst",
"src/module_v1/__init__.py",
"src/module_v2/__init__.py",
}

View file

@ -1,3 +1,4 @@
import os
import shlex
import shutil
import tempfile
@ -21,44 +22,67 @@ class Shell:
_MODULE_PATH = pl.Path(__file__)
FIXTURES_DIR = _MODULE_PATH.parent / "fixtures"
FIXTURE_PATH_PARTS = [
["README.rst"],
["README.md"],
["setup.cfg"],
["setup.py"],
["pycalver.toml"],
["src", "module_v1", "__init__.py"],
["src", "module_v2", "__init__.py"],
]
class Project:
def __init__(self, project_prefix="a"):
if not project_prefix.endswith("_"):
project_prefix += "_"
def __init__(self, project="a"):
if not project.startswith("project_"):
project = "project_" + project
tmpdir = pl.Path(tempfile.mkdtemp(prefix="pytest_"))
self.tmpdir = tmpdir
_project_dir = tmpdir / "pycalver_project"
_project_dir.mkdir()
self.dir = tmpdir / "pycalver_project"
self.dir.mkdir()
for fpath in FIXTURES_DIR.glob(project_prefix + "*"):
fname = fpath.name[len(project_prefix) :]
shutil.copy(fpath, _project_dir / fname)
fixtures_subdir = FIXTURES_DIR / project
self.dir = _project_dir
for path_parts in FIXTURE_PATH_PARTS:
fixture_fpath = fixtures_subdir.joinpath(*path_parts)
if fixture_fpath.exists():
project_fpath = self.dir.joinpath(*path_parts)
project_fpath.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(str(fixture_fpath), str(project_fpath))
def __enter__(self):
self.prev_cwd = os.getcwd()
os.chdir(self.dir)
return self
def __exit__(self, *exc):
shutil.rmtree(str(self.tmpdir))
os.chdir(self.prev_cwd)
return False
def sh(self, cmd):
shell = Shell(str(self.dir))
return shell(cmd)
def _vcs_addall(self, cmd):
added_file_paths = []
for path_parts in FIXTURE_PATH_PARTS:
maybe_file_path = self.dir.joinpath(*path_parts)
if maybe_file_path.exists():
self.sh(f"{cmd} add {str(maybe_file_path)}")
added_file_paths.append(maybe_file_path)
assert len(added_file_paths) >= 2
def git_init(self):
self.sh("git init")
self.sh("git add pycalver.toml")
self.sh("git add README.md")
self._vcs_addall(cmd="git")
self.sh("git commit -m 'initial commit'")
def hg_init(self):
self.sh = Shell(str(self.dir))
self.sh("hg init")
self.sh("hg add pycalver.toml")
self.sh("hg add README.md")
self._vcs_addall(cmd="hg")
self.sh("hg commit -m 'initial commit'")