fix tests

This commit is contained in:
Manuel Barkhau 2018-12-08 19:18:47 +01:00
parent 0e1a6271a3
commit 946cdaa5ba
13 changed files with 199 additions and 1333 deletions

View file

@ -10,10 +10,7 @@ CLI module for PyCalVer.
Provided subcommands: show, incr, init, bump Provided subcommands: show, incr, init, bump
""" """
import io
import os
import sys import sys
import toml
import click import click
import logging import logging
import typing as typ import typing as typ
@ -144,16 +141,16 @@ def init(verbose: int = 0, dry: bool = False) -> None:
cfg: config.MaybeConfig = config.parse(ctx) cfg: config.MaybeConfig = config.parse(ctx)
if cfg: if cfg:
log.error("Configuration already initialized in {cfg.filename}") log.error("Configuration already initialized in {ctx.config_filepath}")
sys.exit(1) sys.exit(1)
if dry: if dry:
print("Exiting because of '--dry'. Would have written to setup.cfg:") print("Exiting because of '--dry'. Would have written to setup.cfg:")
cfg_lines = config.default_config(output_fmt) cfg_lines = config.default_config(ctx)
print("\n " + "\n ".join(cfg_lines)) print("\n " + "\n ".join(cfg_lines))
return return
config.write_default_config() config.write_content(ctx)
def _assert_not_dirty(vcs, filepaths: typ.Set[str], allow_dirty: bool): def _assert_not_dirty(vcs, filepaths: typ.Set[str], allow_dirty: bool):

View file

@ -22,6 +22,8 @@ log = logging.getLogger("pycalver.config")
PatternsByFilePath = typ.Dict[str, typ.List[str]] PatternsByFilePath = typ.Dict[str, typ.List[str]]
SUPPORTED_CONFIGS = ["setup.cfg", "pyproject.toml", "pycalver.toml"]
class ProjectContext(typ.NamedTuple): class ProjectContext(typ.NamedTuple):
"""Container class for project info.""" """Container class for project info."""
@ -49,6 +51,8 @@ def init_project_ctx(project_path: typ.Union[str, pl.Path, None] = ".") -> Proje
config_filepath = path / "pycalver.toml" config_filepath = path / "pycalver.toml"
config_format = 'toml' config_format = 'toml'
vcs_type: typ.Optional[str]
if (path / ".git").exists(): if (path / ".git").exists():
vcs_type = 'git' vcs_type = 'git'
elif (path / ".hg").exists(): elif (path / ".hg").exists():
@ -70,7 +74,7 @@ class Config(typ.NamedTuple):
tag : bool tag : bool
commit: bool commit: bool
push: bool push : bool
file_patterns: PatternsByFilePath file_patterns: PatternsByFilePath
@ -95,13 +99,12 @@ def _debug_str(cfg: Config) -> str:
MaybeConfig = typ.Optional[Config] MaybeConfig = typ.Optional[Config]
MaybeRawConfig = typ.Optional[RawConfig]
FilePatterns = typ.Dict[str, typ.List[str]] FilePatterns = typ.Dict[str, typ.List[str]]
def _parse_cfg_file_patterns( def _parse_cfg_file_patterns(cfg_parser: configparser.RawConfigParser,) -> FilePatterns:
cfg_parser: configparser.RawConfigParser,
) -> FilePatterns:
file_patterns: FilePatterns = {} file_patterns: FilePatterns = {}
@ -117,14 +120,26 @@ def _parse_cfg_file_patterns(
return file_patterns return file_patterns
def _parse_cfg_option(option_name): class _ConfigParser(configparser.RawConfigParser):
# preserve uppercase filenames """Custom parser, simply to override optionxform behaviour."""
return option_name
def optionxform(self, optionstr: str) -> str:
"""Non-xforming (ie. uppercase preserving) override.
This is important because our option names are actually
filenames, so case sensitivity is relevant. The default
behaviour is to do optionstr.lower()
"""
return optionstr
OptionVal = typ.Union[str, bool, None]
BOOL_OPTIONS: typ.Mapping[str, OptionVal] = {'commit': False, 'tag': None, 'push': None}
def _parse_cfg(cfg_buffer: typ.TextIO) -> RawConfig: def _parse_cfg(cfg_buffer: typ.TextIO) -> RawConfig:
cfg_parser = configparser.RawConfigParser() cfg_parser = _ConfigParser()
cfg_parser.optionxform = _parse_cfg_option
if hasattr(cfg_parser, 'read_file'): if hasattr(cfg_parser, 'read_file'):
cfg_parser.read_file(cfg_buffer) cfg_parser.read_file(cfg_buffer)
@ -132,21 +147,15 @@ def _parse_cfg(cfg_buffer: typ.TextIO) -> RawConfig:
cfg_parser.readfp(cfg_buffer) # python2 compat cfg_parser.readfp(cfg_buffer) # python2 compat
if not cfg_parser.has_section("pycalver"): if not cfg_parser.has_section("pycalver"):
log.error("Missing [pycalver] section.") raise ValueError("Missing [pycalver] section.")
return None
raw_cfg = dict(cfg_parser.items("pycalver")) raw_cfg: RawConfig = dict(cfg_parser.items("pycalver"))
raw_cfg['commit'] = raw_cfg.get('commit', False) for option, default_val in BOOL_OPTIONS.items():
raw_cfg['tag' ] = raw_cfg.get('tag' , None) val: OptionVal = raw_cfg.get(option, default_val)
raw_cfg['push' ] = raw_cfg.get('push' , None) if isinstance(val, str):
val = val.lower() in ("yes", "true", "1", "on")
if isinstance(raw_cfg['commit'], str): raw_cfg[option] = val
raw_cfg['commit'] = raw_cfg['commit'].lower() in ("yes", "true", "1", "on")
if isinstance(raw_cfg['tag'], str):
raw_cfg['tag'] = raw_cfg['tag'].lower() in ("yes", "true", "1", "on")
if isinstance(raw_cfg['push'], str):
raw_cfg['push'] = raw_cfg['push'].lower() in ("yes", "true", "1", "on")
raw_cfg['file_patterns'] = _parse_cfg_file_patterns(cfg_parser) raw_cfg['file_patterns'] = _parse_cfg_file_patterns(cfg_parser)
@ -157,9 +166,8 @@ def _parse_toml(cfg_buffer: typ.TextIO) -> RawConfig:
raw_full_cfg = toml.load(cfg_buffer) raw_full_cfg = toml.load(cfg_buffer)
raw_cfg = raw_full_cfg.get('pycalver', {}) raw_cfg = raw_full_cfg.get('pycalver', {})
raw_cfg['commit'] = raw_cfg.get('commit', False) for option, default_val in BOOL_OPTIONS.items():
raw_cfg['tag' ] = raw_cfg.get('tag' , None) raw_cfg[option] = raw_cfg.get(option, default_val)
raw_cfg['push' ] = raw_cfg.get('push' , None)
return raw_cfg return raw_cfg
@ -208,8 +216,6 @@ def parse(ctx: ProjectContext) -> MaybeConfig:
log.error(f"File not found: {ctx.config_filepath}") log.error(f"File not found: {ctx.config_filepath}")
return None return None
raw_cfg: typ.Optional[RawConfig]
try: try:
with ctx.config_filepath.open(mode="rt", encoding="utf-8") as fh: with ctx.config_filepath.open(mode="rt", encoding="utf-8") as fh:
if ctx.config_format == 'toml': if ctx.config_format == 'toml':
@ -231,6 +237,7 @@ current_version = "{initial_version}"
commit = True commit = True
tag = True tag = True
push = True push = True
[pycalver:file_patterns] [pycalver:file_patterns]
""" """
@ -268,6 +275,7 @@ current_version = "{initial_version}"
commit = true commit = true
tag = true tag = true
push = true push = true
[pycalver.file_patterns] [pycalver.file_patterns]
""" """
@ -312,7 +320,8 @@ DEFAULT_TOML_README_MD_STR = """
def default_config(ctx: ProjectContext) -> str: def default_config(ctx: ProjectContext) -> str:
"""Generate initial default config.""" """Generate initial default config."""
if ctx.config_format == 'cfg': fmt = ctx.config_format
if fmt == 'cfg':
base_str = DEFAULT_CONFIGPARSER_BASE_STR base_str = DEFAULT_CONFIGPARSER_BASE_STR
default_pattern_strs_by_filename = { default_pattern_strs_by_filename = {
@ -321,7 +330,7 @@ def default_config(ctx: ProjectContext) -> str:
"README.rst": DEFAULT_CONFIGPARSER_README_RST_STR, "README.rst": DEFAULT_CONFIGPARSER_README_RST_STR,
"README.md" : DEFAULT_CONFIGPARSER_README_MD_STR, "README.md" : DEFAULT_CONFIGPARSER_README_MD_STR,
} }
elif ctx.config_format == 'toml': elif fmt == 'toml':
base_str = DEFAULT_TOML_BASE_STR base_str = DEFAULT_TOML_BASE_STR
default_pattern_strs_by_filename = { default_pattern_strs_by_filename = {
@ -332,7 +341,7 @@ def default_config(ctx: ProjectContext) -> str:
"README.md" : DEFAULT_TOML_README_MD_STR, "README.md" : DEFAULT_TOML_README_MD_STR,
} }
else: else:
raise ValueError(f"Invalid fmt='{fmt}', must be either 'toml' or 'cfg'.") raise ValueError(f"Invalid config_format='{fmt}', must be either 'toml' or 'cfg'.")
initial_version = dt.datetime.now().strftime("v%Y%m.0001-dev") initial_version = dt.datetime.now().strftime("v%Y%m.0001-dev")
@ -342,11 +351,7 @@ def default_config(ctx: ProjectContext) -> str:
if (ctx.path / filename).exists(): if (ctx.path / filename).exists():
cfg_str += default_str cfg_str += default_str
has_config_file = ( has_config_file = any((ctx.path / fn).exists() for fn in SUPPORTED_CONFIGS)
(ctx.path / "setup.cfg").exists() or
(ctx.path / "pyproject.toml").exists() or
(ctx.path / "pycalver.toml").exists()
)
if not has_config_file: if not has_config_file:
if ctx.config_format == 'cfg': if ctx.config_format == 'cfg':
@ -359,7 +364,14 @@ def default_config(ctx: ProjectContext) -> str:
return cfg_str return cfg_str
def write_content(cfg: Config) -> None: def write_content(ctx: ProjectContext) -> None:
"""Update project config file with initial default config."""
# path : pl.Path
# config_filepath: pl.Path
# config_format : str
# vcs_type : typ.Optional[str]
cfg_lines = default_config(ctx)
cfg_content = "\n" + "\n".join(cfg_lines) cfg_content = "\n" + "\n".join(cfg_lines)
if os.path.exists("pyproject.toml"): if os.path.exists("pyproject.toml"):
with io.open("pyproject.toml", mode="at", encoding="utf-8") as fh: with io.open("pyproject.toml", mode="at", encoding="utf-8") as fh:

View file

@ -152,6 +152,7 @@ def diff(new_version: str, file_patterns: config.PatternsByFilePath) -> str:
content = fh.read() content = fh.read()
rfd = rfd_from_content(patterns, new_version, content) rfd = rfd_from_content(patterns, new_version, content)
rfd = rfd._replace(path=file_path)
full_diff += "\n".join(diff_lines(rfd)) + "\n" full_diff += "\n".join(diff_lines(rfd)) + "\n"
full_diff = full_diff.rstrip("\n") full_diff = full_diff.rstrip("\n")

View file

@ -1,10 +1,16 @@
[pycalver] [pycalver]
current_version = "{initial_version}" current_version = "v201710.0123-alpha"
commit = true commit = true
tag = true tag = true
push = true
[pycalver.file_patterns] [pycalver.file_patterns]
"pycalver.toml" = [
'current_version = "{version}"',
]
"README.md" = [ "README.md" = [
"{version}", "{version}",
"{pep440_version}", "{pep440_version}",
] ]

13
test/fixtures/project_b/setup.cfg vendored Normal file
View file

@ -0,0 +1,13 @@
[pycalver]
current_version = v201307.0456-beta
commit = True
tag = True
push = True
[pycalver:file_patterns]
setup.cfg =
current_version = {version}
setup.py =
version="{pep440_version}"
README.rst =
img.shields.io/badge/PyCalVer-{calver}{build}--{release}-blue

3
test/fixtures/project_b/setup.py vendored Normal file
View file

@ -0,0 +1,3 @@
import setuptools
setuptools.setup(name="mylib", license="MIT", version="201307.456b0", keywords="awesome library")

File diff suppressed because one or more lines are too long

View file

@ -2,18 +2,18 @@ import io
from pycalver import config from pycalver import config
from . import util as test_util from . import util
PYCALVER_TOML_FIXTURE = """ PYCALVER_TOML_FIXTURE = """
[pycalver] [pycalver]
current_version = "v201808.0123-dev" current_version = "v201808.0123-alpha"
commit = true commit = true
tag = true tag = true
push = true push = true
[pycalver.file_patterns] [pycalver.file_patterns]
"setup.py" = [ "README.md" = [
"{version}", "{version}",
"{pep440_version}", "{pep440_version}",
] ]
@ -25,7 +25,7 @@ push = true
SETUP_CFG_FIXTURE = """ SETUP_CFG_FIXTURE = """
[pycalver] [pycalver]
current_version = "v201808.0456-dev" current_version = "v201808.0456-beta"
commit = True commit = True
tag = True tag = True
push = True push = True
@ -52,13 +52,13 @@ def test_parse_toml():
raw_cfg = config._parse_toml(buf) raw_cfg = config._parse_toml(buf)
cfg = config._parse_config(raw_cfg) cfg = config._parse_config(raw_cfg)
assert cfg.current_version == "v201808.0123-dev" assert cfg.current_version == "v201808.0123-alpha"
assert cfg.commit is True assert cfg.commit is True
assert cfg.tag is True assert cfg.tag is True
assert cfg.push is True assert cfg.push is True
assert "pycalver.toml" in cfg.file_patterns assert "pycalver.toml" in cfg.file_patterns
assert cfg.file_patterns["setup.py" ] == ["{version}", "{pep440_version}"] assert cfg.file_patterns["README.md" ] == ["{version}", "{pep440_version}"]
assert cfg.file_patterns["pycalver.toml"] == ['current_version = "{version}"'] assert cfg.file_patterns["pycalver.toml"] == ['current_version = "{version}"']
@ -68,7 +68,7 @@ def test_parse_cfg():
raw_cfg = config._parse_cfg(buf) raw_cfg = config._parse_cfg(buf)
cfg = config._parse_config(raw_cfg) cfg = config._parse_config(raw_cfg)
assert cfg.current_version == "v201808.0456-dev" assert cfg.current_version == "v201808.0456-beta"
assert cfg.commit is True assert cfg.commit is True
assert cfg.tag is True assert cfg.tag is True
assert cfg.push is True assert cfg.push is True
@ -79,76 +79,144 @@ def test_parse_cfg():
def test_parse_default_toml(): def test_parse_default_toml():
project_path = test_util.FIXTURES_DIR / "project_a" project_path = util.FIXTURES_DIR / "project_a"
config_path = test_util.FIXTURES_DIR / "project_a" / "pycalver.toml"
ctx = config.ProjectContext(project_path, config_path, "toml", None) ctx = config.init_project_ctx(project_path)
buf = mk_buf(config.default_config(ctx)) default_toml = config.default_config(ctx)
buf = mk_buf(default_toml)
raw_cfg = config._parse_toml(buf) raw_cfg = config._parse_toml(buf)
cfg = config._parse_config(raw_cfg) cfg = config._parse_config(raw_cfg)
assert cfg assert cfg
assert cfg.current_version.endswith(".0001-dev")
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert "setup.py" in cfg.file_patterns
assert "README.md" in cfg.file_patterns
assert "pycalver.toml" in cfg.file_patterns
def test_parse_default_cfg(): def test_parse_default_cfg():
project_path = test_util.FIXTURES_DIR / "project_a" project_path = util.FIXTURES_DIR / "project_b"
config_path = test_util.FIXTURES_DIR / "project_a" / "setup.cfg"
ctx = config.ProjectContext(project_path, config_path, "cfg", None) ctx = config.init_project_ctx(project_path)
buf = mk_buf(config.default_config(ctx)) default_cfg = config.default_config(ctx)
buf = mk_buf(default_cfg)
raw_cfg = config._parse_cfg(buf) raw_cfg = config._parse_cfg(buf)
cfg = config._parse_config(raw_cfg) cfg = config._parse_config(raw_cfg)
assert cfg assert cfg
assert cfg.current_version.endswith(".0001-dev")
def test_parse_project_toml():
project_path = util.FIXTURES_DIR / "project_a"
config_path = util.FIXTURES_DIR / "project_a" / "pycalver.toml"
with config_path.open() as fh:
config_data = fh.read()
assert "v201710.0123-alpha" in config_data
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, config_path, "toml", None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201710.0123-alpha"
assert cfg.commit is True assert cfg.commit is True
assert cfg.tag is True assert cfg.tag is True
assert cfg.push is True assert cfg.push is True
assert "setup.py" in cfg.file_patterns assert set(cfg.file_patterns.keys()) == {"pycalver.toml", "README.md"}
assert "README.md" in cfg.file_patterns
assert "setup.cfg" in cfg.file_patterns
def test_parse_project_cfg():
project_path = util.FIXTURES_DIR / "project_b"
config_path = util.FIXTURES_DIR / "project_b" / "setup.cfg"
with config_path.open() as fh:
config_data = fh.read()
assert "v201307.0456-beta" in config_data
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, config_path, 'cfg', None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201307.0456-beta"
assert cfg.commit is True
assert cfg.tag is True
assert cfg.push is True
assert set(cfg.file_patterns.keys()) == {"setup.py", "README.rst", "setup.cfg"}
def test_parse_toml_file(tmpdir):
project_path = tmpdir.mkdir("minimal")
setup_cfg = project_path.join("pycalver.toml")
setup_cfg.write(PYCALVER_TOML_FIXTURE)
ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, setup_cfg, 'toml', None)
cfg = config.parse(ctx)
assert cfg
assert cfg.current_version == "v201808.0123-alpha"
assert cfg.tag is True
assert cfg.commit is True
assert cfg.push is True
assert cfg.file_patterns == {
"README.md" : ["{version}", "{pep440_version}"],
"pycalver.toml": ['current_version = "{version}"'],
}
def test_parse_cfg_file(tmpdir): def test_parse_cfg_file(tmpdir):
setup_path = tmpdir.mkdir("minimal").join("setup.cfg") project_path = tmpdir.mkdir("minimal")
setup_path.write(SETUP_CFG_FIXTURE) setup_cfg = project_path.join("setup.cfg")
setup_cfg.write(SETUP_CFG_FIXTURE)
cfg = config.parse(str(setup_path)) ctx = config.init_project_ctx(project_path)
assert ctx == config.ProjectContext(project_path, setup_cfg, 'cfg', None)
cfg = config.parse(ctx)
assert cfg assert cfg
assert cfg.current_version == "v201808.0001-dev" assert cfg.current_version == "v201808.0456-beta"
assert not cfg.tag assert cfg.tag is True
assert not cfg.commit assert cfg.commit is True
assert cfg.push is True
assert cfg.file_patterns == {"setup.cfg": ["current_version = {version}"]} assert cfg.file_patterns == {
"setup.py" : ["{version}", "{pep440_version}"],
"setup.cfg": ['current_version = "{version}"'],
}
def test_parse_config_missing(tmpdir): def test_parse_config_missing(tmpdir):
cfg = config.parse("does_not_exist/setup.cfg") ctx = config.init_project_ctx("does_not_exist/setup.cfg")
assert ctx
cfg = config.parse(ctx)
assert cfg is None assert cfg is None
setup_path = tmpdir.mkdir("fail").join("setup.cfg") setup_path = tmpdir.mkdir("fail").join("setup.cfg")
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(str(setup_path)) cfg = config.parse(ctx)
assert cfg is None assert cfg is None
def test_parse_empty_config(tmpdir): def test_parse_empty_config(tmpdir):
setup_path = tmpdir.mkdir("fail").join("setup.cfg") setup_path = tmpdir.mkdir("fail").join("setup.cfg")
setup_path.write("") setup_path.write("")
ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(str(setup_path)) cfg = config.parse(ctx)
assert cfg is None assert cfg is None
@ -164,7 +232,10 @@ def test_parse_missing_version(tmpdir):
) )
) )
cfg = config.parse(str(setup_path)) ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(ctx)
assert cfg is None assert cfg is None
@ -172,5 +243,8 @@ def test_parse_invalid_version(tmpdir):
setup_path = tmpdir.mkdir("fail").join("setup.cfg") setup_path = tmpdir.mkdir("fail").join("setup.cfg")
setup_path.write("\n".join(("[pycalver]", "current_version = 0.1.0", "commit = False"))) setup_path.write("\n".join(("[pycalver]", "current_version = 0.1.0", "commit = False")))
cfg = config.parse(str(setup_path)) ctx = config.init_project_ctx(setup_path)
assert ctx
cfg = config.parse(ctx)
assert cfg is None assert cfg is None

View file

@ -169,21 +169,25 @@ def test_badge_parse_patterns():
assert matches[1].match == ":alt: CalVer v201809.0002-beta" assert matches[1].match == ":alt: CalVer v201809.0002-beta"
def test_parse_error(): def test_parse_error_empty():
try: try:
parse.VersionInfo.parse("") parse.parse_version_info("")
assert False assert False
except ValueError as err: except ValueError as err:
pass pass
def test_parse_error_noprefix():
try: try:
parse.VersionInfo.parse("201809.0002") parse.parse_version_info("201809.0002")
assert False assert False
except ValueError as err: except ValueError as err:
pass pass
def test_parse_error_nopadding():
try: try:
parse.VersionInfo.parse("v201809.2b0") parse.parse_version_info("v201809.2b0")
assert False assert False
except ValueError as err: except ValueError as err:
pass pass

View file

@ -1,18 +0,0 @@
#!/bin/bash
set -e
if [[ $(python -c "import sys;sys.exit(sys.version[:3] < '3.6')") ]]; then
python --version
python -m pip install setuptools lib3to6
python setup.py bdist_wheel --python-tag=py2.py3
else
curl -sSf -o python-3.6.tar.bz2 https://s3.amazonaws.com/travis-python-archives/binaries/ubuntu/16.04/x86_64/python-3.6.tar.bz2
tar xjf python-3.6.tar.bz2 --directory /
source $HOME/virtualenv/python3.6.0/bin/activate
python3.6 --version
python3.6 -m pip install setuptools lib3to6
python3.6 setup.py bdist_wheel --python-tag=py2.py3
fi

View file

@ -1,26 +0,0 @@
#!/bin/bash
set -e
# minimal test requirements for py27 testing
python -m pip install -U pip
python -m pip install pytest rst2html5
rst2html5 --strict README.rst > /dev/null
rst2html5 --strict CHANGELOG.rst > /dev/null
# first test module from installed wheel
python -m pip install $(ls -1t dist/pycalver*.whl | head -n 1)
grep 'coding: utf-8' $(python -c 'import pycalver;print(pycalver.__file__.replace(".pyc", ".py"))')
python -m pytest test/
if [[ $(python -c "import sys;sys.exit(sys.version[:3] < '3.6')") ]]; then
python -m pip install $(cat requirements-test.txt)
python -m flake8 src/pycalver/
MYPYPATH=stubs/ python -m mypy src/pycalver/;
# next test module from src/
PYTHONPATH=src/:$PYTHONPATH python -m pytest --cov=pycalver test/;
codecov
fi