From 0d10752b5a9f68d2f0bd97ac5003bf2690027d58 Mon Sep 17 00:00:00 2001 From: Joscha Date: Wed, 19 May 2021 17:48:51 +0200 Subject: [PATCH] Configure explain log level via cli and config file --- CONFIG.md | 2 ++ PFERD/__main__.py | 19 +++++++++++++++++++ PFERD/config.py | 23 ++++++++++++++--------- PFERD/crawler.py | 2 +- PFERD/crawlers/local.py | 2 +- PFERD/logging.py | 19 +++++++------------ 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 6149ef5..29fc7e2 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -19,6 +19,8 @@ default values for the other sections. paths in the config file are interpreted relative to this path. If this path is relative, it is interpreted relative to the script's working dir. `~` is expanded to the current user's home directory. (Default: `.`) +- `explain`: Whether PFERD should log and explain its actions and decisions in + detail. (Default: `no`) ## The `crawl:*` sections diff --git a/PFERD/__main__.py b/PFERD/__main__.py index 54228a5..589c12d 100644 --- a/PFERD/__main__.py +++ b/PFERD/__main__.py @@ -4,6 +4,7 @@ import configparser from pathlib import Path from .config import Config, ConfigDumpException, ConfigLoadException +from .logging import log from .output_dir import OnConflict, Redownload from .pferd import Pferd from .version import NAME, VERSION @@ -42,6 +43,13 @@ GENERAL_PARSER.add_argument( metavar="PATH", help="custom working directory" ) +GENERAL_PARSER.add_argument( + "--explain", "-e", + # TODO Use argparse.BooleanOptionalAction after updating to 3.9 + action="store_const", + const=True, + help="log and explain in detail what PFERD is doing" +) def load_general( @@ -52,6 +60,8 @@ def load_general( if args.working_dir is not None: section["working_dir"] = str(args.working_dir) + if args.explain is not None: + section["explain"] = "true" if args.explain else "false" CRAWLER_PARSER = argparse.ArgumentParser(add_help=False) @@ -217,6 +227,10 @@ def prune_crawlers( def main() -> None: args = PARSER.parse_args() + # Configure log levels set by command line arguments + if args.explain is not None: + log.output_explain = args.explain + if args.version: print(f"{NAME} {VERSION}") exit() @@ -226,6 +240,11 @@ def main() -> None: except ConfigLoadException: exit(1) + # Configure log levels set in the config file + # TODO Catch config section exceptions + if args.explain is None: + log.output_explain = config.default_section.explain() + if args.dump_config is not None: try: if args.dump_config is True: diff --git a/PFERD/config.py b/PFERD/config.py index 7fe5d9e..08beb0c 100644 --- a/PFERD/config.py +++ b/PFERD/config.py @@ -50,6 +50,15 @@ class Section: self.error(key, "Missing value") +class DefaultSection(Section): + def working_dir(self) -> Path: + pathstr = self.s.get("working_dir", ".") + return Path(pathstr).expanduser() + + def explain(self) -> bool: + return self.s.getboolean("explain", fallback=False) + + class Config: @staticmethod def _default_path() -> Path: @@ -62,6 +71,11 @@ class Config: def __init__(self, parser: ConfigParser): self._parser = parser + self._default_section = DefaultSection(parser[parser.default_section]) + + @property + def default_section(self) -> DefaultSection: + return self._default_section @staticmethod def _fail_load(path: Path, reason: str) -> None: @@ -134,10 +148,6 @@ class Config: def dump_to_stdout(self) -> None: self._parser.write(sys.stdout) - @property - def default_section(self) -> SectionProxy: - return self._parser[self._parser.default_section] - def crawler_sections(self) -> List[Tuple[str, SectionProxy]]: result = [] for name, proxy in self._parser.items(): @@ -153,8 +163,3 @@ class Config: result.append((name, proxy)) return result - - @property - def working_dir(self) -> Path: - pathstr = self.default_section.get("working_dir", ".") - return Path(pathstr).expanduser() diff --git a/PFERD/crawler.py b/PFERD/crawler.py index adfe74b..80ecedb 100644 --- a/PFERD/crawler.py +++ b/PFERD/crawler.py @@ -184,7 +184,7 @@ class Crawler(ABC): self._transformer = Transformer(section.transform()) self._output_dir = OutputDirectory( - config.working_dir / section.output_dir(name), + config.default_section.working_dir() / section.output_dir(name), section.redownload(), section.on_conflict(), ) diff --git a/PFERD/crawlers/local.py b/PFERD/crawlers/local.py index d4156bc..8cfc79a 100644 --- a/PFERD/crawlers/local.py +++ b/PFERD/crawlers/local.py @@ -46,7 +46,7 @@ class LocalCrawler(Crawler): ): super().__init__(name, section, config) - self._target = config.working_dir / section.target() + self._target = config.default_section.working_dir() / section.target() self._crawl_delay = section.crawl_delay() self._download_delay = section.download_delay() self._download_speed = section.download_speed() diff --git a/PFERD/logging.py b/PFERD/logging.py index b075d35..cedc5c9 100644 --- a/PFERD/logging.py +++ b/PFERD/logging.py @@ -52,9 +52,9 @@ class Log: self._lines: List[str] = [] # Whether different parts of the output are enabled or disabled - self._enabled_explain = False - self._enabled_action = True - self._enabled_report = True + self.output_explain = False + self.output_action = True + self.output_report = True def _update_live(self) -> None: elements = [] @@ -66,11 +66,6 @@ class Log: group = RenderGroup(*elements) # type: ignore self._live.update(group) - def configure(self, explain: bool, action: bool, report: bool) -> None: - self._enabled_explain = explain - self._enabled_action = action - self._enabled_report = report - @contextmanager def show_progress(self) -> Iterator[None]: if self._showing_progress: @@ -107,19 +102,19 @@ class Log: self.console.print(text) def explain_topic(self, text: str) -> None: - if self._enabled_explain: + if self.output_explain: self.print(f"[cyan]{escape(text)}") def explain(self, text: str) -> None: - if self._enabled_explain: + if self.output_explain: self.print(f" {escape(text)}") def action(self, text: str) -> None: - if self._enabled_action: + if self.output_action: self.print(text) def report(self, text: str) -> None: - if self._enabled_report: + if self.output_report: self.print(text) @contextmanager