GitBucket
4.21.2
Toggle navigation
Snippets
Sign in
Files
Branches
1
Releases
Issues
1
Pull requests
Labels
Priorities
Milestones
Wiki
Forks
nigel.stanger
/
Handbook
Browse code
Moved CLI arg processing into config package
master
1 parent
fd1a6da
commit
6fd6cb2dcf0e28aece5f5c214ab0cfb86b75e134
Nigel Stanger
authored
on 18 Nov 2019
Patch
Showing
3 changed files
calendar/generate_dates/app.py
calendar/generate_dates/config/__init__.py
calendar/generate_dates/config/cli.py
Ignore Space
Show notes
View
calendar/generate_dates/app.py
import argparse import copy import pathlib import sys from generate_dates import TeachingCalendar, config, templates from generate_dates.config import parse_command_line class PeriodError(KeyError): pass class PaperError(KeyError): pass class LectureStyleError(KeyError): pass 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 def run(): args = parse_command_line() if args.debug: print("DEBUG: args: {0}".format(args)) try: period_config, paper_config = parse_config(args.config, args) if args.debug: print("DEBUG: period config: {0}".format(period_config)) print("DEBUG: paper config: {0}".format(paper_config)) # priority: year on command line (defaults to current year), # year in config if period_config: args.year = ( args.config["year"] if "year" in args.config.keys() else args.year) cal = TeachingCalendar.TeachingCalendar( args.year, args.period, args.paper, period_config, paper_config) print("Period = {p}".format(p=args.period)) print(cal.calendar()) print(cal.lecture_dates()) except LectureStyleError as e: print("ERROR: 'lecture' style was requested but {c} contains no " "papers for {t}.".format(c=args.config, t=args.period)) except PaperError as e: print("ERROR: no entry in {c} for paper {p} ({t}).".format( c=args.config, p=args.paper, t=args.period)) except PeriodError as e: print("ERROR: no entry in {c} for teaching period " "{p}.".format(c=args.config_file, p=args.period)) except KeyError as e: print("ERROR: teaching period {p} in {c} is missing required " "key {k}.".format(p=args.period, c=args.config, k=e))
#!/usr/bin/env python3 import argparse import copy import datetime import importlib.resources as pkg_resources import pathlib import sys import yaml from generate_dates import TeachingCalendar, config, templates 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 = yaml.safe_load( pkg_resources.read_text(config, "default.yml")) 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 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 def run(): args = parse_command_line() if args.debug: print("DEBUG: args: {0}".format(args)) try: period_config, paper_config = parse_config(args.config, args) if args.debug: print("DEBUG: period config: {0}".format(period_config)) print("DEBUG: paper config: {0}".format(paper_config)) # priority: year on command line (defaults to current year), # year in config if period_config: args.year = ( args.config["year"] if "year" in args.config.keys() else args.year) cal = TeachingCalendar.TeachingCalendar( args.year, args.period, args.paper, period_config, paper_config) print("Period = {p}".format(p=args.period)) print(cal.calendar()) print(cal.lecture_dates()) except LectureStyleError as e: print("ERROR: 'lecture' style was requested but {c} contains no " "papers for {t}.".format(c=args.config, t=args.period)) except PaperError as e: print("ERROR: no entry in {c} for paper {p} ({t}).".format( c=args.config, p=args.paper, t=args.period)) except PeriodError as e: print("ERROR: no entry in {c} for teaching period " "{p}.".format(c=args.config_file, p=args.period)) except KeyError as e: print("ERROR: teaching period {p} in {c} is missing required " "key {k}.".format(p=args.period, c=args.config, k=e))
Ignore Space
Show notes
View
calendar/generate_dates/config/__init__.py
from generate_dates.config.cli import parse_command_line
Ignore Space
Show notes
View
calendar/generate_dates/config/cli.py
0 → 100644
import argparse import datetime import importlib.resources as pkg_resources import yaml from generate_dates import config 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 = yaml.safe_load( pkg_resources.read_text(config, "default.yml")) 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
Show line notes below