Configure explain log level via cli and config file

This commit is contained in:
Joscha 2021-05-19 17:48:51 +02:00
parent 92886fb8d8
commit 0d10752b5a
6 changed files with 44 additions and 23 deletions

View File

@ -19,6 +19,8 @@ default values for the other sections.
paths in the config file are interpreted relative to this path. If this path 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 is relative, it is interpreted relative to the script's working dir. `~` is
expanded to the current user's home directory. (Default: `.`) 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 ## The `crawl:*` sections

View File

@ -4,6 +4,7 @@ import configparser
from pathlib import Path from pathlib import Path
from .config import Config, ConfigDumpException, ConfigLoadException from .config import Config, ConfigDumpException, ConfigLoadException
from .logging import log
from .output_dir import OnConflict, Redownload from .output_dir import OnConflict, Redownload
from .pferd import Pferd from .pferd import Pferd
from .version import NAME, VERSION from .version import NAME, VERSION
@ -42,6 +43,13 @@ GENERAL_PARSER.add_argument(
metavar="PATH", metavar="PATH",
help="custom working directory" 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( def load_general(
@ -52,6 +60,8 @@ def load_general(
if args.working_dir is not None: if args.working_dir is not None:
section["working_dir"] = str(args.working_dir) 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) CRAWLER_PARSER = argparse.ArgumentParser(add_help=False)
@ -217,6 +227,10 @@ def prune_crawlers(
def main() -> None: def main() -> None:
args = PARSER.parse_args() 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: if args.version:
print(f"{NAME} {VERSION}") print(f"{NAME} {VERSION}")
exit() exit()
@ -226,6 +240,11 @@ def main() -> None:
except ConfigLoadException: except ConfigLoadException:
exit(1) 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: if args.dump_config is not None:
try: try:
if args.dump_config is True: if args.dump_config is True:

View File

@ -50,6 +50,15 @@ class Section:
self.error(key, "Missing value") 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: class Config:
@staticmethod @staticmethod
def _default_path() -> Path: def _default_path() -> Path:
@ -62,6 +71,11 @@ class Config:
def __init__(self, parser: ConfigParser): def __init__(self, parser: ConfigParser):
self._parser = parser self._parser = parser
self._default_section = DefaultSection(parser[parser.default_section])
@property
def default_section(self) -> DefaultSection:
return self._default_section
@staticmethod @staticmethod
def _fail_load(path: Path, reason: str) -> None: def _fail_load(path: Path, reason: str) -> None:
@ -134,10 +148,6 @@ class Config:
def dump_to_stdout(self) -> None: def dump_to_stdout(self) -> None:
self._parser.write(sys.stdout) 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]]: def crawler_sections(self) -> List[Tuple[str, SectionProxy]]:
result = [] result = []
for name, proxy in self._parser.items(): for name, proxy in self._parser.items():
@ -153,8 +163,3 @@ class Config:
result.append((name, proxy)) result.append((name, proxy))
return result return result
@property
def working_dir(self) -> Path:
pathstr = self.default_section.get("working_dir", ".")
return Path(pathstr).expanduser()

View File

@ -184,7 +184,7 @@ class Crawler(ABC):
self._transformer = Transformer(section.transform()) self._transformer = Transformer(section.transform())
self._output_dir = OutputDirectory( self._output_dir = OutputDirectory(
config.working_dir / section.output_dir(name), config.default_section.working_dir() / section.output_dir(name),
section.redownload(), section.redownload(),
section.on_conflict(), section.on_conflict(),
) )

View File

@ -46,7 +46,7 @@ class LocalCrawler(Crawler):
): ):
super().__init__(name, section, config) 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._crawl_delay = section.crawl_delay()
self._download_delay = section.download_delay() self._download_delay = section.download_delay()
self._download_speed = section.download_speed() self._download_speed = section.download_speed()

View File

@ -52,9 +52,9 @@ class Log:
self._lines: List[str] = [] self._lines: List[str] = []
# Whether different parts of the output are enabled or disabled # Whether different parts of the output are enabled or disabled
self._enabled_explain = False self.output_explain = False
self._enabled_action = True self.output_action = True
self._enabled_report = True self.output_report = True
def _update_live(self) -> None: def _update_live(self) -> None:
elements = [] elements = []
@ -66,11 +66,6 @@ class Log:
group = RenderGroup(*elements) # type: ignore group = RenderGroup(*elements) # type: ignore
self._live.update(group) 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 @contextmanager
def show_progress(self) -> Iterator[None]: def show_progress(self) -> Iterator[None]:
if self._showing_progress: if self._showing_progress:
@ -107,19 +102,19 @@ class Log:
self.console.print(text) self.console.print(text)
def explain_topic(self, text: str) -> None: def explain_topic(self, text: str) -> None:
if self._enabled_explain: if self.output_explain:
self.print(f"[cyan]{escape(text)}") self.print(f"[cyan]{escape(text)}")
def explain(self, text: str) -> None: def explain(self, text: str) -> None:
if self._enabled_explain: if self.output_explain:
self.print(f" {escape(text)}") self.print(f" {escape(text)}")
def action(self, text: str) -> None: def action(self, text: str) -> None:
if self._enabled_action: if self.output_action:
self.print(text) self.print(text)
def report(self, text: str) -> None: def report(self, text: str) -> None:
if self._enabled_report: if self.output_report:
self.print(text) self.print(text)
@contextmanager @contextmanager