Newer
Older
Handbook / calendar / generate_dates / config / cli.py
import argparse
import datetime
import importlib.resources as pkg_resources
import yaml

from generate_dates import config


class PeriodError(KeyError):
    pass

class PaperError(KeyError):
    pass

class LectureStyleError(KeyError):
    pass


def parse_command_line():
    """Parse command-line arguments.

    Example command lines:
    generate_dates --style calendar --format latex --year 2020 --period S1 --paper INFO201
    generate_dates --style lecture --format xml --period S2 --paper INFO202
    """
    format_map = {
        "t": "text",
        "text": "text",
        "l": "latex",
        "latex": "latex",
        "x": "xml",
        "xml": "xml",
    }
    style_map = {
        "c": "calendar",
        "calendar": "calendar",
        "l": "lecture",
        "lecture": "lecture",
        "i": "iso",
        "iso": "iso",
    }

    parser = argparse.ArgumentParser(
        prog="generate_dates",
        description="")
    
    parser.add_argument(
        "--config", "-c", default=None, dest="config_file",
        help="file name of the configuration file "
            "[default 'default.yml' in generate_dates.config]")
    
    parser.add_argument(
        "--debug", "-d", action='store_true',
        help="enable debugging output")
    
    parser.add_argument(
        "--format", "-f", default="latex",
        choices=["text", "t", "latex", "l", "xml", "x"],
        help="output format [default 'latex']")
    
    parser.add_argument(
        "--output", "-o",
        type=argparse.FileType("w", encoding="UTF-8"),
        help="file name to write the output to; existing "
            "files of the same name will be overwritten!")
    
    parser.add_argument(
        "--paper", "-p", default=None,
        help="paper code (e.g., INFO201) [required for 'lecture' style, "
            "ignored otherwise]")
    
    parser.add_argument(
        "--style", "-s", default="calendar",
        choices=["calendar", "c", "lecture", "l", "iso", "i"],
        help="output style: 'calendar' for teaching calendars in course "
            "outlines, 'lecture' for individual lecture dates, or 'iso'"
            "for dates across the entire ISO-8601 year [default 'calendar']")
    
    parser.add_argument(
        "--teaching-period", "-t", default=None,
        choices=["SS", "S1", "S2", "FY"], dest="period",
        help="teaching period [required]")
    
    parser.add_argument(
        "--year", "-y", type=int, default=datetime.date.today().year,
        help=("the year to generate dates for [default {y}]".format(
            y=datetime.date.today().year)))
    
    args = parser.parse_args()
    # normalise format and style
    args.format = format_map[args.format]
    args.style = style_map[args.style]

    # Load the default config if none is explicitly specified.
    if not args.config_file:
        args.config_file = "default.yml"
        args.config = yaml.safe_load(
            pkg_resources.read_text(config, args.config_file))
    else:
        with open(args.config_file) as cfg:
            args.config = yaml.safe_load(cfg.read())

    if args.style == "calendar":
        # --paper is irrelevant
        if args.paper:
            print("generate_dates: warning: --paper/-p is ignored for "
                "'calendar' style")
        # --teaching-period is required
        if not args.period:
            parser.exit(2, "generate_dates: error: --teaching-period/-t "
                "is required for 'calendar' style\n")

    elif args.style == "iso":
        # both --paper and --teaching-period are irrelevant
        if args.paper or args.period:
            print("generate_dates: warning: --paper/-p and "
                "--teaching-period/-t are ignored for 'iso' style")

    elif args.style == "lecture":
        # both --paper and --teaching-period are required
        if not args.paper:
            parser.exit(2, message="generate_dates: error: -paper/-p and "
                "--teaching-period/-t are required for 'lecture' style\n")
    
    # --teaching-period must be specified if --style is "calendar" or "lecture"
    else:
        pass
    
    return args