def test_override_fixture(self, app): mr = MockRows( io.StringIO('sid,first_name,last_name\n20000000,Martin,Van Buren')) with register_mock(data_loch.get_sis_section_enrollments, mr): data = data_loch.get_sis_section_enrollments(2178, 12345) assert len(data) == 1 assert { 'sid': 20000000, 'first_name': 'Martin', 'last_name': 'Van Buren' } == data[0]
def test_fixture_not_found(self, app): no_db = data_loch.get_sis_section_enrollments(0, 0) # TODO Real data_loch queries will return an empty list if the course is not found. assert no_db is None
def get_course_student_profiles(term_id, section_id, offset=None, limit=None, featured=None): benchmark = get_benchmarker('get_course_student_profiles') benchmark('begin') enrollment_rows = data_loch.get_sis_section_enrollments( term_id, section_id, offset=offset, limit=limit, ) sids = [str(r['sid']) for r in enrollment_rows] if offset or len(sids) >= 50: count_result = data_loch.get_sis_section_enrollments_count(term_id, section_id) total_student_count = count_result[0]['count'] else: total_student_count = len(sids) # If we have a featured UID not already present in the result set, add the corresponding SID only if the # student is enrolled. if featured and not next((r for r in enrollment_rows if str(r['uid']) == featured), None): featured_enrollment_rows = data_loch.get_sis_section_enrollment_for_uid(term_id, section_id, featured) if featured_enrollment_rows: sids = [str(featured_enrollment_rows[0]['sid'])] + sids # TODO It's probably more efficient to store class profiles in the loch, rather than distilling them # on the fly from full profiles. students = get_full_student_profiles(sids) benchmark('begin enrollments query') enrollments_for_term = data_loch.get_enrollments_for_term(term_id, sids) benchmark('end enrollments query') enrollments_by_sid = {row['sid']: json.loads(row['enrollment_term']) for row in enrollments_for_term} academic_standing = get_academic_standing_by_sid(sids, as_dicts=True) term_gpas = get_term_gpas_by_sid(sids, as_dicts=True) all_canvas_sites = {} benchmark('begin profile transformation') for student in students: # Strip SIS details to lighten the API load. sis_profile = student.pop('sisProfile', None) if sis_profile: student['academicCareerStatus'] = sis_profile.get('academicCareerStatus') student['cumulativeGPA'] = sis_profile.get('cumulativeGPA') student['cumulativeUnits'] = sis_profile.get('cumulativeUnits') student['degree'] = sis_profile.get('degree') student['level'] = _get_sis_level_description(sis_profile) student['currentTerm'] = sis_profile.get('currentTerm') student['majors'] = _get_active_plan_descriptions(sis_profile) student['transfer'] = sis_profile.get('transfer') term = enrollments_by_sid.get(student['sid']) if term: # Strip the enrollments list down to the section of interest. enrollments = term.pop('enrollments', []) for enrollment in enrollments: _section = next((s for s in enrollment['sections'] if str(s['ccn']) == section_id), None) if _section: canvas_sites = enrollment.get('canvasSites', []) student['enrollment'] = { 'canvasSites': canvas_sites, 'enrollmentStatus': _section.get('enrollmentStatus', None), 'grade': enrollment.get('grade', None), 'gradingBasis': enrollment.get('gradingBasis', None), 'midtermGrade': enrollment.get('midtermGrade', None), } student['analytics'] = analytics.mean_metrics_across_sites(canvas_sites, 'student') # If more than one course site is associated with this section, derive mean metrics from as many sites as possible. for site in canvas_sites: if site['canvasCourseId'] not in all_canvas_sites: all_canvas_sites[site['canvasCourseId']] = site continue student['academicStanding'] = academic_standing.get(student['sid']) student['termGpa'] = term_gpas.get(student['sid']) benchmark('end profile transformation') mean_metrics = analytics.mean_metrics_across_sites(all_canvas_sites.values(), 'courseMean') mean_metrics['gpa'] = {} mean_gpas = data_loch.get_sis_section_mean_gpas(term_id, section_id) for row in mean_gpas: mean_metrics['gpa'][str(row['gpa_term_id'])] = row['avg_gpa'] benchmark('end') return { 'students': students, 'totalStudentCount': total_student_count, 'meanMetrics': mean_metrics, }
def get_course_student_profiles(term_id, section_id, offset=None, limit=None): enrollment_rows = data_loch.get_sis_section_enrollments( term_id, section_id, scope=get_student_query_scope(), offset=offset, limit=limit, ) sids = [str(r['sid']) for r in enrollment_rows] if offset or len(sids) >= 50: count_result = data_loch.get_sis_section_enrollments_count( term_id, section_id, scope=get_student_query_scope()) total_student_count = count_result[0]['count'] else: total_student_count = len(sids) # TODO It's probably more efficient to store class profiles in the loch, rather than distilling them # on the fly from full profiles. students = get_full_student_profiles(sids) enrollments_for_term = data_loch.get_enrollments_for_term(term_id, sids) enrollments_by_sid = { row['sid']: json.loads(row['enrollment_term']) for row in enrollments_for_term } all_canvas_sites = {} for student in students: # Strip SIS details to lighten the API load. sis_profile = student.pop('sisProfile', None) if sis_profile: student['cumulativeGPA'] = sis_profile.get('cumulativeGPA') student['cumulativeUnits'] = sis_profile.get('cumulativeUnits') student['level'] = sis_profile.get('level', {}).get('description') student['majors'] = sorted( plan.get('description') for plan in sis_profile.get('plans', [])) term = enrollments_by_sid.get(student['sid']) student['hasCurrentTermEnrollments'] = False if term: # Strip the enrollments list down to the section of interest. enrollments = term.pop('enrollments', []) for enrollment in enrollments: _section = next((s for s in enrollment['sections'] if str(s['ccn']) == section_id), None) if _section: canvas_sites = enrollment.get('canvasSites', []) student['enrollment'] = { 'canvasSites': canvas_sites, 'enrollmentStatus': _section.get('enrollmentStatus', None), 'grade': enrollment.get('grade', None), 'gradingBasis': enrollment.get('gradingBasis', None), } student['analytics'] = analytics.mean_metrics_across_sites( canvas_sites, 'student') # If more than one course site is associated with this section, derive mean metrics from as many sites as possible. for site in canvas_sites: if site['canvasCourseId'] not in all_canvas_sites: all_canvas_sites[site['canvasCourseId']] = site continue mean_metrics = analytics.mean_metrics_across_sites( all_canvas_sites.values(), 'courseMean') return { 'students': students, 'totalStudentCount': total_student_count, 'meanMetrics': mean_metrics, }