From 810039e9e1c8155287b77c2b666a581b122c4ae3 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Wed, 9 Nov 2022 09:42:36 -0800 Subject: [PATCH] log data to csv --- app/generator.py | 18 ++++++-- app/util/courses.py | 56 ++++++++++++++++++++++++ app/util/getCourses.py | 32 -------------- app/util/{getStudents.py => students.py} | 12 +++++ main.py | 53 ++++++++++++---------- 5 files changed, 114 insertions(+), 57 deletions(-) create mode 100644 app/util/courses.py delete mode 100644 app/util/getCourses.py rename app/util/{getStudents.py => students.py} (81%) diff --git a/app/generator.py b/app/generator.py index 56cb42f..0e9439a 100644 --- a/app/generator.py +++ b/app/generator.py @@ -41,7 +41,8 @@ def generateScheduleV3( blockClassLimit: int=40, # Block class limit is the number of classrooms available per block. Default 40 classes per block totalBlocks: int=10, # total blocks between two semesters -> default is 10 for 5 per semester... or this can be 8 for 4 blocks per semester studentsDir: str="../output/raw/students.json", - conflictsDir: str="../output/raw/conflicts.json" + conflictsDir: str="../output/raw/conflicts.json", + coursesDir: str="../output/raw/courses.json" ) -> tuple[dict, Error]: # Returns the completed 'running' dictionary from above # Return error that totalBlocks is invalid @@ -531,10 +532,21 @@ def generateScheduleV3( for student in students: for block in student["schedule"]: if len(student["schedule"][block]) == 0: - student["schedule"][block].append(flex[0]) if int(block[5:]) <= 5 else student["schedule"][block].append(flex[1]) + i = 0 if int(block[5:]) <= blockPerSem else 1 + student["schedule"][block].append(flex[i]) - # Update/log Student records + # Read timetable and collect data on courses + for block in running: + for course in running[block]: + sem = "Sem1" if int(block[5:]) <= blockPerSem else "Sem2" + courses[running[block][course]["CrsNo"]][sem] += 1 + + # Update/log new student records with open(studentsDir, "w") as outfile: json.dump(students, outfile, indent=2) + # Update/log new course records + with open(coursesDir, "w") as outfile: + json.dump(courses, outfile, indent=2) + return (running, None) diff --git a/app/util/courses.py b/app/util/courses.py new file mode 100644 index 0000000..a7a0ff5 --- /dev/null +++ b/app/util/courses.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3.11 +import json +import csv +from app.util.estimateGrade import getGradeFromCourseCode + +# Get all requested courses from data +def getCourses( + data_dir: str, + log: int=False, + log_dir: str='./output/raw/courses.json', +) -> dict[dict[str: any]]: + + courses = {} + + with open(data_dir, newline='') as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + exists = False + for course in courses: + exists = True if courses[course]["CrsNo"] == row["CrsNo"] else False + if exists: break + if not exists: + courses[row["CrsNo"]] = { + "CrsNo": row["CrsNo"], + "Requests": 0, + "Description": row["Description"], + "Sem1": 0, + "Sem2":0, + "Grade": getGradeFromCourseCode(row["CrsNo"]) + } + + if log: + with open(log_dir, "w") as outfile: + json.dump(courses, outfile, indent=2) + + return courses + +# Writes all course data to csv file +def writeCoursesToCSV(courses: dict, output_dir: str='./output/raw/csv/courses.csv') -> None: + with open(output_dir, 'w') as file: + writer = csv.writer(file) + # Write header + data = ("CrsNo", "Description", "Grade", "Requests", "First sem. # of Classes", "Second sem. # of Classes", "Total # of Classes") + writer.writerow(data) + + for course in courses: + courseData = ( + courses[course]["CrsNo"], + courses[course]["Description"], + courses[course]["Grade"], + courses[course]["Requests"], + courses[course]["Sem1"], + courses[course]["Sem2"], + (courses[course]["Sem1"] + courses[course]["Sem2"]) + ) + writer.writerow(courseData) diff --git a/app/util/getCourses.py b/app/util/getCourses.py deleted file mode 100644 index 01fde22..0000000 --- a/app/util/getCourses.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3.11 -import json -import csv - -# Get all requested courses from data -def getCourses( - data_dir: str, - log: int=False, - log_dir: str='./output/raw/courses.json', -) -> dict[dict[str: any]]: - - courses = {} - - with open(data_dir, newline='') as csvfile: - reader = csv.DictReader(csvfile) - for row in reader: - exists = False - for course in courses: - exists = True if courses[course]["CrsNo"] == row["CrsNo"] else False - if exists: break - if not exists: - courses[row["CrsNo"]] = { - "CrsNo": row["CrsNo"], - "Requests": 0, - "Description": row["Description"] - } - - if log: - with open(log_dir, "w") as outfile: - json.dump(courses, outfile, indent=2) - - return courses diff --git a/app/util/getStudents.py b/app/util/students.py similarity index 81% rename from app/util/getStudents.py rename to app/util/students.py index e870c7c..7eb40ea 100644 --- a/app/util/getStudents.py +++ b/app/util/students.py @@ -57,3 +57,15 @@ def getStudents( json.dump(students, outfile, indent=2) return students + +# Writes all students data to csv file +def writeStudentsToCSV(students: dict, output_dir: str='./output/raw/csv/students.csv') -> None: + with open(output_dir, 'w') as file: + writer = csv.writer(file) + # Write header + data = ("Pupil #", "# of Classes", "Grade") + writer.writerow(data) + + for student in students: + studentData = (student["Pupil #"], student["classes"], student["gradelevel"]) + writer.writerow(studentData) diff --git a/main.py b/main.py index 19dc6e1..b725181 100755 --- a/main.py +++ b/main.py @@ -4,8 +4,8 @@ import os import json from app.generator import generateScheduleV3 from app.util.globals import Error -from app.util.getCourses import getCourses -from app.util.getStudents import getStudents +from app.util.courses import getCourses, writeCoursesToCSV +from app.util.students import getStudents, writeStudentsToCSV from app.util.convertRawData import putScheduleToWord, putMasterTimetable eel.init('template') @@ -19,18 +19,22 @@ def start( total_blocks: int, ) -> dict: - eel.post_data('Ensuring Directories Exists...') - # Ensure output paths exists - if not os.path.exists('output'): os.makedirs('output') - if not os.path.exists('output/temp'): os.makedirs('output/temp') - if not os.path.exists('output/final'): os.makedirs('output/final') - if not os.path.exists('output/final/student_schedules'): os.makedirs('output/final/student_schedules') - if not os.path.exists('output/raw'): os.makedirs('output/raw') - raw_data_dir = './output/temp/course_selection_data.csv' + raw_json_dir = './output/raw/json' + + # Ensure output paths exists + eel.post_data('Ensuring Directories Exists...') + + if not os.path.exists('output'): os.makedirs('output') + if not os.path.exists('output/temp'): os.makedirs('output/temp') + if not os.path.exists('output/final'): os.makedirs('output/final') + if not os.path.exists('output/final/student_schedules'): os.makedirs('output/final/student_schedules') + if not os.path.exists('output/raw'): os.makedirs('output/raw') + if not os.path.exists('output/raw/json'): os.makedirs('output/raw/json') + if not os.path.exists('output/raw/csv'): os.makedirs('output/raw/csv') - eel.post_data('Saving raw data to local file...') # save raw file data to local file + eel.post_data('Saving raw data to local file...') with open(raw_data_dir, 'w') as raw_file: raw_file.write(raw_file_data) @@ -40,19 +44,19 @@ def start( block_class_limit = int(block_class_limit) total_blocks = int(total_blocks) - eel.post_data('Collecting student information...') # call pre-algorithm functions read raw data into a processable format + eel.post_data('Collecting student information...') students = getStudents( raw_data_dir, log=True, totalBlocks=total_blocks, - log_dir='./output/raw/students.json' + log_dir='./output/raw/json/students.json' ) eel.post_data('Collecting course information...') courses = getCourses( raw_data_dir, log=True, - log_dir='./output/raw/courses.json' + log_dir=f'{raw_json_dir}/courses.json' ) eel.post_data('Generating timetables...') @@ -64,26 +68,31 @@ def start( classCap=class_cap, blockClassLimit=block_class_limit, totalBlocks=total_blocks, - studentsDir='./output/raw/students.json', - conflictsDir='./output/raw/conflicts.json' + studentsDir=f'{raw_json_dir}/students.json', + conflictsDir=f'{raw_json_dir}/conflicts.json', + coursesDir=f'{raw_json_dir}/courses.json' ) - if err is not None: eel.post_data(f'An error has occured while generating the timetable: {err.Title}') return err.__dict__ - eel.post_data('Gathering latest data...')() # Get updated students - with open('./output/raw/students.json', 'r') as studentFile: students = json.load(studentFile) + eel.post_data('Gathering latest data...') + with open(f'{raw_json_dir}/students.json', 'r') as studentFile: students = json.load(studentFile) + + # call post-algorithm functions to present sorted data + eel.post_data('Writing data to .csv files...') + # get updated raw data + with open(f'{raw_json_dir}/students.json', 'r') as sFile: students = json.load(sFile) + with open(f'{raw_json_dir}/courses.json', 'r') as cFile: courses = json.load(cFile) + writeStudentsToCSV(students, output_dir='./output/raw/csv/students.csv') + writeCoursesToCSV(courses, output_dir='./output/raw/csv/courses.csv') eel.post_data('Writing timetables to .docx files...') - # call post-algorithm functions to present sorted data for student in students: putScheduleToWord(courses, student, './output/final/student_schedules') - # TODO: log master_timetable - return err.__dict__ if err is not None else None eel.start('index.html', size=(800, 1000))