From 44261a46b1b338a7222f44a7afc35f55f56517d6 Mon Sep 17 00:00:00 2001 From: Manuel Barkhau Date: Sun, 11 Nov 2018 15:08:46 +0100 Subject: [PATCH] refactor config.py --- src/pycalver/config.py | 193 +++++++++++++++++++++++++++-------------- test/test_config.py | 8 +- 2 files changed, 132 insertions(+), 69 deletions(-) diff --git a/src/pycalver/config.py b/src/pycalver/config.py index d6ea838..22efd18 100644 --- a/src/pycalver/config.py +++ b/src/pycalver/config.py @@ -3,6 +3,7 @@ # # Copyright (c) 2018 Manuel Barkhau (@mbarkhau) - MIT License # SPDX-License-Identifier: MIT +"""Parsing code for setup.cfg or pycalver.cfg""" import io import os @@ -21,46 +22,43 @@ log = logging.getLogger("pycalver.config") class Config(typ.NamedTuple): current_version: str - pep440_version : str tag : bool commit: bool file_patterns: typ.Dict[str, typ.List[str]] + def _debug_str(self) -> str: + cfg_str_parts = [ + f"Config Parsed: Config(", + f"current_version='{self.current_version}'", + f"tag={self.tag}", + f"commit={self.commit}", + f"file_patterns={{", + ] + + for filename, patterns in self.file_patterns.items(): + for pattern in patterns: + cfg_str_parts.append(f"\n '{filename}': '{pattern}'") + + cfg_str_parts += ["\n})"] + return ", ".join(cfg_str_parts) + + @property + def pep440_version(self) -> str: + return str(pkg_resources.parse_version(self.current_version)) + MaybeConfig = typ.Optional[Config] +FilePatterns = typ.Dict[str, typ.List[str]] -def parse_buffer(cfg_buffer: io.StringIO) -> MaybeConfig: - cfg_parser = configparser.RawConfigParser() - if hasattr(cfg_parser, 'read_file'): - cfg_parser.read_file(cfg_buffer) - else: - cfg_parser.readfp(cfg_buffer) - if not cfg_parser.has_section("pycalver"): - log.error("setup.cfg does not contain a [pycalver] section.") - return None +def _parse_file_patterns( + cfg_parser: configparser.RawConfigParser, config_filename: str +) -> typ.Optional[FilePatterns]: - base_cfg = dict(cfg_parser.items("pycalver")) - - if "current_version" not in base_cfg: - log.error("setup.cfg does not have 'pycalver.current_version'") - return None - - current_version = base_cfg['current_version'] - if PYCALVER_RE.match(current_version) is None: - log.error(f"setup.cfg 'pycalver.current_version is invalid") - log.error(f"current_version = {current_version}") - return None - - pep440_version = str(pkg_resources.parse_version(current_version)) - - tag = base_cfg.get("tag" , "").lower() in ("yes", "true", "1", "on") - commit = base_cfg.get("commit", "").lower() in ("yes", "true", "1", "on") - - file_patterns: typ.Dict[str, typ.List[str]] = {} + file_patterns: FilePatterns = {} section_name: str for section_name in cfg_parser.sections(): @@ -69,7 +67,7 @@ def parse_buffer(cfg_buffer: io.StringIO) -> MaybeConfig: filepath = section_name.split(":", 2)[-1] if not os.path.exists(filepath): - log.error(f"No such file: {filepath} from {section_name} in setup.cfg") + log.error(f"No such file: {filepath} from {section_name} in {config_filename}") return None section: typ.Dict[str, str] = dict(cfg_parser.items(section_name)) @@ -83,64 +81,125 @@ def parse_buffer(cfg_buffer: io.StringIO) -> MaybeConfig: ] if not file_patterns: - file_patterns["setup.cfg"] = ["{version}", "{pep440_version}"] + file_patterns[f"{config_filename}"] = ["{version}", "{pep440_version}"] + + return file_patterns + + +def _parse_buffer(cfg_buffer: io.StringIO, config_filename: str = "") -> MaybeConfig: + cfg_parser = configparser.RawConfigParser() + + if hasattr(cfg_parser, 'read_file'): + cfg_parser.read_file(cfg_buffer) + else: + cfg_parser.readfp(cfg_buffer) + + if not cfg_parser.has_section("pycalver"): + log.error(f"{config_filename} does not contain a [pycalver] section.") + return None + + base_cfg = dict(cfg_parser.items("pycalver")) + + if "current_version" not in base_cfg: + log.error(f"{config_filename} does not have 'pycalver.current_version'") + return None + + current_version = base_cfg['current_version'] + + if PYCALVER_RE.match(current_version) is None: + log.error(f"{config_filename} 'pycalver.current_version is invalid") + log.error(f"current_version = {current_version}") + return None + + tag = base_cfg.get("tag" , "").lower() in ("yes", "true", "1", "on") + commit = base_cfg.get("commit", "").lower() in ("yes", "true", "1", "on") + + file_patterns = _parse_file_patterns(cfg_parser, config_filename) + + if file_patterns is None: + return None + + cfg = Config(current_version, tag, commit, file_patterns) + + log.debug(cfg._debug_str()) - cfg = Config(current_version, pep440_version, tag, commit, file_patterns) - log.debug(f"Config Parsed: {cfg}") return cfg -def parse(config_file="setup.cfg") -> MaybeConfig: - if not os.path.exists(config_file): - log.error("File not found: setup.cfg") +def parse(config_filename: str = None) -> MaybeConfig: + if config_filename is None: + if os.path.exists("pycalver.cfg"): + config_filename = "pycalver.cfg" + elif os.path.exists("setup.cfg"): + config_filename = "setup.cfg" + else: + log.error("File not found: pycalver.cfg or setup.cfg") + return None + + if not os.path.exists(config_filename): + log.error(f"File not found: {config_filename}") return None cfg_buffer = io.StringIO() - with io.open(config_file, mode="rt", encoding="utf-8") as fh: + with io.open(config_filename, mode="rt", encoding="utf-8") as fh: cfg_buffer.write(fh.read()) cfg_buffer.seek(0) - return parse_buffer(cfg_buffer) + return _parse_buffer(cfg_buffer, config_filename) + + +DEFAULT_CONFIG_BASE_STR = """ +[pycalver] +current_version = {initial_version} +commit = True +tag = True + +[pycalver:file:setup.cfg] +patterns = + current_version = {{version}} +""" + + +DEFAULT_CONFIG_SETUP_PY_STR = """ +[pycalver:file:setup.py] +patterns = + "{version}" + "{pep440_version}" +""" + + +DEFAULT_CONFIG_README_RST_STR = """ +[pycalver:file:README.rst] +patterns = + {version} + {pep440_version} +""" + + +DEFAULT_CONFIG_README_MD_STR = """ +[pycalver:file:README.md] +patterns = + {version} + {pep440_version} +""" def default_config_lines() -> typ.List[str]: initial_version = dt.datetime.now().strftime("v%Y%m.0001-dev") - cfg_lines = [ - "[pycalver]", - f"current_version = {initial_version}", - "commit = True", - "tag = True", - "", - "[pycalver:file:setup.cfg]", - "patterns = ", - " current_version = {version}", - "", - ] + cfg_str = DEFAULT_CONFIG_BASE_STR.format(initial_version=initial_version) + + cfg_lines = cfg_str.splitlines() if os.path.exists("setup.py"): - cfg_lines.extend( - [ - "[pycalver:file:setup.py]", - "patterns = ", - " \"{version}\"", - " \"{pep440_version}\"", - "", - ] - ) + cfg_lines.extend(DEFAULT_CONFIG_SETUP_PY_STR.splitlines()) if os.path.exists("README.rst"): - cfg_lines.extend( - [ - "[pycalver:file:README.rst]", - "patterns = ", - " {version}", - " {pep440_version}", - "", - ] - ) + cfg_lines.extend(DEFAULT_CONFIG_README_RST_STR.splitlines()) if os.path.exists("README.md"): - cfg_lines.extend(["[pycalver:file:README.md]", " {version}", " {pep440_version}", ""]) + cfg_lines.extend(DEFAULT_CONFIG_README_MD_STR.splitlines()) + + cfg_lines += [""] return cfg_lines diff --git a/test/test_config.py b/test/test_config.py index 68f000e..078dbf3 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -9,16 +9,20 @@ def test_parse_default_config(): buf.write(line + "\n") buf.seek(0) - cfg = config.parse_buffer(buf) + cfg = config._parse_buffer(buf) assert cfg assert cfg.current_version.endswith(".0001-dev") assert cfg.tag assert cfg.commit + # NOTE (mb 2018-11-10): These refer to the actual files + # of the pycalver project. A different project would + # have README.rst for example. To fully test this + # we might create temporary projects. assert "setup.py" in cfg.file_patterns assert "setup.cfg" in cfg.file_patterns - assert "README.rst" in cfg.file_patterns + assert "README.md" in cfg.file_patterns def test_parse(tmpdir):