Exemple #1
0
def test_results_table():
    for student in Master.query.all():
        mat_no = student.mat_no
        if not start <= int(student.database[:4]) <= stop:
            continue
        print(mat_no)  # for debugging on failure
        session = load_session(student.database)
        table_blanks = (0, 0)  # for tracking blanks within tables
        # TODO use new col on table to update to verify value is correct
        for level in range(100, 900, 100):
            result_lvl = eval("session.Result{}".format(level))
            result = result_lvl.query.filter_by(mat_no=mat_no).first()
            if result:
                # Assert level for results not higher than present level
                assert personal_info.get(mat_no)["level"] >= min(
                    500, result.level)
                assert table_blanks != (1, 0
                                        )  # assert no blank above this table
                table_blanks = (table_blanks[1], 1)
                expected_TCP = 0  # For verifying Total Credits Passed
                for prop in dir(result):
                    if re.match("[A-Z][A-Z][A-Z][0-9][0-9][0-9]",
                                prop) and result.__getattribute__(prop):
                        score, grade = result.__getattribute__(prop).split(",")
                        # Ensure score matches grade
                        assert utils.compute_grade(int(score),
                                                   student.database) == grade
                        if grade not in ("F", "ABS"):
                            expected_TCP += course_details.get(
                                prop)["course_credit"]
                if result.carryovers:
                    for course, score, grade in [
                            x.split() for x in result.carryovers.split(",")
                    ]:
                        # Assert course isn't from a higher level
                        assert result.level >= course_details.get(
                            course)["course_level"]
                        # Ensure score matches grade
                        assert utils.compute_grade(int(score),
                                                   student.database) == grade
                        if grade not in ("F", "ABS"):
                            expected_TCP += course_details.get(
                                course)["course_credit"]
                assert expected_TCP == result.tcp
            elif table_blanks[1]:
                table_blanks = (table_blanks[1], 0)  # Met a blank
Exemple #2
0
def enrich_course_list(course_list,
                       fields=('code', 'title', 'credit', 'level')):
    """
    Add details to courses supplied in course_list

    :param course_list: <list: str>: ['course_code_1', 'course_code_2', ...]
                     or <list: list>: [['course_code_1', '', ...], ['course_code_2', '', ...]]
    :param fields: <list> (optional): the course details fields to include in the order required
    :return: the enriched list
    """
    enriched_course_list = []
    for crse in course_list:
        if isinstance(crse, list):
            crse_dets = course_details.get(crse[0])
            [
                crse.append(crse_dets[field]) for field in fields
                if field != 'code'
            ]
        elif isinstance(crse, str):
            crse_dets = course_details.get(crse)
            crse = [crse_dets[field] for field in fields]
        enriched_course_list.append(crse)
    return enriched_course_list
Exemple #3
0
def sum_credits(course_objects, credits_index=None):
    """
    :param course_objects: [('course_code_1', <some_other_detail>, <>,..),
                            ('course_code_2', <some_other_detail>, <>,..), ...]
    :param credits_index: <int>: (optional) index of course object that contains the course_credits
    :return: <int: the sum of credits>
    """
    tot = 0
    for course_object in course_objects:
        if credits_index:
            tot += int(course_object[credits_index])
        else:
            tot += int(course_details.get(course_object[0])['credit'])
    return tot
Exemple #4
0
def test_course_reg_table():
    for student in Master.query.all():
        mat_no = student.mat_no
        if not start <= int(student.database[:4]) <= stop:
            continue
        print(mat_no)  # for debugging on failure
        session = load_session(student.database)
        table_blanks = (0, 0)  # for tracking blanks within tables
        # TODO use new col on table to update to verify value is correct
        for level in range(100, 900, 100):
            course_reg_lvl = eval("session.CourseReg{}".format(level))
            course_reg = course_reg_lvl.query.filter_by(mat_no=mat_no).first()
            if course_reg:
                # Assert level for registration not higher than present level
                assert personal_info.get(mat_no)["level"] >= min(
                    500, course_reg.level)
                assert table_blanks != (1, 0
                                        )  # assert no blank above this table
                table_blanks = (table_blanks[1], 1)
                expected_TCR = 0  # For verifying Total Credits Registered
                for prop in dir(course_reg):
                    if re.match("[A-Z][A-Z][A-Z][0-9][0-9][0-9]", prop):
                        if int(course_reg.__getattribute__(prop)):
                            expected_TCR += course_details.get(
                                prop)["course_credit"]
                for course in course_reg.carryovers.split(","):
                    # TODO Remove re check after carryover100 set to NULL
                    if re.match("[A-Z][A-Z][A-Z][0-9][0-9][0-9]", course):
                        # Assert course isn't from a higher level
                        assert course_reg.level >= course_details.get(
                            course)["course_level"]
                        expected_TCR += course_details.get(
                            course)["course_credit"]
                assert expected_TCR == course_reg.tcr
            elif table_blanks[1]:
                table_blanks = (table_blanks[1], 0)  # Met a blank
Exemple #5
0
def get_carryovers(mat_no, level=None, next_level=False):
    """
    Returns a dictionary of the carryover courses for a student for each semester
    :param level: Courses up to but not including this level which are not passed
    :param next_level: Courses up to and including level which are not passed
    """
    level = level or get_level(mat_no)
    first_sem, second_sem = set(), set()
    for course in get_courses(mat_no)[:ltoi(level) + next_level]:
        first_sem |= set(course[0])
        second_sem |= set(course[1])

    person_options = csv_fn(personal_info.get(mat_no)["option"])
    for pair in person_options:
        group, choice = spc_fn(pair, s_int)
        option = course_details.get_options(group)
        idx = option["semester"] - 1
        [first_sem, second_sem][idx] -= set(option["members"])
        [first_sem, second_sem][idx] |= {choice}

    res_stmt = result_statement.get(mat_no)
    results, categories = res_stmt["results"], res_stmt["categories"]
    res_first_sem, res_second_sem = [], []
    if results:
        res_first_sem = reduce(add, [
            result["first_sem"] for idx, result in enumerate(results)
            if not (categories[idx] in "CD" and 200 <= result["level"] <= 400)
        ])
        res_second_sem = reduce(add, [
            result["second_sem"] for idx, result in enumerate(results)
            if not (categories[idx] in "CD" and 200 <= result["level"] <= 400)
        ])
    first_sem -= set([
        record[0] for record in res_first_sem if record[4] not in ("F", "ABS")
    ])
    second_sem -= set([
        record[0] for record in res_second_sem if record[4] not in ("F", "ABS")
    ])

    carryovers = {"first_sem": [], "second_sem": []}
    courses = [("first_sem", course)
               for course in first_sem] + [("second_sem", course)
                                           for course in second_sem]
    for sem, failed_course in courses:
        course = course_details.get(failed_course)
        carryovers[sem].append(
            [failed_course, course["credit"], course["level"]])
    return carryovers
Exemple #6
0
def format_results(results, tcp=(0, 0), tcf=(0, 0)):
    # TODO when making undumb, use TCP, TCF 1&2 from DB
    formatted_results, tcp, tcf, failed_courses = [[],
                                                   []], [*tcp], [*tcf], [[],
                                                                         []]
    for code, score, grade in results:
        course = course_details.get(code)
        sem, credit, title = course["semester"], course["credit"], course[
            "title"]
        formatted_results[sem - 1].append(
            (code, title, credit, int(score), grade))
        if grade not in ("ABS", "F"):
            tcp[sem - 1] += credit
        else:
            tcf[sem - 1] += credit
            failed_courses[sem - 1].append(code)
    tcw = [tcp[0] + tcf[0], tcp[1] + tcf[1]]
    return [formatted_results] + [tcw] + [tcp] + [tcf] + [failed_courses]
Exemple #7
0
def test_credits_of_course():
    for year in range(start, stop + 1):
        session = load_session(year)
        for mode in (1, 2, 3):
            courses = session.Courses.query.filter_by(
                mode_of_entry=mode).first()
            credits = session.Credits.query.filter_by(
                mode_of_entry=mode).first()
            for lvl in range(mode * 100, 600, 100):
                courses_sems = eval("courses.level{}".format(lvl)).split(" ")
                courses_lvl = courses_sems[0].split(
                    ",") + courses_sems[1].split(",")
                credits_lvl = eval("credits.level{}".format(lvl))
                lvl_total = sum([
                    course_details.get(course)["course_credit"]
                    for course in courses_lvl if course
                ])
                # verify corresponding cells in courses and credits table have same credits total
                assert lvl_total == credits_lvl
Exemple #8
0
def _get_single_results_stats(mat_no, level, acad_session):
    info = personal_info.get(mat_no)
    name = info['surname'] + ' ' + info['othernames']
    reg_courses = course_reg_for_session(mat_no, acad_session)
    reg_course_codes = reg_courses.get('courses', [])
    tcr = reg_courses.get('tcr', 0)
    res, _ = res_poll_for_session(acad_session, mat_no=mat_no)
    tce, carryovers_dict, remark = 0, {}, ''

    if res:
        carryovers = res.pop('carryovers')
        carryovers_list = [] if not carryovers else carryovers.split(',')
        for course_dets in carryovers_list:
            code, _, _ = course_dets.split(' ')
            carryovers_dict[code] = True

    for course_code in reg_course_codes:
        if res.get(course_code) not in [
                None, '-1,ABS'
        ] or carryovers_dict.get(course_code) not in [None, '-1,ABS']:
            tce += course_details.get(course_code)['credit']

    return [mat_no, name, tcr, tce, remark], 200
Exemple #9
0
def add_result_records(list_of_results, level=None):
    """
    :param list_of_results: [
             [course_code_1, session_written_1, mat_no_1, score_1], ...]
    :param level: level for the results being entered; to control course advisers' access
    :return:
    """
    base_dir = os.path.dirname(__file__)
    result_errors_file = open(
        os.path.join(base_dir, '../../result_errors.txt'), 'a')
    error_log = []

    # Initialize a dictionary of course details for all courses in list_of_results
    courses = list(set(list(zip(*list_of_results))[0]))
    try:
        course_details_dict = {
            course: course_details.get(course)
            for course in courses
        }
    except:
        # for any error, set this to an empty dict, individual calls will be made
        # and the error course would fail gracefully
        course_details_dict = {}

    for index, result_details in enumerate(list_of_results):
        idx = index + 1  # start index at 1
        errors = add_single_result_record(idx, result_details,
                                          result_errors_file,
                                          course_details_dict, level)
        error_log.extend(errors)

    result_errors_file.close()
    print(
        Fore.CYAN, '====>>  ', '{} result entries added with {} errors'.format(
            len(list_of_results), len(error_log)), Style.RESET_ALL)

    return error_log or ['Done'], 200
def test_get_course_details():
    assert course_details.get_course_details(valid_course) == ([course_details.get(valid_course)], 200)
    assert course_details.get_course_details(inv_crs_val[0]) == (None, 404)
    assert course_details.get_course_details() == (course_details.get_all(), 200)
def test_get_one_course():
    course_obj = course_details.get(valid_course)
    course_row = cur.execute(*sql_get_course(valid_course)).fetchone()
    for prop in set(course_keys):
        assert course_obj[prop] == course_row[prop]
Exemple #12
0
def add_single_result_record(index,
                             result_details,
                             result_errors_file,
                             course_details_dict,
                             level=None):
    """
    :param index: position of entry in the larger list --for tracking
    :param result_details: [course_code, session_written, mat_no, score]
    :param result_errors_file: file object in write or append mode for logging important errors
    :param course_details_dict:
    :param level: student's course-adviser assigned level
    """
    error_log = []
    try:
        course_code, session_taken, mat_no, score = result_details
        session_taken, score = map(int, [session_taken, score])
        entry_session = utils.get_DB(mat_no)
    except:
        return handle_errors('Invalid inputs at index {}'.format(index),
                             error_log, result_errors_file, result_details)

    grade = utils.compute_grade(score, entry_session)
    current_level = utils.get_level(mat_no)

    # Error check on level, grade and score
    error_text = ''
    if level:
        levels = [600, 700, 800] if level == 600 else [level]
        if current_level not in levels:
            error_text = "You are not allowed to enter results for {} at index {} whose current level is " \
                         "{}".format(mat_no, index, current_level)
    if not (-1 <= score <= 100) and not error_text:
        error_text = 'Unexpected score for {}, "{}", for {} at index {}; ' \
                     'result not added'.format(course_code, score, mat_no, index)
    if not grade and not error_text:
        error_text = '{0} at index {1} was not found in the database'.format(
            mat_no, index)
    if error_text:
        return handle_errors(error_text, error_log, result_errors_file,
                             result_details)

    # Get course details
    if course_code in course_details_dict and course_details_dict[course_code]:
        course_dets = course_details_dict[course_code]
    else:
        # if there was error in initializing course_details_dict, individual calls would be made
        course_dets = course_details.get(course_code)
        if not course_dets:
            # fail on non-existent course(s)
            error_text = '{} at index {} was not found in the database'.format(
                course_code, index)
            return handle_errors(error_text, error_log, result_errors_file,
                                 result_details)

    course_credit = course_dets['credit']
    course_level = course_dets['level']
    is_unusual = False

    # Get course reg
    course_registration = course_reg_for_session(mat_no, session_taken) or {
        'level': current_level,
        'courses': []
    }
    courses_registered = course_registration['courses']
    level_written = course_registration['level']
    if not courses_registered:
        is_unusual = True
        error_log = handle_errors(
            'No course registration found for {0} at index {1} for the {2}/{3} '
            'session'.format(mat_no, index, session_taken, session_taken + 1),
            error_log)
    elif course_code not in courses_registered:
        is_unusual = True
        error_log = handle_errors(
            '{0} at index {1} did not register {2} in the {3}/{4} session'
            ''.format(mat_no, index, course_code, session_taken,
                      session_taken + 1), error_log)

    # Get the result table for the session
    res_poll = utils.result_poll(mat_no)
    result_record, table_to_populate = res_poll_for_session(
        session_taken, res_poll)
    session = utils.load_session(utils.get_DB(mat_no))
    if not result_record:
        if is_unusual and grade == 'ABS':
            return handle_errors(
                'Unregistered course {} with grade "ABS" cannot be added for '
                '{}'.format(course_code, mat_no), error_log)
        table_to_populate = get_table_to_populate(course_registration,
                                                  res_poll)
        result_xxx_schema = getattr(session, table_to_populate + 'Schema')()
        params = mat_no, session_taken, courses_registered, result_xxx_schema, level_written
        result_record = prepare_new_results_table(params)
    else:
        result_xxx_schema = getattr(session, table_to_populate + 'Schema')()

    # Check if a previous entry for the course exists in the current session and updates the value
    # of "previous_grade" while logging the changes to be made
    previous_grade = get_previous_grade_and_log_changes(
        result_details, result_record, is_unusual)

    # add score to result object
    if is_unusual or result_record['unusual_results']:
        unusual_results = result_record['unusual_results'].split(',')
        index = [
            ind for ind, x in enumerate(unusual_results)
            if x.split(' ')[0] == course_code
        ]
        if index: unusual_results.pop(index[0])
        if is_unusual and grade != "ABS":
            unusual_results.append('{} {} {}'.format(course_code, score,
                                                     grade))
        while '' in unusual_results:
            unusual_results.remove('')
        result_record['unusual_results'] = ','.join(unusual_results)
    if not is_unusual:
        if course_code in result_record:
            result_record[course_code] = '{},{}'.format(score, grade)
        else:
            carryovers = result_record['carryovers'].split(
                ',') if result_record['carryovers'] else ['']
            index = [
                ind for ind, x in enumerate(carryovers)
                if x.split(' ')[0] == course_code
            ]
            if index: carryovers.pop(index[0])
            carryovers.append('{} {} {}'.format(course_code, score, grade))
            while '' in carryovers:
                carryovers.remove('')
            result_record['carryovers'] = ','.join(carryovers)

    # get the session category
    owed_courses_exist = check_owed_courses_exists(
        mat_no, level_written, grade, course_dets) if not is_unusual else True
    if not courses_registered:
        tcr, tcp = 0, 0
    else:
        if grade not in ['F', 'ABS'] and previous_grade in [
                'F', 'ABS', ''
        ] and not is_unusual:
            result_record['tcp'] += course_credit
        elif grade in ['F', 'ABS'] and previous_grade not in [
                'F', 'ABS', ''
        ] and not is_unusual:
            result_record['tcp'] -= course_credit
        tcr, tcp = course_registration['tcr'], result_record['tcp']

    res_record = result_xxx_schema.load(result_record)
    res_record.category = utils.compute_category(tcr, res_record,
                                                 owed_courses_exist)

    db_session = result_xxx_schema.Meta.sqla_session
    db_session.add(res_record)
    if grade == 'ABS':
        delete_if_empty(res_record, result_xxx_schema)
    db_session.commit()
    db_session.close()

    # update GPA - Credits table
    if not is_unusual:
        update_gpa_credits(mat_no, grade, previous_grade, course_credit,
                           course_level)

    return error_log