def get_plot(self): popularity = [x.popularity for x in self.terms] trace1 = go.Bar( x=list(range(len(self.terms))), y=popularity, name='terms', marker=dict( showscale=True, colorscale=[[0, 'rgb(200,200,200)'], [0.95, 'rgb(100,100,150)'], [1, 'rgb(200, 0, 0)']], cmax=1, cmin=0, color=[1 if x.public else float(x.popularity) / Term.average_popularity() for x in self.terms], ), text=[x.name + ', ' + ('public' if x.public else '{}% not enough to be public'.format( round(100 - float(x.popularity) / Term.average_popularity() * 100, 2))) for x in self.terms] ) trace2 = go.Scatter( x=[-1, len(self.terms)], y=[Term.average_popularity()] * 2, name='average', ) data = [trace1, trace2] layout = go.Layout( title='Popularity', xaxis=dict(title='Terms'), yaxis=dict(title='Popularity'), showlegend=False, ) fig = go.Figure(data=data, layout=layout) plot_ = plot(fig, **Chart.default_args) return plot_
def get_context_data(self, **kwargs): ctx = super(InterimIntentionsView, self).get_context_data(**kwargs) admin, created = InterimIntentionsAdmin.objects.get_or_create( term=Term.current_term()) interim_itineraries_forms = [] if self.request.method == 'POST': interim_itineraries_forms = self.update_interim_itinerary( interim_intentions=self.get_object(), data=self.request.POST.copy()) elif self.request.method == 'GET': interim_itineraries = InterimItinerary.objects.filter( interim_intentions=self.get_object()).order_by('start') if interim_itineraries.count() == 0: interim_itineraries_forms.append(InterimItineraryForm()) else: for itin in interim_itineraries: interim_itineraries_forms.append( InterimItineraryForm(instance=itin)) ctx['button_label'] = 'Submit' ctx['page_title'] = 'Interim Intentions' ctx['itinerary_forms'] = interim_itineraries_forms ctx['interim_start'] = Term.current_term().end + timedelta(days=1) ctx['interim_end'] = admin.term_begin_date - timedelta(days=1) ctx['admin'] = admin return ctx
def get_queryset(self, request): qs = super(RollAdmin, self).get_queryset(request) if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return qs.filter(date__gte=start_date, date__lte=end_date) return qs
def get_context_data(self, **kwargs): context = super(QuestionList, self).get_context_data(**kwargs) trainee = trainee_from_user(self.request.user) if is_TA(self.request.user) or (trainee.firstname == 'Tobi' and trainee.lastname == 'Abosede') or ( trainee.firstname == 'Sofia' and trainee.lastname == 'Hunter'): faqs = HouseInspectionFaq.objects.none() for status in ['U', 'A', 'An', 'D']: faqs = chain( faqs, HouseInspectionFaq.objects.filter(status=status).filter( date_assigned__gte=Term.current_term().get_date(0, 0)). order_by('date_assigned').order_by('status')) context['faqs'] = faqs if not is_TA(self.request.user) and ( trainee.firstname != 'Tobi' or trainee.lastname != 'Abosede' ) and (trainee.firstname != 'Sofia' or trainee.lastname != 'Hunter'): faqs = HouseInspectionFaq.objects.none() for status in ['A']: faqs = chain( faqs, HouseInspectionFaq.objects.filter(status=status).filter( date_assigned__gte=Term.current_term().get_date( 0, 0)).order_by('date_assigned')) context['faqs'] = faqs return context
def get_queryset(self): queryset = super(AnnouncementManager, self).get_queryset() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return queryset.filter(date_requested__gte=start_date, date_requested__lte=end_date).distinct() else: return queryset
def get_queryset(self): queryset = super(IndividualSlipManager, self).get_queryset() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return queryset.filter(rolls__date__gte=start_date, rolls__date__lte=end_date).distinct() else: return queryset
def get_queryset(self): queryset = super(GroupSlipManager, self).get_queryset() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return queryset.filter(start__gte=start_date, end__lte=end_date) else: return queryset
def get_queryset(self): queryset = super(SummaryManager, self).get_queryset() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return queryset.filter(date_submitted__gte=start_date, date_submitted__lte=end_date).distinct() else: return queryset
def periods(self): rolls = self.rolls.order_by('date') if rolls.count() < 1: return list() first_roll = rolls.first() last_roll = rolls.last() first_period = Term.current_term().period_from_date(first_roll.date) last_period = Term.current_term().period_from_date(last_roll.date) return range(first_period, last_period + 1)
def get_queryset(self): queryset = super(ClassnotesManager, self).get_queryset() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end return queryset.filter(date_assigned__gte=start_date, date_assigned__lte=end_date).distinct() else: return queryset
def finalizeStatus(request): my_user = request.user if request.is_ajax(): action = request.POST['action'] week_id = request.POST['week_id'] forced = request.POST.get('forced', False) current_term = Term.current_term() term_id = current_term.id term_week_code = str(term_id) + "_" + str(week_id) now = datetime.date.today() lastDayofWeek = Term.enddate_of_week(current_term, int(week_id)) WedofNextWeek = lastDayofWeek + datetime.timedelta(days=3) # if not TA, cannot finalize till right time. if is_trainee(my_user): if forced: pass elif now >= WedofNextWeek or now < lastDayofWeek: return HttpResponse('Cannot finalize now', status=400) if is_TA(my_user): my_user = Trainee.objects.get(pk=request.POST['userId']) try: trainee_bible_reading = BibleReading.objects.get(trainee=my_user) except BibleReading.ObjectDoesNotExist: trainee_bible_reading = BibleReading( trainee=my_user, weekly_reading_status={term_week_code: EMPTY_WEEK_CODE_QUERY}, books_read={}) if term_week_code not in trainee_bible_reading.weekly_reading_status: trainee_bible_reading.weekly_reading_status[ term_week_code] = EMPTY_WEEK_CODE_QUERY trainee_weekly_reading = trainee_bible_reading.weekly_reading_status[ term_week_code] json_weekly_reading = json.loads(trainee_weekly_reading) if action == "finalize" and str( json_weekly_reading['finalized']) == FINALIZED_STR: return HttpResponse("Already finalized, so cannot finalize.", status=400) if action == "finalize": json_weekly_reading['finalized'] = FINALIZED_STR if action == "unfinalize": json_weekly_reading['finalized'] = UNFINALIZED_STR hstore_weekly_reading = json.dumps(json_weekly_reading) trainee_bible_reading.weekly_reading_status[ term_week_code] = hstore_weekly_reading trainee_bible_reading.save() return HttpResponse("Successfully saved")
def unfinalized_week(user): current_term = Term.current_term() if date.today() < current_term.start: return None # current week = up to week we want to access + 1 current_week = Term.reverse_date(current_term, date.today())[0] if date.today() <= current_term.startdate_of_week(current_week) + timedelta(1): # Cannot access past week's because today is less than Wednesday current_week = current_week - 1 for week in range(0, current_week): if not is_week_finalized(user, week): return week return None
def _change_to_single_roll_system(self): rolls = Roll.objects.all() if Term.current_term(): start_date = Term.current_term().start end_date = Term.current_term().end rolls = rolls.filter(date__gte=start_date, date__lte=end_date) rolls = list(rolls) i = 0 while rolls: roll = rolls[i] trainee = roll.trainee event = roll.event date = roll.date duplicates = Roll.objects.filter(trainee=trainee, event=event.id, date=date) if duplicates.count() == 1: dup = duplicates.first() if dup.submitted_by != trainee: dup.submitted_by = trainee dup.save() else: trainee_roll = duplicates.filter(submitted_by=trainee) TA_roll = duplicates.filter(submitted_by__in=TAS) AM_roll = duplicates.filter(submitted_by__in=AMS) if trainee_roll.count() == 1 and TA_roll.count( ) == 1 and AM_roll.count() == 0: if TA_roll[0].last_modified >= trainee_roll[ 0].last_modified: print "Deleting:", trainee_roll[0].id, trainee_roll[ 0].submitted_by, trainee_roll[0].trainee trainee_roll.delete() else: print "Deleting:", TA_roll[0].id, TA_roll[ 0].submitted_by, TA_roll[0].trainee TA_roll.delete() elif (trainee_roll.count() == 1 and TA_roll.count() == 0 and AM_roll.count() == 1) or \ (trainee_roll.count() == 0 and TA_roll.count() == 1 and AM_roll.count() == 1): print "Deleting:", AM_roll[0].id, AM_roll[ 0].submitted_by, AM_roll[0].trainee AM_roll.delete() elif trainee_roll.count() == 1 and TA_roll.count( ) == 1 and AM_roll.count() == 1: print "Check the rolls related to:", trainee_roll[0].event else: #there should only be one of each max print "Check the rolls related to:", trainee_roll[0].event rolls.pop()
def get_queryset(self): user_has_service = self.request.user.groups.filter( name__in=['facility_maintenance', 'linens', 'frames']).exists() if is_TA(self.request.user) or user_has_service: qs = self.model.objects.filter(status='P').filter( date_requested__gte=Term.current_term().get_date( 0, 0)) | self.model.objects.filter(status='F').filter( date_requested__gte=Term.current_term().get_date(0, 0)) return qs.order_by('date_requested') else: trainee = self.request.user return self.model.objects.filter(trainee_author=trainee).filter( date_requested__gte=Term.current_term().get_date( 0, 0)).order_by('status')
def filter_list(self, week, trainee): term = Term.current_term() # return pre-training recordings if week == 0: return filter(lambda f: f.code == 'PT', self.filter_term(term)) # also filters year: if not a class with a Y1/Y2 designation or if the class year matches trainee's year, add file to files list return filter(lambda f: f.week == week and f.can_trainee_view(trainee), self.filter_term(term))
def get_context_data(self, **kwargs): context = super(SpeakingReport, self).get_context_data(**kwargs) speaking_trainees = GradAdmin.objects.get(term=Term.current_term()).speaking_trainees.all() context['data'] = Outline.objects.filter(trainee__in=speaking_trainees) context['title'] = 'Speaking Report' return context
class GroupSlipsJSON(BaseDatatableView): model = GroupSlip columns = [ 'id', 'trainee', 'submitted', 'trainees', 'description', 'status', 'service_assignment', 'start', 'end' ] order_columns = [ 'id', 'trainee', 'submitted', '', 'description', 'status', 'service_assignment', 'start', 'end' ] max_display_length = 200 which_url = 'get_admin_url' term = Term.current_term() def filter_queryset(self, qs): qs = qs.filter(start__gte=self.term.start, end__lte=self.term.end) search = self.request.GET.get(u'search[value]', None) qs_params = Q() ret = qs.none() if search: for exp in search.split(): try: q = Q(id__icontains=exp) | Q( service_assignment__service__name__icontains=exp) qs_params = qs_params & q if q else qs_params except ValueError: continue ret = ret | qs.filter(qs_params).distinct() return ret else: return qs
class LeaveSlipsJSON(BaseDatatableView): model = IndividualSlip fields = ['id', 'trainee', 'rolls', 'status', 'TA', 'type'] columns = fields order_columns = fields max_display_length = 200 which_url = 'get_admin_url' term = Term.current_term() def filter_queryset(self, qs): qs = qs.filter(rolls__date__gte=self.term.start, rolls__date__lte=self.term.end) search = self.request.GET.get(u'search[value]', None) qs_params = Q() ret = qs.none() if search: for exp in search.split(): try: q = Q(trainee__firstname__icontains=exp) | Q(trainee__lastname__icontains=exp) | Q(id__icontains=exp) | \ Q(type__icontains=exp) | Q(rolls__event__name__icontains=exp) | Q(rolls__event__id__icontains=exp) | Q(rolls__id__icontains=exp) qs_params = qs_params & q if q else qs_params except ValueError: continue ret = ret | qs.filter(qs_params).distinct() return ret else: return qs
def import_csvfile(file_path): # sanity check localities, teams, residences = check_csvfile(file_path) if localities or teams or residences: return False log.info("Beginning CSV File Import") # TODO(import2): Remove this # count = 0; with open(file_path, 'r') as f: reader = csv.DictReader(f) for row in reader: # count = count + 1 # if count > 10: # return import_row(row) term = Term.current_term() schedules = Schedule.objects.filter(term=term) # TODO(import2) -- this needs to be smarter eventually for schedule in schedules: schedule.assign_trainees_to_schedule() log.info("Import complete") return True
def create(self, validated_data): if validated_data.get("id"): #this is pretty naive and inefficient, needs to be optimized later chart = Chart.objects.get(pk=validated_data.get("id")) seats = Seat.objects.filter(chart=chart).delete() chart.width = validated_data.get("width") chart.height = validated_data.get("height") chart.name = validated_data.get("name") chart.save() seats = validated_data.pop('trainees') print seats for y in range(0, validated_data.get('height')): for x in range(0, validated_data.get('width')): if seats[y][x] != {} and seats[y][x].get('pk') != '': trainee = Trainee.objects.get(pk=seats[y][x]['pk']) s = Seat(trainee=trainee, chart=chart, x=x, y=y) s.save() return chart seats = validated_data.pop('trainees') print seats validated_data['term'] = Term.current_term() new_chart = Chart.objects.create(**validated_data) for y in range(0, validated_data.get('height')): for x in range(0, validated_data.get('width')): if seats[y][x] != {} and seats[y][x].get('pk') != '': trainee = Trainee.objects.get(pk=seats[y][x]['pk']) s = Seat(trainee=trainee, chart=new_chart, x=x, y=y) s.save() return new_chart
def post(self, request, *args, **kwargs): survey_admin = self.admin_model.objects.get_or_create( term=Term.current_term())[0] recommended_hcs = request.POST.getlist("recommended_hc") choices = request.POST.getlist("choice") recommendations = request.POST.getlist("recommendation") for i in range(len(recommended_hcs)): form_data = {} form_data['recommended_hc'] = Trainee.objects.get( id=recommended_hcs[i]) form_data['choice'] = choices[i] form_data['recommendation'] = recommendations[i] check_existing = HCRecommendation.objects.filter( survey_admin=survey_admin, recommended_hc=form_data["recommended_hc"]) if check_existing.count() != 0: # if existing then delete and make new ones, don't bother editing # not the safest thing in the world but this is a low risk module so yeah. check_existing.delete() hcr = HCRecommendation(**form_data) hcr.survey_admin = survey_admin hcr.hc = self.request.user hcr.house = self.request.user.house hcr.save() return HttpResponseRedirect(reverse_lazy('hc:hc-recommendation'))
def get_context_data(self, **kwargs): ctx = super(HCSurveyAdminCreate, self).get_context_data(**kwargs) term = Term.current_term() hcra = HCRecommendationAdmin.objects.get_or_create(term=term)[0] if HCSA_FORM not in ctx: ctx[HCSA_FORM] = self.form_class(auto_id="hcsa_%s") if HCRA_FORM not in ctx: ctx[HCRA_FORM] = self.second_form_class(instance=hcra, auto_id="hcra_%s") ctx['hc_admins'] = HCSurveyAdmin.objects.filter( term=term).order_by('-index') init_open_datetime = hcra.open_time init_close_datetime = hcra.close_time if init_open_datetime is None or init_close_datetime is None: ctx['button_label2'] = 'Create Recommendation' else: ctx['init_open_datetime'] = init_open_datetime.strftime( "%m/%d/%Y %H:%M") ctx['init_close_datetime'] = init_close_datetime.strftime( "%m/%d/%Y %H:%M") ctx['button_label2'] = 'Update Recommendation' ctx['button_label1'] = 'Create Survey' ctx['page_title'] = 'HC Survey Admin' return ctx
def get_context_data(self, **kwargs): ctx = super(HCRecommendationCreate, self).get_context_data(**kwargs) survey_admin = self.admin_model.objects.get_or_create( term=Term.current_term())[0] house = House.objects.get(id=self.request.user.house.id) eligible_hcs = house.residents.exclude(groups__name="HC").filter( current_term__in=[2, 3]) hc_recommendation_forms = [] for trainee in eligible_hcs: try: hcr = HCRecommendation.objects.get(recommended_hc=trainee, survey_admin=survey_admin) hcr_form = HCRecommendationForm(house=house, instance=hcr) except HCRecommendation.DoesNotExist: hcr_form = HCRecommendationForm( house=house, initial={'recommended_hc': trainee}) hc_recommendation_forms.append(hcr_form) ctx['button_label'] = 'Submit' ctx['page_title'] = 'HC Recommendation' ctx['hc'] = Trainee.objects.get(id=self.request.user.id) ctx['house'] = house ctx['hc_recommendation_forms'] = hc_recommendation_forms # if survey is open, but not within time range -> read-only if (datetime.now() > survey_admin.close_time or datetime.now() < survey_admin.open_time) and survey_admin.open_survey: ctx['read_only'] = True return ctx
def clean(self): data = self.cleaned_data trainees = data['trainees'] interested_schedules = Schedule.objects.filter(trainees__in=trainees).exclude(priority__gt=int(data['priority'])).exclude(trainee_select='GP') interested_eventsList = list(interested_schedules.values('events__id', 'events__start', 'events__end', 'events__weekday')) events = data['events'] events_weekday = set(events.values_list('weekday', flat=True)) event_ids = [] for ev in interested_eventsList: if ev['events__weekday'] in events_weekday: for event in events: if event.start <= ev['events__start'] <= event.end or event.start <= ev['events__end'] <= event.end or (ev['events__start'] <= event.start and ev['events__end'] >= event.end): event_ids.append(ev['events__id']) break weeks = data['weeks'] weeks = weeks.split(',') current_term = Term.current_term() ### The next set of code is to find and delete rolls if someone is inputting new events in the middle of the term. # The old solution of using "date__range=[start_date, end_date]" for the Roll.objects.filter only works with the assumption # that trainee events are continuous throughout the term. So in the case if a trainee event is every other week, then roll objects will need to be deleted # even if the selected week isn't chosen. # E.g. Weeks 2,4,6,8 - so anything between 2 through 8 would be deleted, including weeks 3,4,7 even though they're not included. ### Put weeks chosen for an event in a group, then add them to a list. # This is based off of "https://docs.python.org/2.6/library/itertools.html#examples" # and explicitly copied from an answer "https://stackoverflow.com/questions/2154249/identify-groups-of-continuous-numbers-in-a-list" # Order of the numbering matters for this solution (in our case, it's already ordered). week_ranges = [] for k, g in groupby(enumerate(weeks), lambda (i,x):int(i)-int(x)): group = map(itemgetter(1), g) week_ranges.append((group[0], group[-1]))
def migrate_seating_charts(): term = Term.current_term() term_minus_one = term_before(term) charts = Chart.objects_all.filter(term=term_minus_one) for chart in charts: migrate_seating_chart(chart, term)
def immediate_upcoming_event(self, time_delta=15, with_seating_chart=False): # Code for debugging # Turn this boolean to test locally and receive valid event on page load every time test_ev_with_chart = False if test_ev_with_chart: from schedules.models import Event ev = Event.objects.filter(chart__isnull=False)[0] date = ev.date_for_week(3) # calc date from w ev.start_datetime = datetime.combine(date, ev.start) ev.end_datetime = datetime.combine(date, ev.end) return [ev, ] # Actual code starts below schedules = self.active_schedules c_time = datetime.now() delay = timedelta(minutes=time_delta) start_time = c_time + delay end_time = c_time - delay c_term = Term.current_term() weeks = set([int(c_term.term_week_of_date(c_time.date()))]) w_tb = OrderedDict() for schedule in schedules: evs = schedule.events.filter(Q(weekday=c_time.weekday()) | Q(day=c_time.date())).filter(start__lte=start_time, end__gte=end_time) if with_seating_chart: evs = evs.filter(chart__isnull=False) schedule_weeks = set(map(int, schedule.weeks.split(','))) w_tb = EventUtils.compute_prioritized_event_table(w_tb, weeks & schedule_weeks, evs, schedule.priority) # print w_tb return EventUtils.export_event_list_from_table(w_tb)
def get_context_data(self, **kwargs): context = super(ClassnotesAssignView, self).get_context_data(**kwargs) term = Term.current_term() week = term.term_week_of_date(datetime.now().date()) context['weekinit'] = str(week) context['week_range'] = [str(i) for i in range(20)] return context
def get_context_data(self, **kwargs): ctx = super(HCSurveyAdminCreate, self).get_context_data(**kwargs) term = Term.current_term() ctx['hc_admins'] = HCSurveyAdmin.objects.filter( term=term).order_by('-index') ctx['hcra_form'] = HCRecommendationAdminForm() ctx['hcsa_form'] = ctx['form'] init_open_datetime = HCRecommendationAdmin.objects.get_or_create( term=term)[0].open_time init_close_datetime = HCRecommendationAdmin.objects.get_or_create( term=term)[0].close_time if init_open_datetime is None or init_close_datetime is None: ctx['button_label2'] = 'Create Recommendation' else: ctx['init_open_datetime'] = init_open_datetime.strftime( "%m/%d/%Y %H:%M") ctx['init_close_datetime'] = init_close_datetime.strftime( "%m/%d/%Y %H:%M") ctx['button_label2'] = 'Update Recommendation' ctx['button_label1'] = 'Create Survey' ctx['page_title'] = 'HC Survey Admin' return ctx
def fetch_terms(self, verbose=False): """ Get all terms. Parameters: ----------- verbose : bool [default False] Whether or not to show messages throughout the process of fetching terms. """ response = requests.get(url=TERMS_URL) root = ElementTree.fromstring(response.text.encode('utf-8')) current_term_code = root.attrib['currentTerm'] terms = set([(t.semester, t.year) for t in Term.objects.all()]) for term_el in root[-3:]: code = term_el.attrib['code'] term = Term.from_code(code) query = Term.objects.filter(semester=term.semester, year=term.year) if query.exists(): term = query.first() term.current = code == current_term_code term.save() key = (term.semester, term.year) if key in terms: terms.remove(key) if verbose: self.stdout.write('Fetched term %s' % term) # Remove stale terms for semester, year in terms: Term.objects.get(semester=semester, year=year).delete()
def post(self, request, *args, **kwargs): # determine which form is being submitted # uses the name of the form's submit button if 'hcsa_form' in request.POST: form = self.form_class(request.POST) if form.is_valid(): return self.form_valid(form) else: return self.form_invalid(form) else: # get the secondary form form = self.second_form_class(request.POST) if form.is_valid(): hcra = HCRecommendationAdmin.objects.get_or_create( term=Term.current_term())[0] for house in House.objects.all(): hcr = HCRecommendation.objects.get_or_create( house=house, survey_admin=hcra)[0] hcr.open_time = form.cleaned_data['open_time'] hcr.close_time = form.cleaned_data['close_time'] hcr.save() hcra.open_time = form.cleaned_data['open_time'] hcra.close_time = form.cleaned_data['close_time'] hcra.open_survey = form.cleaned_data['open_survey'] hcra.save() return HttpResponseRedirect(self.success_url) else: return self.form_invalid(form)
def get_object(self, queryset=None): # get the existing object or created a new one hcra = self.admin_model.objects.get_or_create( term=Term.current_term())[0] obj, created = self.model.objects.get_or_create( house=self.request.user.house, survey_admin=hcra) return obj
def get_context_data(self, **kwargs): index = self.kwargs.get('index') context = super(HCSurveyTAView, self).get_context_data(**kwargs) hcsa = HCSurveyAdmin.objects.filter(term=Term.current_term()).filter( index=index) surveys_and_comments = [] house_ids = HCSurvey.objects.filter( survey_admin=hcsa, submitted=True).values_list('house', flat=True) for hcs in HCSurvey.objects.filter( survey_admin=hcsa, submitted=True).exclude(house__gender='C').order_by( 'house__gender', 'house__name'): surveys_and_comments.append({ 'survey': hcs, 'trainee_comments': HCTraineeComment.objects.filter(hc_survey=hcs) }) context['bro_reported'] = House.objects.filter(id__in=house_ids, gender="B") context['bro_not_reported'] = House.objects.exclude( id__in=house_ids).filter(gender="B") context['sis_reported'] = House.objects.filter(id__in=house_ids, gender="S") context['sis_not_reported'] = House.objects.exclude( id__in=house_ids).filter(gender="S") context['surveys_and_comments'] = surveys_and_comments context['page_title'] = "HC Survey Report" return context
def handle(self, *args, **options): verbose = int(options['verbosity']) > 1 if options['all']: for term in Term.objects.all(): self.fetch_courses(term, verbose=verbose) return term = Term.current_term() if options['year'] is not None and options['semester'] is not None: term = Term.objects.get(year=options['year'], semester=options['semester']) self.fetch_courses(term, verbose=verbose)