def get_or_create_semester(strm): if not (isinstance(strm, basestring) and strm.isdigit() and len(strm)==4): raise ValueError, "Bad strm: " + repr(strm) oldsem = Semester.objects.filter(name=strm) if oldsem: return oldsem[0] db = SIMSConn() db.execute("SELECT strm, term_begin_dt, term_end_dt FROM ps_term_tbl WHERE strm=%s", (strm,)) row = db.fetchone() if row is None: raise ValueError, "Not Found: %r" % (strm) strm, st, en = row # create Semester object st = datetime.datetime.strptime(st, "%Y-%m-%d").date() en = datetime.datetime.strptime(en, "%Y-%m-%d").date() sem = Semester(name=strm, start=st, end=en) sem.save() # also create SemesterWeek object for the first week first_monday = st while first_monday.weekday() != 0: first_monday += datetime.timedelta(days=1) wk = SemesterWeek(semester=sem, week=1, monday=first_monday) wk.save() return sem
def create_fake_semester(strm): """ Create a close-enough Semester object for testing """ strm = str(strm) if Semester.objects.filter(name=strm): return s = Semester(name=strm) yr = int(strm[0:3]) + 1900 if strm[3] == '1': mo = 1 elif strm[3] == '4': mo = 5 elif strm[3] == '7': mo = 9 s.start = datetime.date(yr, mo, 5) s.end = datetime.date(yr, mo + 3, 1) s.save() sw = SemesterWeek(semester=s, week=1) mon = s.start while mon.weekday() != 0: mon -= datetime.timedelta(days=1) sw.monday = mon sw.save() return s
def create_fake_semester(strm): """ Create a close-enough Semester object for testing """ strm = str(strm) if Semester.objects.filter(name=strm): return s = Semester(name=strm) yr = int(strm[0:3]) + 1900 if strm[3] == '1': mo = 1 elif strm[3] == '4': mo = 5 elif strm[3] == '7': mo = 9 s.start = datetime.date(yr,mo,5) s.end = datetime.date(yr,mo+3,1) s.save() sw = SemesterWeek(semester=s, week=1) mon = s.start while mon.weekday() != 0: mon -= datetime.timedelta(days=1) sw.monday = mon sw.save() return s
def test_semester_2(self): s = create_semester() wk = SemesterWeek(semester=s, week=1, monday=date(2007,9,3)) wk.save() wk = SemesterWeek(semester=s, week=5, monday=date(2007,10,8)) # pretend there is a Oct 1-5 break wk.save() # test due date calculations: convert date to week-of-semester and weekday (and back) tz = pytz.timezone('America/Vancouver') dt = datetime(2007, 9, 19, 23, 59, 59) self._test_due_date(s, dt, 3, 2) dt = datetime(2007, 11, 16, 16, 0, 0, tzinfo=tz) # timezone change between this and previous SemesterWeek self._test_due_date(s, dt, 10, 4) dt = datetime(2007, 11, 4, tzinfo=tz) # timezone change between this and previous Monday self._test_due_date(s, dt, 8, 6) dt = datetime(2007, 10, 10, tzinfo=tz) # right after a break self._test_due_date(s, dt, 5, 2) dt = datetime(2007, 10, 3, tzinfo=tz) # during a break # shouldn't be inverse function here: duedate always returns an in-semester date self._test_due_date(s, dt, 5, 2, reverse=datetime(2007,10,10, tzinfo=tz)) wk, wkday = s.week_weekday(date(2007, 10, 3)) self.assertEqual(wk, 5) self.assertEqual(wkday, 2) # check weird special-case for before-the-start dates self.assertEqual(s.week_weekday(date(2007, 9, 2)), (1, 0))
def test_semester(self): """ Create and test a semester object """ s = create_semester() wk = SemesterWeek(semester=s, week=1, monday=date(2007,9,3)) wk.save() wk = SemesterWeek(semester=s, week=5, monday=date(2007,10,8)) # pretend there is a Oct 1-5 break wk.save() self.assertEquals(s.label(), "Fall 2007") self.assertEquals(str(wk), "1077 week 5") # test semester arithmetic s = Semester.objects.get(name='1131') self.assertEqual(s.previous_semester().name, '1127') self.assertEqual(s.offset(1).name, '1134') self.assertEqual(s.offset(-1).name, '1127') self.assertEqual(s.offset(2).name, '1137') self.assertEqual(s.offset(-2).name, '1124') self.assertEqual(s - s.offset(-2), 2) self.assertEqual(s.offset(-2) - s, -2) self.assertEqual(s.offset_name(1), '1134') self.assertEqual(s.offset_name(-1), '1127') self.assertEqual(s.offset_name(2), '1137') self.assertEqual(s.offset_name(-2), '1124') self.assertEqual(s.offset_name(3), '1141') self.assertEqual(s.offset_name(-3), '1121') self.assertEqual(s.offset_name(4), '1144') self.assertEqual(s.offset_name(-4), '1117') s2 = Semester(name="1077", start=date(2007,9,4), end=date(2007,12,3)) self.assertRaises(IntegrityError, s2.save)
def import_semester_info(verbose=False, dry_run=False, long_long_ago=False, bootstrap=False): """ Update information on Semester objects from SIMS Finding the reference is tricky. Try Googling 'sfu calendar {{year}} "academic dates"' long_long_ago: import from the beginning of time bootstrap: don't assume Semester.current() will work, for bootstrapping test data creation """ output = [] semester_start = semester_first_day() semester_end = semester_last_day() sims_holidays = [(datetime.datetime.strptime(d, "%Y-%m-%d").date(), h) for d,h in all_holidays()] if not bootstrap: # we want semesters 5 years into the future: that's a realistic max horizon for grad promises current = Semester.current() strms = [current.offset_name(i) for i in range(15)] else: strms = [] if long_long_ago: strms = sorted(list(set(strms) | set(semester_start.keys()))) semesters = dict((s.name, s) for s in Semester.objects.filter(name__in=strms)) semester_weeks = itertools.groupby( SemesterWeek.objects.filter(semester__name__in=strms).select_related('semester'), lambda sw: sw.semester.name) semester_weeks = dict((k,list(v)) for k,v in semester_weeks) holidays = itertools.groupby( Holiday.objects.filter(semester__name__in=strms, holiday_type='FULL').select_related('semester'), lambda h: h.semester.name) holidays = dict((k,list(v)) for k,v in holidays) for strm in strms: url = settings.BASE_ABS_URL + reverse('sysadmin:edit_semester', kwargs={'semester_name': strm}) # Semester object try: semester = semesters[strm] except KeyError: semester = Semester(name=strm) semesters[strm] = semester output.append("Creating %s." % (strm,)) # class start and end dates try: start = datetime.datetime.strptime(semester_start[strm], "%Y-%m-%d").date() except KeyError: # No data found about this semester: if there's a date already around, honour it # Otherwise, guess "same day as this semester last year" which is probably wrong but close. start = semester.start if not semester.start: lastyr = semesters[semester.offset_name(-3)] start = lastyr.start.replace(year=lastyr.start.year+1) output.append("Guessing start date for %s." % (strm,)) try: end = datetime.datetime.strptime(semester_end[strm], "%Y-%m-%d").date() except KeyError: # no classes scheduled yet? Assume 13 weeks exactly end = start + datetime.timedelta(days=91) if semester.start != start: output.append("Changing start date for %s from %s to %s." % (strm, semester.start, start)) semester.start = start if semester.end != end: output.append("Changing end date for %s from %s to %s." % (strm, semester.end, end)) semester.end = end if not dry_run: semester.save() # SemesterWeeks weeks = semester_weeks.get(strm, []) if not weeks: sw = SemesterWeek(semester=semester, week=1, monday=first_monday(start)) weeks.append(sw) assert sw.monday.weekday() == 0 output.append("Creating week 1 for %s on %s." % (strm, sw.monday)) if not dry_run: sw.save() elif weeks[0].monday != first_monday(start): sw = weeks[0] sw.monday = first_monday(start) output.append("Changing first Monday of %s to %s." % (strm, sw.monday)) if not dry_run: sw.save() length = semester.end - semester.start if not bootstrap and length > datetime.timedelta(days=92) and len(weeks) < 2 \ and semester.start - datetime.date.today() < datetime.timedelta(days=365): # semester is longer than 13 weeks: insist that the user specify reading week reasonably-soon before the semester starts message = "Semester %s is long (%s) but has no reading week specified. Please have a look here: %s\n\nYou probably want to enter the Monday of week 5/6/7/8 as the Monday after reading week, a week later than it would otherwise be." % (strm, length, url) if verbose: output.append('*** ' + message) else: import_admin_email(source='coredata.importer.import_semester_info', message=message) elif not bootstrap: # also check that the last day of classes is at a coherent time. Might reveal problems with reading week specification. endweek,_ = semester.week_weekday(semester.end, weeks=weeks) if endweek not in [12, 13, 14]: message = "Semester %s ends in week %i (should be 13 or 14). That's weird. Have a look here to see if things are coherent: %s" % (strm, endweek, url) if verbose: output.append('*** ' + message) else: import_admin_email(source='coredata.importer.import_semester_info', message=message) # Holidays hs = holidays.get(strm, []) h_start, h_end = Semester.start_end_dates(semester) for dt, desc in [(d,h) for d,h in sims_holidays if h_start <= d <= h_end]: existing = [h for h in hs if h.date == dt] if existing: holiday = existing[0] else: holiday = Holiday(semester=semester, date=dt, holiday_type='FULL') output.append("Adding holiday %s on %s." % (desc, dt)) holiday.description = desc if not dry_run: holiday.save() if verbose: print '\n'.join(output)
def import_semester_info(verbose=False, dry_run=False, long_long_ago=False, bootstrap=False): """ Update information on Semester objects from SIMS Finding the reference is tricky. Try Googling 'sfu calendar {{year}} "academic dates"' long_long_ago: import from the beginning of time bootstrap: don't assume Semester.current() will work, for bootstrapping test data creation """ output = [] semester_start = semester_first_day() semester_end = semester_last_day() sims_holidays = all_holidays() if not bootstrap: # we want semesters 5 years into the future: that's a realistic max horizon for grad promises current = Semester.current() strms = [current.offset_name(i) for i in range(15)] else: strms = [] if long_long_ago: strms = sorted(list(set(strms) | set(semester_start.keys()))) semesters = dict((s.name, s) for s in Semester.objects.filter(name__in=strms)) semester_weeks = itertools.groupby( SemesterWeek.objects.filter(semester__name__in=strms).select_related('semester'), lambda sw: sw.semester.name) semester_weeks = dict((k,list(v)) for k,v in semester_weeks) holidays = itertools.groupby( Holiday.objects.filter(semester__name__in=strms, holiday_type='FULL').select_related('semester'), lambda h: h.semester.name) holidays = dict((k,list(v)) for k,v in holidays) for strm in strms: url = settings.BASE_ABS_URL + reverse('sysadmin:edit_semester', kwargs={'semester_name': strm}) # Semester object try: semester = semesters[strm] except KeyError: semester = Semester(name=strm) semesters[strm] = semester output.append("Creating %s." % (strm,)) # class start and end dates try: start = semester_start[strm] except KeyError: # No data found about this semester: if there's a date already around, honour it # Otherwise, guess "same day as this semester last year" which is probably wrong but close. start = semester.start if not semester.start: lastyr = semesters[semester.offset_name(-3)] start = lastyr.start.replace(year=lastyr.start.year+1) output.append("Guessing start date for %s." % (strm,)) try: end = semester_end[strm] except KeyError: # no classes scheduled yet? Assume 13 weeks exactly end = start + datetime.timedelta(days=91) if semester.start != start: output.append("Changing start date for %s from %s to %s." % (strm, semester.start, start)) semester.start = start if semester.end != end: output.append("Changing end date for %s from %s to %s." % (strm, semester.end, end)) semester.end = end if not dry_run: semester.save() # SemesterWeeks weeks = semester_weeks.get(strm, []) if not weeks: sw = SemesterWeek(semester=semester, week=1, monday=first_monday(start)) weeks.append(sw) assert sw.monday.weekday() == 0 output.append("Creating week 1 for %s on %s." % (strm, sw.monday)) if not dry_run: sw.save() elif weeks[0].monday != first_monday(start): sw = weeks[0] sw.monday = first_monday(start) output.append("Changing first Monday of %s to %s." % (strm, sw.monday)) if not dry_run: sw.save() length = semester.end - semester.start if not bootstrap and length > datetime.timedelta(days=92) and len(weeks) < 2 \ and semester.start - datetime.date.today() < datetime.timedelta(days=365): # semester is longer than 13 weeks: insist that the user specify reading week reasonably-soon before the semester starts message = "Semester %s is long (%s) but has no reading week specified. Please have a look here: %s\n\nYou probably want to enter the Monday of week 5/6/7/8 as the Monday after reading week, a week later than it would otherwise be." % (strm, length, url) if verbose: output.append('*** ' + message) else: import_admin_email(source='coredata.importer.import_semester_info', message=message) elif not bootstrap: # also check that the last day of classes is at a coherent time. Might reveal problems with reading week specification. endweek,_ = semester.week_weekday(semester.end, weeks=weeks) if endweek not in [12, 13, 14]: message = "Semester %s ends in week %i (should be 13 or 14). That's weird. Have a look here to see if things are coherent: %s" % (strm, endweek, url) if verbose: output.append('*** ' + message) else: import_admin_email(source='coredata.importer.import_semester_info', message=message) # Holidays hs = holidays.get(strm, []) h_start, h_end = Semester.start_end_dates(semester) for dt, desc in [(d,h) for d,h in sims_holidays if h_start <= d <= h_end]: existing = [h for h in hs if h.date == dt] if existing: holiday = existing[0] else: holiday = Holiday(semester=semester, date=dt, holiday_type='FULL') output.append("Adding holiday %s on %s." % (desc, dt)) holiday.description = desc if not dry_run: holiday.save() if verbose: print('\n'.join(output))