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
Initialisation of ignored CLI args moved to cli.py
master
1 parent
8356d93
commit
b4b2e1ba9f6a6eb6dc603baa9b2d4f33c794839b
Nigel Stanger
authored
on 29 Nov 2019
Patch
Showing
2 changed files
calendar/teachingdates/calendars/basecalendar.py
calendar/teachingdates/config/cli.py
Ignore Space
Show notes
View
calendar/teachingdates/calendars/basecalendar.py
import calendar import datetime from teachingdates import PROG from .weeks import BreakWeek, IsoWeek, TeachingWeek class TeachingCalendar(): """This class generates teaching-related dates for a specific paper offered in a specific teaching period of a specific year. If you don't provide teaching period details, it generates dates for the current ISO-8601 year. """ weeks = [] lecture_offsets = [] skipped_lectures = [] mondays = [] period = None paper = None year = datetime.date.today().year def __init__(self, year, period, paper, period_config=None, paper_config=None): self.year = year self.period = period self.paper = paper # This is likely to end up with one week too many at the end, # but that doesn't matter as there will never be any teaching # during the last week of December! cal = calendar.Calendar().yeardatescalendar(self.year, width=12) self.mondays = [week[0] for month in cal[0] for week in month] self.mondays = list(dict.fromkeys(self.mondays)) if period_config: self.update_weeks(period_config["weeks"]) else: last_week = datetime.date(self.year, 12, 28).isocalendar()[1] self.update_weeks([{"iso": [1, last_week]}]) if paper_config: self.update_lectures(paper_config["lectures"]) @classmethod def from_configuration(cls, config): if config: return cls(config.year, config.period, config.paper, config.get_period_config(), config.get_paper_config()) else: return None def make_week(self, week_type, start, end=None): end = start if end is None else end return [ week_type(self.mondays[w].year, self.mondays[w].month, self.mondays[w].day) for w in range(start - 1, end) ] def teaching_date(self, period, week, offset=0): pass def update_weeks(self, week_list): for w in week_list: for t, r in w.items(): if t == "teach": self.weeks += self.make_week(TeachingWeek, r[0], r[1]) elif t == "break": self.weeks += self.make_week(BreakWeek, r[0], r[1]) elif t == "iso": self.weeks += self.make_week(IsoWeek, r[0], r[1]) else: print("{prog}: warning: ignored unknown week type " "'{type}'.".format(prog=PROG, type=t)) def update_lectures(self, lecture_list): for l in lecture_list: for t, v in l.items(): if t == "offsets": self.lecture_offsets = v elif t == "skip": self.skipped_lectures = v else: print("{prog}: warning: ignored unknown lecture key " "'{key}'.".format(prog=PROG, key=t)) # turn this into a generator? def calendar(self): period = {} week_num = break_num = 0 for w in self.weeks: if isinstance(w, (TeachingWeek, IsoWeek)): # Increment first so that break weeks have the # same week number as the preceding teaching week. # This ensures the keys are always chronologically # sorted. Reset the break number for each new # teaching week. week_num += 1 break_num = 0 period[week_num] = w elif isinstance(w, BreakWeek): # Allow for up to 99 consecutive break weeks, # which should be sufficient :). Should probably # throw an exception if we exceed that. break_num += 0.01 period[week_num + break_num] = w return period # turn this into a generator? def lecture_dates(self): dates = {} lecture_num = 1 teaching_weeks = [t for t in self.weeks if isinstance(t, TeachingWeek)] for week_index, monday in enumerate(teaching_weeks): for offset_index, offset in enumerate(self.lecture_offsets): lec = week_index * 2 + offset_index + 1 if lec in self.skipped_lectures: continue dates[lecture_num] = monday + datetime.timedelta(offset) lecture_num += 1 return dates def render(self, style, fmt): if fmt == "text": return(self.render_text(style)) elif fmt == "latex": return(self.render_latex(style)) elif fmt == "xml": return(self.render_xml(style)) else: return("") def render_text(self, style): # probably cleaner to create Jinja templates? if style == "calendar": yield "# Teaching calendar for {period} {year}".format( period=self.period, year=self.year) for weeknum, monday in self.calendar().items(): if isinstance(monday, TeachingWeek): yield "Week {week}: {mon} — {fri}".format( week=str(weeknum).rjust(2), mon=monday.isoformat(), fri=monday + datetime.timedelta(days=4)) elif isinstance(monday, BreakWeek): yield "Break : {mon} — {fri}".format( mon=monday.isoformat(), fri=monday + datetime.timedelta(days=4)) else: yield ("") elif style == "lecture": yield "# Lecture dates for {paper} {period} {year}".format( paper=self.paper, period=self.period, year=self.year) for lecnum, day in self.lecture_dates().items(): yield "Lecture {lecture}: {day}".format( lecture=str(lecnum).rjust(2), day=day.isoformat()) else: yield("") def render_latex(self, style): if style == "calendar": pass elif style == "lecture": pass else: return("") def render_xml(self, style): if style == "calendar": pass elif style == "lecture": pass else: return("")
import calendar import datetime from teachingdates import PROG from .weeks import BreakWeek, IsoWeek, TeachingWeek class TeachingCalendar(): """This class generates teaching-related dates for a specific paper offered in a specific teaching period of a specific year. If you don't provide teaching period details, it generates dates for the current ISO-8601 year. """ weeks = [] lecture_offsets = [] skipped_lectures = [] mondays = [] period = "iso" year = datetime.date.today().year def __init__(self, year, period, paper, period_config=None, paper_config=None): self.year = year self.period = period self.paper = paper # This is likely to end up with one week too many at the end, # but that doesn't matter as there will never be any teaching # during the last week of December! cal = calendar.Calendar().yeardatescalendar(self.year, width=12) self.mondays = [week[0] for month in cal[0] for week in month] self.mondays = list(dict.fromkeys(self.mondays)) if period_config: self.update_weeks(period_config["weeks"]) else: last_week = datetime.date(self.year, 12, 28).isocalendar()[1] self.update_weeks([{"iso": [1, last_week]}]) if paper_config: self.update_lectures(paper_config["lectures"]) @classmethod def from_configuration(cls, config): if config: return cls(config.year, config.period, config.paper, config.get_period_config(), config.get_paper_config()) else: return None def make_week(self, week_type, start, end=None): end = start if end is None else end return [ week_type(self.mondays[w].year, self.mondays[w].month, self.mondays[w].day) for w in range(start - 1, end) ] def teaching_date(self, period, week, offset=0): pass def update_weeks(self, week_list): for w in week_list: for t, r in w.items(): if t == "teach": self.weeks += self.make_week(TeachingWeek, r[0], r[1]) elif t == "break": self.weeks += self.make_week(BreakWeek, r[0], r[1]) elif t == "iso": self.weeks += self.make_week(IsoWeek, r[0], r[1]) else: print("{prog}: warning: ignored unknown week type " "'{type}'.".format(prog=PROG, type=t)) def update_lectures(self, lecture_list): for l in lecture_list: for t, v in l.items(): if t == "offsets": self.lecture_offsets = v elif t == "skip": self.skipped_lectures = v else: print("{prog}: warning: ignored unknown lecture key " "'{key}'.".format(prog=PROG, key=t)) # turn this into a generator? def calendar(self): period = {} week_num = break_num = 0 for w in self.weeks: if isinstance(w, (TeachingWeek, IsoWeek)): # Increment first so that break weeks have the # same week number as the preceding teaching week. # This ensures the keys are always chronologically # sorted. Reset the break number for each new # teaching week. week_num += 1 break_num = 0 period[week_num] = w elif isinstance(w, BreakWeek): # Allow for up to 99 consecutive break weeks, # which should be sufficient :). Should probably # throw an exception if we exceed that. break_num += 0.01 period[week_num + break_num] = w return period # turn this into a generator? def lecture_dates(self): dates = {} lecture_num = 1 teaching_weeks = [t for t in self.weeks if isinstance(t, TeachingWeek)] for week_index, monday in enumerate(teaching_weeks): for offset_index, offset in enumerate(self.lecture_offsets): lec = week_index * 2 + offset_index + 1 if lec in self.skipped_lectures: continue dates[lecture_num] = monday + datetime.timedelta(offset) lecture_num += 1 return dates def render(self, style, fmt): if fmt == "text": return(self.render_text(style)) elif fmt == "latex": return(self.render_latex(style)) elif fmt == "xml": return(self.render_xml(style)) else: return("") def render_text(self, style): # probably cleaner to create Jinja templates? if style == "calendar": yield "# Teaching calendar for {period} {year}".format( period=self.period, year=self.year) for weeknum, monday in self.calendar().items(): if isinstance(monday, TeachingWeek): yield "Week {week}: {mon} — {fri}".format( week=str(weeknum).rjust(2), mon=monday.isoformat(), fri=monday + datetime.timedelta(days=4)) elif isinstance(monday, BreakWeek): yield "Break : {mon} — {fri}".format( mon=monday.isoformat(), fri=monday + datetime.timedelta(days=4)) else: yield ("") elif style == "lecture": yield "# Lecture dates for {paper} {period} {year}".format( paper=self.paper, period=self.period, year=self.year) for lecnum, day in self.lecture_dates().items(): yield "Lecture {lecture}: {day}".format( lecture=str(lecnum).rjust(2), day=day.isoformat()) else: yield("") def render_latex(self, style): if style == "calendar": pass elif style == "lecture": pass else: return("") def render_xml(self, style): if style == "calendar": pass elif style == "lecture": pass else: return("")
Ignore Space
Show notes
View
calendar/teachingdates/config/cli.py
import argparse import datetime from teachingdates import PROG 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=PROG, description="") parser.add_argument( "--config", "-c", default=None, dest="config_file", help="file name of the configuration file " "[default '~/.config/{prog}/config.yml']".format(prog=PROG)) 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] if args.style == "calendar": # --paper is irrelevant if args.paper: args.paper = "" print("{prog}: warning: --paper/-p is ignored for 'calendar' " "style".format(prog=PROG)) # --teaching-period is required if not args.period: parser.exit( 2, "{prog}: error: --teaching-period/-t is required for " "'calendar' style\n".format(prog=PROG)) elif args.style == "iso": # both --paper and --teaching-period are irrelevant if args.paper or args.period: args.paper = "" args.period = "iso" print("{prog}: warning: --paper/-p and --teaching-period/-t are " "ignored for 'iso' style".format(prog=PROG)) elif args.style == "lecture": # both --paper and --teaching-period are required if not args.paper: parser.exit( 2, message="{prog}: error: -paper/-p and --teaching-period/-t " "are required for 'lecture' style\n".format(prog=PROG)) else: pass return args
import argparse import datetime from teachingdates import PROG 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=PROG, description="") parser.add_argument( "--config", "-c", default=None, dest="config_file", help="file name of the configuration file " "[default '~/.config/{prog}/config.yml']".format(prog=PROG)) 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] if args.style == "calendar": # --paper is irrelevant if args.paper: print("{prog}: warning: --paper/-p is ignored for 'calendar' " "style".format(prog=PROG)) # --teaching-period is required if not args.period: parser.exit( 2, "{prog}: error: --teaching-period/-t is required for " "'calendar' style\n".format(prog=PROG)) elif args.style == "iso": # both --paper and --teaching-period are irrelevant if args.paper or args.period: print("{prog}: warning: --paper/-p and --teaching-period/-t are " "ignored for 'iso' style".format(prog=PROG)) elif args.style == "lecture": # both --paper and --teaching-period are required if not args.paper: parser.exit( 2, message="{prog}: error: -paper/-p and --teaching-period/-t " "are required for 'lecture' style\n".format(prog=PROG)) else: pass return args
Show line notes below