예제 #1
0
    def _save(self, objects, datatype, should_update=False):
        self.push_datatype(datatype)

        def _should_report_progress(i, num):
            return i == num or num < 5 or i % (num / 5) == 0

        def _report_progress(i, num):
            logging.debug('...{}%\t({}/{})'.format(i * 100 / num, i, num))

        logging.debug("Saving some <{}> <{}> to local db".format(
            self._institution, datatype))
        for i, obj in enumerate(objects, start=1):
            identifiers = tuple(obj.get(pkey) for pkey in self.cur_primary_keys())
            should_add = self.doesnt_know_about(datatype=self.cur_datatype(),
                                                identifiers=identifiers)
            if should_add:
                self._local_db.add(obj, datatype=self.cur_datatype())
            elif should_update:
                self._local_db.update(obj, datatype=self.cur_datatype(),
                                           identifiers=primary_key_values)
            if _should_report_progress(i, len(objects)):
                _report_progress(i, len(objects))
        try:
            self._local_db.commit()
        except Exception as e:
            logging.error(str(e))
            logging.error("Failed to save <{}> <{}> to local_db".format(
                self._institution, self.cur_datatype()))
        else:
            verb = "Updated" if should_update else "Saved"
            logging.debug("{} some <{}> <{}> to local_db".format(
                verb, self._institution, self.cur_datatype()))

        self.pop_datatype()
예제 #2
0
 def push_datatype(self, datatype):
     datatype = datatype.lower()
     if 'term' in datatype:
         self.push_terms()
     elif 'schedule' in datatype:
         self.push_schedules()
     elif 'course' in datatype:
         self.push_courses()
     elif 'section' in datatype:
         self.push_sections()
     else:
         logging.error('Cannot find datatype <{}>'.format(datatype))
     return self
예제 #3
0
    def _fetch(self, datatype, **kwargs):
        if datatype not in self._remote_db.known_searches():
            logging.error('<{}> has no datatype <{}>'.format(
                self._institution, datatype))
            results = list()
        else:
            logging.debug("Fetching <{}> <{}> ({}) from remote db".format(
                self._institution, datatype, kwargs))
            results = self._remote_db.search(datatype, **kwargs)

            if 'section' in datatype.lower():
                results = self._attach_classtimes(results)
        return results
예제 #4
0
 def push_datatype(self, datatype):
     datatype = datatype.lower()
     if 'term' in datatype:
         self.push_terms()
     elif 'schedule' in datatype:
         self.push_schedules()
     elif 'course' in datatype:
         self.push_courses()
     elif 'section' in datatype:
         self.push_sections()
     else:
         logging.error('Cannot find datatype <{}>'.format(datatype))
     return self
예제 #5
0
    def _fetch(self, datatype, **kwargs):
        if datatype not in self._remote_db.known_searches():
            logging.error('<{}> has no datatype <{}>'.format(
                self._institution, datatype))
            results = list()
        else:
            logging.debug("Fetching <{}> <{}> ({}) from remote db".format(
                self._institution, datatype, kwargs))
            results = self._remote_db.search(datatype, **kwargs)

            if 'section' in datatype.lower():
                results = self._attach_classtimes(results)
        return results
예제 #6
0
파일: api.py 프로젝트: rosshamish/classtime
def fill_institutions(search_params=None): #pylint: disable=W0613
    db.create_all()
    if Institution.query.first() is None:
        config_file = os.path.join(classtime.brain.institutions.CONFIG_FOLDER_PATH,
            'institutions.json')
        with open(config_file, 'r') as config:
            config = json.loads(config.read())
        institutions = config.get('institutions')
        for institution in institutions:
            if not Institution.query.get(institution.get('institution')):
                db.session.add(Institution(institution))
        try:
            db.session.commit()
        except:
            logging.error('Institutions failed to add to database')
            return None
예제 #7
0
def fill_institutions(search_params=None):  #pylint: disable=W0613
    db.create_all()
    if Institution.query.first() is None:
        config_file = os.path.join(
            classtime.brain.institutions.CONFIG_FOLDER_PATH,
            'institutions.json')
        with open(config_file, 'r') as config:
            config = json.loads(config.read())
        institutions = config.get('institutions')
        for institution in institutions:
            if not Institution.query.get(institution.get('institution')):
                db.session.add(Institution(institution))
        try:
            db.session.commit()
        except:
            logging.error('Institutions failed to add to database')
            return None
예제 #8
0
    def _fetch_multiple(self, datatype, identifiers):
        if datatype not in self._remote_db.known_searches():
            logging.error('<{}> has no datatype <{}>'.format(
                self._institution, datatype))
            results = list()
        else:
            logging.debug("Fetching <{}> <{}> <{}> from remote db".format(
                len(identifiers), self._institution, datatype))

            multiple_results = self._remote_db.search_multiple(
                [datatype] * len(identifiers),
                identifiers)

            if 'section' in datatype.lower():
                multiple_results = [self._attach_classtimes(results)
                                    for results in multiple_results]
        return multiple_results
    def add_busy_time(self, busy_time):
        """Attempts to add a busy_time to the timetable.
        On success, adds it to the busy_time list.

        :param busy_time: the busy_time to add
        :type busy_time: section dict

        If a busy_time has null timetable info (day, startTime, endTime),
        it will not be added.
        """
        try:
            self.attempt_add_to_timetable(busy_time, Schedule.BUSY)
        except ValueError:
            logging.error('Failed to schedule busy time {}'.format(
                busy_time))
        else:
            self.busy_times.append(busy_time)
        return self
예제 #10
0
    def _fetch_multiple(self, datatype, identifiers):
        if datatype not in self._remote_db.known_searches():
            logging.error('<{}> has no datatype <{}>'.format(
                self._institution, datatype))
            results = list()
        else:
            logging.debug("Fetching <{}> <{}> <{}> from remote db".format(
                len(identifiers), self._institution, datatype))

            multiple_results = self._remote_db.search_multiple(
                [datatype] * len(identifiers), identifiers)

            if 'section' in datatype.lower():
                multiple_results = [
                    self._attach_classtimes(results)
                    for results in multiple_results
                ]
        return multiple_results
예제 #11
0
    def push_datatype(self, datatype):
        """ONLY for use with unknown datatypes coming from an outside source.

        If you know the datatype from context, use the named method.

        Note that 'term', 'terms', 'Term', and 'Terms' are all legal.
        """
        datatype = datatype.lower()
        if 'term' in datatype:
            self.push_terms()
        elif 'course' in datatype:
            self.push_courses()
        elif 'section' in datatype:
            self.push_sections()
        elif 'status' in datatype:
            self.push_status()
        elif 'classtime' in datatype:
            self.push_classtimes()
        else:
            logging.error('Cannot find datatype <{}>'.format(datatype))
        return self
예제 #12
0
    def push_datatype(self, datatype):
        """ONLY for use with unknown datatypes coming from an outside source.

        If you know the datatype from context, use the named method.

        Note that 'term', 'terms', 'Term', and 'Terms' are all legal.
        """
        datatype = datatype.lower()
        if 'term' in datatype:
            self.push_terms()
        elif 'course' in datatype:
            self.push_courses()
        elif 'section' in datatype:
            self.push_sections()
        elif 'status' in datatype:
            self.push_status()
        elif 'classtime' in datatype:
            self.push_classtimes()
        else:
            logging.error('Cannot find datatype <{}>'.format(datatype))
        return self
예제 #13
0
    def _save(self, objects, datatype, should_update=False):
        self.push_datatype(datatype)

        def _should_report_progress(i, num):
            return i == num or num < 5 or i % (num / 5) == 0

        def _report_progress(i, num):
            logging.debug('...{}%\t({}/{})'.format(i * 100 / num, i, num))

        logging.debug("Saving some <{}> <{}> to local db".format(
            self._institution, datatype))
        for i, obj in enumerate(objects, start=1):
            identifiers = tuple(
                obj.get(pkey) for pkey in self.cur_primary_keys())
            should_add = self.doesnt_know_about(datatype=self.cur_datatype(),
                                                identifiers=identifiers)
            if should_add:
                self._local_db.add(obj, datatype=self.cur_datatype())
            elif should_update:
                self._local_db.update(obj,
                                      datatype=self.cur_datatype(),
                                      identifiers=primary_key_values)
            if _should_report_progress(i, len(objects)):
                _report_progress(i, len(objects))
        try:
            self._local_db.commit()
        except Exception as e:
            logging.error(str(e))
            logging.error("Failed to save <{}> <{}> to local_db".format(
                self._institution, self.cur_datatype()))
        else:
            verb = "Updated" if should_update else "Saved"
            logging.debug("{} some <{}> <{}> to local_db".format(
                verb, self._institution, self.cur_datatype()))

        self.pop_datatype()
예제 #14
0
def find_schedules(schedule_params, num_requested):
    """
    :param dict schedule_params: parameters to build the schedule with.
        Check :ref:`api/generate-schedules <api-generate-schedules>`
        for available parameters.
    """
    logging.info('Received schedule request')

    if 'term' not in schedule_params:
        logging.error("Schedule generation call did not specify <term>")
    term = schedule_params.get('term', '')
    institution = schedule_params.get('institution', 'ualberta')
    cal = classtime.brain.get_calendar(institution)

    if 'courses' not in schedule_params:
        logging.error("Schedule generation call did not specify <courses>")
    course_ids = schedule_params.get('courses', list())
    busy_times = schedule_params.get('busy-times', list())
    preferences = schedule_params.get('preferences', dict())
    electives_groups = schedule_params.get('electives', list())
    for electives_group in electives_groups:
        if 'courses' not in electives_group:
            logging.warning('"courses" not found for electives. q={}'.format(
                schedule_params))

    schedules = _generate_schedules_sat(cal, term, course_ids, busy_times, electives_groups, preferences)
    schedules = _condense_schedules(cal, schedules)
    schedules = sorted(schedules,
                       reverse=True,
                       key=lambda s: s.overall_score())
    if not schedules:
        logging.error('No schedules found for q={}'.format(
            schedule_params))
    else:
        logging.info('Returning {}/{} schedules from request q={}'.format(
            min(num_requested, len(schedules)),
            len(schedules),
            schedule_params))
        debug_msg = 'Request q={q}\n' + \
                    'Response: Returning {ret} schedules\n' + \
                    '          including {ret_like} more like them\n' + \
                    '          out of {tot} total generated\n' + \
                    'Returning:\n{ret_schedules}'
        logging.debug(debug_msg.format(
            q=schedule_params,
            ret=min(num_requested,
                len(schedules)),
            ret_like=sum([len(s.more_like_this)
                          for s in schedules[:num_requested]]),
            tot=len(schedules) + sum([len(s.more_like_this)
                                     for s in schedules]),
            ret_schedules=schedules[:num_requested]))
    return schedules[:num_requested]
def find_schedules(schedule_params, num_requested):
    """
    :param dict schedule_params: parameters to build the schedule with.
        Check :ref:`api/generate-schedules <api-generate-schedules>`
        for available parameters.
    """
    logging.info('Received schedule request')

    if 'term' not in schedule_params:
        logging.error("Schedule generation call did not specify <term>")
    term = schedule_params.get('term', '')
    institution = schedule_params.get('institution', 'ualberta')
    cal = classtime.brain.get_calendar(institution)

    if 'courses' not in schedule_params:
        logging.error("Schedule generation call did not specify <courses>")
    course_ids = schedule_params.get('courses', list())
    busy_times = schedule_params.get('busy-times', list())
    preferences = schedule_params.get('preferences', dict())
    electives_groups = schedule_params.get('electives', list())
    for electives_group in electives_groups:
        if 'courses' not in electives_group:
            logging.warning('"courses" not found for electives. q={}'.format(
                schedule_params))

    schedules = _generate_schedules_sat(cal, term, course_ids, busy_times,
                                        electives_groups, preferences)
    schedules = _condense_schedules(cal, schedules)
    schedules = sorted(schedules,
                       reverse=True,
                       key=lambda s: s.overall_score())
    if not schedules:
        logging.error('No schedules found for q={}'.format(schedule_params))
    else:
        logging.info('Returning {}/{} schedules from request q={}'.format(
            min(num_requested, len(schedules)), len(schedules),
            schedule_params))
        debug_msg = 'Request q={q}\n' + \
                    'Response: Returning {ret} schedules\n' + \
                    '          including {ret_like} more like them\n' + \
                    '          out of {tot} total generated\n' + \
                    'Returning:\n{ret_schedules}'
        logging.debug(
            debug_msg.format(q=schedule_params,
                             ret=min(num_requested, len(schedules)),
                             ret_like=sum([
                                 len(s.more_like_this)
                                 for s in schedules[:num_requested]
                             ]),
                             tot=len(schedules) +
                             sum([len(s.more_like_this) for s in schedules]),
                             ret_schedules=schedules[:num_requested]))
    return schedules[:num_requested]