add course dataclass

This commit is contained in:
SowinskiBraeden committed 2022-11-30 19:57:54 -08:00
1 parent 283c5e72ff
commit fe2561a543
4 files changed
+74 -59

No files matched your search

+24 -22
View File
@@ -6,6 +6,7 @@ from string import hexdigits
from app.util.globals import flex, Error
from app.util.estimateGrade import getGrade
from app.util.students import Student, studentsToDict
from app.util.courses import Course, coursesToDict
# Takes in information to create or add a new conflict
# Returns if the particular student has a previous error
@@ -45,17 +46,17 @@ def insertConflictSolutions(
# Then it starts to attempt to fit all classes into a timetable, making corretions along
# the way. Corrections being moving a students class
def generateScheduleV3(
students: list[Student], # Refer to /util/students.py to see the students list structure
courses: dict, # Refer to /util/courses.py to see the courses dictionary structure
minReq: int = 18, # minimum requests for a class to run
classCap: int = 30, # maximum students per class
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
students: list[Student], # Refer to /util/students.py to see the students list structure
courses: dict[str: Course], # Refer to /util/courses.py to see the courses dictionary structure
minReq: int = 18, # minimum requests for a class to run
classCap: int = 30, # maximum students per class
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",
coursesDir: str = "../output/raw/courses.json"
) -> tuple[dict, Error]: # Returns the completed 'running' dictionary from above
) -> tuple[dict, Error]: # Returns the completed 'running' dictionary
# Return error that totalBlocks is invalid
if totalBlocks not in (10, 8):
totalBlockError = Error('Invalid totalBlocks', 'An invalid \'totalBlocks\' value was provided -> must be 10 or 8')
@@ -80,9 +81,9 @@ def generateScheduleV3(
# Tally class request
for request in (request for request in student.Requests if not request.Alt and request.CrsNo not in flex):
code = request.CrsNo
courses[code]["Requests"] += 1
courses[code].Requests += 1
# Add course to active list if enough requests
if courses[code]["Requests"] > minReq and courses[code]["CrsNo"] not in activeCourses:
if courses[code].Requests > minReq and courses[code].CrsNo not in activeCourses:
activeCourses[code] = courses[code]
@@ -94,14 +95,14 @@ def generateScheduleV3(
for i in range(len(activeCourses)):
index = list(activeCourses)[i]
if index not in emptyClasses: emptyClasses[index] = {}
classRunCount = activeCourses[index]["Requests"] // median
remaining = activeCourses[index]["Requests"] % median
classRunCount = activeCourses[index].Requests // median
remaining = activeCourses[index].Requests % median
# Put number of classRunCount classes in emptyClasses
for j in range(classRunCount):
emptyClasses[index][f"{index}-{hexdigits[j]}"] = {
"CrsNo": index,
"Description": activeCourses[index]["Description"],
"Description": activeCourses[index].Description,
"expectedLen": median # Number of students expected in this class / may be altered later
}
@@ -118,7 +119,7 @@ def generateScheduleV3(
# Create a class using remaining
emptyClasses[index][f"{index}-{hexdigits[classRunCount]}"] = {
"CrsNo": index,
"Description": activeCourses[index]["Description"],
"Description": activeCourses[index].Description,
"expectedLen": remaining
}
@@ -145,7 +146,7 @@ def generateScheduleV3(
# Create a class using remaining + required amount from existing classes
emptyClasses[index][f"{index}-{hexdigits[classRunCount]}"] = {
"CrsNo": index,
"Description": activeCourses[index]["Description"],
"Description": activeCourses[index].Description,
"expectedLen": remaining
}
@@ -225,7 +226,7 @@ def generateScheduleV3(
"index": student.StudentIndex
}],
"CrsNo": course,
"Description": courses[course]["Description"]
"Description": courses[course].Description
}
getAvailableCourse = False
break
@@ -550,13 +551,14 @@ def generateScheduleV3(
# 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
courses[running[block][course]["CrsNo"]]["Occupied"] += len(running[block][course]["students"])
c = running[block][course]["CrsNo"]
if int(block[5:]) <= blockPerSem: courses[c].Sem1 += 1
else: courses[c].Sem2 += 1
courses[c].Occupied += len(running[block][course]["students"])
for course in courses:
courses[course]["Total"] = courses[course]["Sem1"] + courses[course]["Sem2"]
courses[course]["Seats"] = courses[course]["Total"] * classCap
courses[course].Total = courses[course].Sem1 + courses[course].Sem2
courses[course].Seats = courses[course].Total * classCap
# Update/log new student records
with open(studentsDir, "w") as outfile:
@@ -564,7 +566,7 @@ def generateScheduleV3(
# Update/log new course records
with open(coursesDir, "w") as outfile:
json.dump(courses, outfile, indent=2)
json.dump(coursesToDict(courses), outfile, indent=2)
# Save timetable to json
with open('./output/raw/json/timetable.json', 'w') as outfile:
+7 -4
View File
@@ -4,8 +4,11 @@ from app.util.globals import flex
import xlsxwriter
import docx
from app.util.courses import Course
from app.util.students import Student
def putMasterTimetable(
table: dict,
table: dict[str: dict],
output_dir: str = './output/final'
) -> None:
@@ -36,8 +39,8 @@ def putMasterTimetable(
workbook.close()
def putScheduleToWord(
courses: dict,
student: dict,
courses: dict[str: Course],
student: Student,
output_dir: str = './output/final/student_schedules'
) -> None:
@@ -64,7 +67,7 @@ def putScheduleToWord(
for block in student['schedule']:
courseCode = student.Schedule[block][0]
if courseCode in flex: courseName = 'Study'
else: courseName = courses[courseCode[:-2]]["Description"]
else: courseName = courses[courseCode[:-2]].Description
blockNum = int(block.split('block')[1])
semester = 2 if blockNum > 5 else 1
if blockNum > (len(student.Schedule)/2): blockNum -= (len(student.Schedule)/2)
+35 -26
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3.11
import json
import csv
from dataclasses import dataclass
from dataclasses import dataclass, asdict
from app.util.estimateGrade import getGrade
@dataclass
@@ -10,45 +10,54 @@ class Request:
Description: str
Alt: bool
@dataclass
class Course:
CrsNo: str
Description: str
Grade: int
Requests: int = 0 # number of requests for this
Sem1: int = 0 # number of classes running in sem1
Sem2: int = 0 # number of classes running in sem2
Total: int = 0 # total number of classes running
Seats: int = 0 # total number of seats
Occupied: int = 0 # number of occupied seats
def coursesToDict(courses: dict[str: Course]) -> dict[str: dict]:
return [asdict(courses[c]) for c in courses]
# 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]]:
) -> dict[str: Course]:
courses = {}
courses: dict[str: Course] = {}
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
exists = True if courses[course].CrsNo == row["CrsNo"] else False
if exists: break
if not exists:
grade = getGrade(row["CrsNo"], row["Description"])
courses[row["CrsNo"]] = {
"CrsNo": row["CrsNo"],
"Description": row["Description"],
"Grade": grade,
"Requests": 0,
"Sem1": 0, # number of classes running in sem1
"Sem2": 0, # number of classes running in sem2
"Total": 0, # total number of classes running
"Seats": 0, # total number of seats
"Occupied": 0, # number of occupied seats
}
courses[row["CrsNo"]] = Course(
row["CrsNo"],
row["Description"],
grade
)
if log:
with open(log_dir, "w") as outfile:
json.dump(courses, outfile, indent=2)
json.dump(coursesToDict(courses), outfile, indent=2)
return courses
# Writes all course data to csv file
def writeCoursesToCSV(
courses: dict,
courses: dict[str: Course],
output_dir: str = './output/raw/csv/courses.csv'
) -> None:
with open(output_dir, 'w') as file:
@@ -69,14 +78,14 @@ def writeCoursesToCSV(
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]["Total"],
courses[course]["Seats"],
courses[course]["Occupied"]
courses[course].CrsNo,
courses[course].Description,
courses[course].Grade,
courses[course].Requests,
courses[course].Sem1,
courses[course].Sem2,
courses[course].Total,
courses[course].Seats,
courses[course].Occupied
)
writer.writerow(courseData)