import datetime import importlib.resources as pkg_resources from pathlib import Path from shutil import copyfile import yaml from teachingdates import PROG from .errors import LectureStyleError, PaperError, PeriodError CONFIG_FILENAME = "config.yml" CONFIG_DIR = Path.home().joinpath(".config", PROG) CONFIG_FILE = CONFIG_DIR.joinpath(CONFIG_FILENAME) class Configuration(object): """Validate and structure the configuration for easy access. Includes methods to return the period configuration and the paper configuration, as applicable. (Yes, the period configuration includes the paper configuration, but it may also include other papers, so it's more convenient to return these separately.) The configuration file will normally contain specifications for several teaching periods and papers. We don't need all of this: usually we're only interested in one teaching period and one paper (if relevant). """ style = None period = None paper = None year = None config = None def __init__(self, args): self.config = args.config self.style = args.style self.period = args.period self.paper = args.paper # priority: year on command line (defaults to current year), # year in config self.year = ( args.config["year"] if "year" in args.config.keys() else args.year) period_config = paper_config = None if self.style != "iso": if self.period not in self.config.keys(): raise PeriodError() period_config = self.config[self.period] # raises KeyError if source key is missing period_config["name"] and period_config["weeks"] # papers are irrelevant in "calendar" style if self.style == "lecture": if "papers" in period_config.keys(): if self.paper in period_config["papers"].keys(): paper_config = period_config["papers"][self.paper] # we expect at least a "lectures" entry paper_config["lectures"] else: raise PaperError() else: raise LectureStyleError() def get_period_config(self, period=None): period = self.period if period is None else period if period in self.config.keys(): return self.config[period] else: return None def get_paper_config(self, period=None, paper=None): paper = self.paper if paper is None else paper period_config = self.get_period_config(period=period) if (period_config and "papers" in period_config.keys() and paper in period_config["papers"].keys()): return period_config["papers"][paper] else: return None def load_config(file=None): """Load a configuration file. If no file is specified, try the default configuration in ~/.config. If that doesn't exist, copy the default configuration from teachingdates.config. """ cfg = None if not file: file = CONFIG_FILE if not CONFIG_FILE.exists(): CONFIG_DIR.mkdir(exist_ok=True) configmgr = pkg_resources.path( "teachingdates.config", CONFIG_FILENAME) with configmgr as f: copyfile(f, CONFIG_FILE) print("{prog}: created new configuration file at " "'{f}'".format(prog=PROG, f=str(CONFIG_FILE))) try: with open(file) as f: cfg = yaml.safe_load(f.read()) except FileNotFoundError as e: print("{prog}: error: no such file '{f}'".format(prog=PROG, f=file)) return file, cfg