Newer
Older
Handbook / calendar / teachingdates / config / config.py
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)


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


def parse_config(config, args):
    """Validate and filter the top-level configuration.

    Returns separate references to 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 a separate reference
    for the specified paper.)

    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).
    """
    period_config = paper_config = None
    # this is all irrelevant if we're going ISO style
    if args.style != "iso":
        if args.period not in config.keys():
            raise PeriodError()

        period_config = config[args.period]
        # raises KeyError if source key is missing
        period_config["name"] and period_config["weeks"]

        # papers are irrelevant in "calendar" style
        if args.style == "lecture":
            if "papers" in period_config.keys():
                if args.paper in period_config["papers"].keys():
                    paper_config = period_config["papers"][args.paper]
                    # we expect at least a "lectures" entry
                    paper_config["lectures"]
                else:
                    raise PaperError()
            else:
                raise LectureStyleError()
    
    return period_config, paper_config