From 3cf07cedda11649578526ccb2253fd73e823c29c Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 18 Apr 2023 16:33:23 -0700 Subject: [PATCH] more conversations --- src/DataHandler.py | 280 ++++++++++++++++-------------------- src/DataTypes/Course.py | 77 +++++++--- src/DataTypes/Curriculum.py | 14 +- src/DataTypes/Simulation.py | 103 ++++++------- src/DegreePlanCreation.py | 6 +- 5 files changed, 246 insertions(+), 234 deletions(-) diff --git a/src/DataHandler.py b/src/DataHandler.py index 93d5739..ddace4a 100644 --- a/src/DataHandler.py +++ b/src/DataHandler.py @@ -18,15 +18,24 @@ julia> dp = read_csv("./mydata/UBW_plan.csv") ``` """ -def read_csv(file_path:AbstractString): - file_path = remove_empty_lines(file_path) - if typeof(file_path) == Bool && !file_path - return false - end +import os +from typing import Dict, List +from src.CSVUtilities import csv_line_reader, read_all_courses, remove_empty_lines +from src.DataTypes.Course import Course +from src.DataTypes.Curriculum import Curriculum +from src.DataTypes.DataTypes import quarter, semester +from src.DataTypes.DegreePlan import DegreePlan +from src.DataTypes.LearningOutcome import LearningOutcome + + +def read_csv(raw_file_path:str): + file_path = remove_empty_lines(raw_file_path) + if isinstance(file_path, bool) and not file_path: + return False # dict_curric_degree_type = Dict("AA"=>AA, "AS"=>AS, "AAS"=>AAS, "BA"=>BA, "BS"=>BS, ""=>BS) - dict_curric_system = Dict("semester"=>semester, "quarter"=>quarter, ""=>semester) + dict_curric_system = {"semester":semester,"quarter":quarter,"": semester} dp_name = "" - dp_add_courses = Array{Course,1}() + dp_add_courses: List[Course] = [] curric_name = "" curric_inst = "" curric_dtype = "BS" @@ -40,213 +49,178 @@ def read_csv(file_path:AbstractString): learning_outcomes_count=0 curric_learning_outcomes_start=0 curric_learning_outcomes_count=0 - part_missing_term=false + part_missing_term=False output = "" # Open the CSV file and read in the basic information such as the type (curric or degreeplan), institution, degree type, etc - open(file_path) do csv_file - read_line = csv_line_reader(readline(csv_file), ',') + with open(file_path) as csv_file: + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - if read_line[1] == "Curriculum" - curric_name = read_line[2] - read_line = csv_line_reader(readline(csv_file), ',') - is_dp = read_line[1] == "Degree Plan" - if is_dp - dp_name = read_line[2] - read_line = csv_line_reader(readline(csv_file), ',') + if read_line[0] == "Curriculum" + curric_name = read_line[1] + read_line = csv_line_reader(csv_file.readline(), ',') + is_dp = read_line[0] == "Degree Plan" + if is_dp: + dp_name = read_line[1] + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - end - if read_line[1] == "Institution" - curric_inst = read_line[2] - read_line = csv_line_reader(readline(csv_file), ',') + if read_line[0] == "Institution": + curric_inst = read_line[1] + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - end - if read_line[1] == "Degree Type" - curric_dtype = read_line[2] - read_line = csv_line_reader(readline(csv_file), ',') + if read_line[0] == "Degree Type": + curric_dtype = read_line[1] + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - end - if read_line[1] == "System Type" - curric_stype = dict_curric_system[lowercase(read_line[2])] - read_line = csv_line_reader(readline(csv_file), ',') + if read_line[0] == "System Type": + curric_stype = dict_curric_system[lowercase(read_line[1])] + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - end - if read_line[1] == "CIP" - curric_CIP = read_line[2] - read_line = csv_line_reader(readline(csv_file), ',') + if read_line[0] == "CIP": + curric_CIP = read_line[1] + read_line = csv_line_reader(csv_file.readline(), ',') courses_header += 1 - end - if read_line[1] == "Courses" + if read_line[0] == "Courses": courses_header += 1 - else - println("Could not find Courses") - return false - end + else: + print("Could not find Courses") + return False # File isn't formatted correctly, couldn't find the curriculum field in Col A Row 1 - else - println("Could not find a Curriculum") - return false - end + else: + print("Could not find a Curriculum") + return False # This is the row containing Course ID, Course Name, Prefix, etc - read_line = csv_line_reader(readline(csv_file), ',') + read_line = csv_line_reader(csv_file.readline(), ',') # Checks that all courses have an ID, and counts the total number of courses - while length(read_line) > 0 && read_line[1] != "Additional Courses" && read_line[1] != "Course Learning Outcomes" && - read_line[1] != "Curriculum Learning Outcomes" && !startswith(read_line[1], "#") + while len(read_line) > 0 and read_line[0] != "Additional Courses" and read_line[0] != "Course Learning Outcomes" and \ + read_line[0] != "Curriculum Learning Outcomes" and not read_line[0].startswith( "#"): # Enforce that each course has an ID - if length(read_line[1]) == 0 - if !any(x -> x != "", read_line) - read_line = csv_line_reader(readline(csv_file), ',') + if len(read_line[0]) == 0: + if not any(x != "" for x in read_line): + read_line = csv_line_reader(csv_file.readline(), ',') continue - end - println("All courses must have a Course ID (1)") - return false - end + print("All courses must have a Course ID (1)") + return False # Enforce that each course has an associated term if the file is a degree plan - if (is_dp) - if (length(read_line) == 10) - error("Each Course in a Degree Plan must have an associated term." * - "\nCourse with ID \'$(read_line[1])\' ($(read_line[2])) has no term.") - return false - elseif (read_line[11] == 0) - error("Each Course in a Degree Plan must have an associated term." * - "\nCourse with ID \'$(read_line[1])\' ($(read_line[2])) has no term.") - return false - end - end + if (is_dp): + if (len(read_line) == 10): + raise Exception("Each Course in a Degree Plan must have an associated term." + + f"\nCourse with ID \'{read_line[0]}\' ({read_line[1]}) has no term.") + elif (read_line[10] == 0): + raise Exception("Each Course in a Degree Plan must have an associated term." + + f"\nCourse with ID \'{read_line[0]}\' ({read_line[1]}) has no term.") course_count += 1 - read_line = csv_line_reader(readline(csv_file), ',') - end - - df_courses = CSV.File(file_path, header = courses_header, limit = course_count - 1, delim = ',', silencewarnings = true) |> DataFrame - if nrow(df_courses) != nrow(unique(df_courses, Symbol("Course ID"))) - println("All courses must have a unique Course ID (2)") - return false - end - if !is_dp && Symbol("Term") in names(df_courses) - println("Curriculum cannot have term information.") - return false - end + read_line = csv_line_reader(csv_file.readline(), ',') + + df_courses = DataFrame(CSV.File(file_path, header = courses_header, limit = course_count - 1, delim = ',', silencewarnings = True)) + if nrow(df_courses) != nrow(unique(df_courses, Symbol("Course ID"))): + print("All courses must have a unique Course ID (2)") + return False + if not is_dp and Symbol("Term") in names(df_courses): + print("Curriculum cannot have term information.") + return False df_all_courses = DataFrame() df_additional_courses = DataFrame() - if length(read_line) > 0 && read_line[1] == "Additional Courses" - if !is_dp - println("Only Degree Plan can have additional courses") - return false + if len(read_line) > 0 and read_line[0] == "Additional Courses": + if not is_dp: + print("Only Degree Plan can have additional courses") + return False end additional_course_start = courses_header+course_count+1 - read_line = csv_line_reader(readline(csv_file), ',') - while length(read_line) > 0 && read_line[1] != "Course Learning Outcomes" && - read_line[1] != "Curriculum Learning Outcomes" && !startswith(read_line[1], "#") + read_line = csv_line_reader(csv_file.readline(), ',') + while length(read_line) > 0 and read_line[0] != "Course Learning Outcomes" and \ + read_line[0] != "Curriculum Learning Outcomes" and not read_line[0].startswith( "#"): additional_course_count += 1 - read_line = csv_line_reader(readline(csv_file), ',') - end - end - if additional_course_count > 1 - df_additional_courses = CSV.File(file_path, header = additional_course_start, limit = additional_course_count - 1, delim = ',', silencewarnings = true) |> DataFrame + read_line = csv_line_reader(csv_file.readline(), ',') + if additional_course_count > 1: + df_additional_courses = DataFrame(CSV.File(file_path, header = additional_course_start, limit = additional_course_count - 1, delim = ',', silencewarnings = True)) df_all_courses = vcat(df_courses,df_additional_courses) - else + else: df_all_courses = df_courses - end df_course_learning_outcomes="" - if length(read_line)>0 && read_line[1] == "Course Learning Outcomes" + if len(read_line)>0 and read_line[0] == "Course Learning Outcomes": learning_outcomes_start = additional_course_start+additional_course_count+1 - read_line = csv_line_reader(readline(csv_file), ',') - while length(read_line)>0 && !startswith(read_line[1],"#") && read_line[1] != "Curriculum Learning Outcomes" + read_line = csv_line_reader(csv_file.readline(), ',') + while len(read_line)>0 and not read_line[0].startswith("#") and read_line[0] != "Curriculum Learning Outcomes": learning_outcomes_count +=1 - read_line = csv_line_reader(readline(csv_file), ',') - end - if learning_outcomes_count > 1 - df_course_learning_outcomes = CSV.File(file_path, header = learning_outcomes_start, limit = learning_outcomes_count - 1, delim = ',', silencewarnings = true) |> DataFrame - end - end - course_learning_outcomes = Dict{Int, Array{LearningOutcome}}() - if df_course_learning_outcomes != "" + read_line = csv_line_reader(csv_file.readline(), ',') + if learning_outcomes_count > 1: + df_course_learning_outcomes = DataFrame(CSV.File(file_path, header = learning_outcomes_start, limit = learning_outcomes_count - 1, delim = ',', silencewarnings = True) ) + course_learning_outcomes: Dict[int, List[LearningOutcome]] = {} + if df_course_learning_outcomes != "": course_learning_outcomes = generate_course_lo(df_course_learning_outcomes) - if typeof(course_learning_outcomes) == Bool && !course_learning_outcomes - return false - end - end + if isinstance(course_learning_outcomes, bool) and not course_learning_outcomes: + return False df_curric_learning_outcomes = "" - if length(read_line)>0 && read_line[1] == "Curriculum Learning Outcomes" + if len(read_line)>0 and read_line[0] == "Curriculum Learning Outcomes": curric_learning_outcomes_start = learning_outcomes_start+learning_outcomes_count+1 - read_line = csv_line_reader(readline(csv_file), ',') - while length(read_line)>0 && !startswith(read_line[1],"#") + read_line = csv_line_reader(csv_file.readline(), ',') + while len(read_line)>0 and not read_line[0].startswith("#"): curric_learning_outcomes_count +=1 - read_line = csv_line_reader(readline(csv_file), ',') - end - if learning_outcomes_count > 1 - df_curric_learning_outcomes = CSV.File(file_path, header = curric_learning_outcomes_start, limit = curric_learning_outcomes_count - 1, delim = ',', silencewarnings = true) |> DataFrame - end - end + read_line = csv_line_reader(csv_file.readline(), ',') + if learning_outcomes_count > 1: + df_curric_learning_outcomes = DataFrame(CSV.File(file_path, header = curric_learning_outcomes_start, limit = curric_learning_outcomes_count - 1, delim = ',', silencewarnings = True) ) - curric_learning_outcomes = if df_curric_learning_outcomes != "" generate_curric_lo(df_curric_learning_outcomes) else LearningOutcome[] end + curric_learning_outcomes =generate_curric_lo(df_curric_learning_outcomes) if df_curric_learning_outcomes != "" else [] - if is_dp + if is_dp: all_courses = read_all_courses(df_all_courses, course_learning_outcomes) - if typeof(all_courses) == Bool && !all_courses - return false - end - all_courses_arr = [course[2] for course in all_courses] + if isinstance(all_courses,bool) and not all_courses: + return False + all_courses_arr = [course[1] for course in all_courses] additional_courses = read_courses(df_additional_courses, all_courses) - ac_arr = Course[] - for course in additional_courses - push!(ac_arr, course[2]) - end + ac_arr = [] + for course in additional_courses: + ac_arr.append( course[1]) curric = Curriculum(curric_name, all_courses_arr, learning_outcomes = curric_learning_outcomes, degree_type = curric_dtype, system_type=curric_stype, institution=curric_inst, CIP=curric_CIP) terms = read_terms(df_all_courses, all_courses, all_courses_arr) #If some courses has term informations but some does not - if isa(terms, Tuple) + if isinstance(terms, tuple): #Add curriculum to the output tuple - output = (terms..., curric, dp_name, ac_arr) # ... operator enumrates the terms - else + output = (*terms, curric, dp_name, ac_arr) # ... operator enumrates the terms + else: degree_plan = DegreePlan(dp_name, curric, terms, ac_arr) output = degree_plan - end else curric_courses = read_all_courses(df_courses, course_learning_outcomes) - if typeof(curric_courses) == Bool && !curric_courses - return false - end - curric_courses_arr = [course[2] for course in curric_courses] + if isinstance(curric_courses,bool) and not curric_courses: + return False + curric_courses_arr = [course[1] for course in curric_courses] curric = Curriculum(curric_name, curric_courses_arr, learning_outcomes = curric_learning_outcomes, degree_type = curric_dtype, system_type=curric_stype, institution=curric_inst, CIP=curric_CIP) output = curric - end - end # Current file is the temp file created by remove_empty_lines(), remove the file. - if file_path[end-8:end] == "_temp.csv" - GC.gc() - rm(file_path) - end + if file_path[-8:] == "_temp.csv": + # GC.gc() # TODO + os.remove(file_path) return output -end -""" - write_csv(c:Curriculum, file_path:AbstractString) +def write_csv(curric:Curriculum, file_path:str; iostream=False, metrics=False)->Union[]: + """ + write_csv(c:Curriculum, file_path:AbstractString) -Write (i.e., serialize) a `Curriculum` data object to disk as a CSV file. To read -(i.e., deserialize) a curriculum CSV file, use the corresponding `read_csv` function. -The file format used to store curricula is described in [File Format](@ref). + Write (i.e., serialize) a `Curriculum` data object to disk as a CSV file. To read + (i.e., deserialize) a curriculum CSV file, use the corresponding `read_csv` function. + The file format used to store curricula is described in [File Format](@ref). -# Arguments -- `c:Curriculum` : the `Curriculum` data object to be serialized. -- `file_path:AbstractString` : the absolute or relative path where the CSV file will be stored. + # Arguments + - `c:Curriculum` : the `Curriculum` data object to be serialized. + - `file_path:AbstractString` : the absolute or relative path where the CSV file will be stored. -# Examples: -```julia-repl -julia> write_csv(c, "./mydata/UBW_curric.csv") -``` -""" -function write_csv(curric:Curriculum, file_path:AbstractString; iostream=false, metrics=false) + # Examples: + ```julia-repl + julia> write_csv(c, "./mydata/UBW_curric.csv") + ``` + """ if iostream == true csv_file = IOBuffer() write_csv_content(csv_file, curric, false, metrics=metrics) diff --git a/src/DataTypes/Course.py b/src/DataTypes/Course.py index df56f55..af12b4f 100644 --- a/src/DataTypes/Course.py +++ b/src/DataTypes/Course.py @@ -2,6 +2,7 @@ from typing import Any, Dict, List from src.DataTypes.DataTypes import Requisite +from src.DataTypes.LearningOutcome import LearningOutcome # Course-related data types: @@ -25,6 +26,26 @@ class AbstractCourse(ABC): id: int "Unique course id" + vertex_id: Dict[int, int] + "The vertex id of the course w/in a curriculum graph, stored as (curriculum_id, vertex_id)" + name: str + "Name of the course, e.g., Introduction to Psychology" + credit_hours: float + 'Number of credit hours associated with course or a "typcial" course in the collection. For the purpose of analytics, variable credits are not supported' + institution: str + "Institution offering the course" + college: str + "College or school (within the institution) offering the course" + department: str + "Department (within the school or college) offering the course" + canonical_name: str + "Standard name used to denote the course in the discipline, e.g., Psychology I, or course collection, e.g., math genearl education" + requisites: Dict[int, Requisite] + "List of requisites, in (requisite_course id, requisite_type) format" + metrics: Dict[str, Any] + "Course-related metrics" + metadata: Dict[str, Any] + "Course-related metadata" ############################################################## @@ -52,34 +73,14 @@ class Course(AbstractCourse): ``` """ - vertex_id: Dict[int, int] - "The vertex id of the course w/in a curriculum graph, stored as (curriculum_id, vertex_id)" - name: str - "Name of the course, e.g., Introduction to Psychology" - credit_hours: float - "Number of credit hours associated with course. For the purpose of analytics, variable credits are not supported" prefix: str "Typcially a department prefix, e.g., PSY" num: str "Course number, e.g., 101, or 302L" - institution: str - "Institution offering the course" - college: str - "College or school (within the institution) offering the course" - department: str - "Department (within the school or college) offering the course" cross_listed: List["Course"] 'courses that are cross-listed with the course (same as "also offered as")' - canonical_name: str - "Standard name used to denote the course in the discipline, e.g., Psychology I" - requisites: Dict[int, Requisite] - "List of requisites, in (requisite_course id, requisite_type) format" learning_outcomes: List[LearningOutcome] "A list of learning outcomes associated with the course" - metrics: Dict[str, Any] - "Course-related metrics" - metadata: Dict[str, Any] - "Course-related metadata" passrate: float "Percentage of students that pass the course" @@ -95,7 +96,7 @@ def __init__( institution: str = "", college: str = "", department: str = "", - cross_listed: List[Course] = [], + cross_listed: List["Course"] = [], canonical_name: str = "", id: int = 0, passrate: float = 0.5, @@ -124,6 +125,40 @@ def __init__( self.passrate = passrate +class CourseCollection(AbstractCourse): + courses: List[Course] + "Courses associated with the collection " + + # Constructor + def __init__( + self, + name: str, + credit_hours: float, + courses: List[Course], + institution: str = "", + college: str = "", + department: str = "", + canonical_name: str = "", + id: int = 0, + ) -> None: + self.name = name + self.credit_hours = credit_hours + self.courses = courses + self.institution = institution + if id == 0: + self.id = hash(self.name + self.institution + str(len(courses))) + else: + self.id = id + self.college = college + self.department = department + self.canonical_name = canonical_name + self.requisites = {} + # self.requisite_formula + self.metrics = {} + self.metadata = {} + self.vertex_id = {} # curriculum id -> vertex id + + def course_id(prefix: str, num: str, name: str, institution: str) -> int: return hash(name + prefix + num + institution) diff --git a/src/DataTypes/Curriculum.py b/src/DataTypes/Curriculum.py index 3a7b1fb..563a299 100644 --- a/src/DataTypes/Curriculum.py +++ b/src/DataTypes/Curriculum.py @@ -1,10 +1,12 @@ ############################################################## # Curriculum data type # The required curriculum associated with a degree program -from typing import Any, List, Optional +from typing import Any, Dict, List, Optional +from src.CurricularAnalytics import isvalid_curriculum -from src.DataTypes.Course import AbstractCourse +from src.DataTypes.Course import AbstractCourse, Course, add_requisite from src.DataTypes.DataTypes import System, belong_to, c_to_c, lo_to_c, lo_to_lo, pre, semester +from src.DataTypes.LearningOutcome import LearningOutcome class Curriculum: @@ -42,7 +44,7 @@ class Curriculum: "Type of degree_type" system_type:System "Semester or quarter system" - CIP:str + cip:str "CIP code associated with the curriculum" courses:List[AbstractCourse] "Array of required courses in curriculum" @@ -75,10 +77,10 @@ def __init__(self, name:str, courses:List[AbstractCourse], learning_outcomes:Lis self.system_type = system_type self.institution = institution if id == 0: - self.id = hash(self.name * self.institution * string(self.degree_type)) + self.id = hash(self.name + self.institution + str(self.degree_type)) else: self.id = id - self.CIP = CIP + self.cip = CIP if sortby_ID: self.courses = sorted(courses, key = lambda c: c.id) else: @@ -129,7 +131,7 @@ def map_lo_vertex_ids(curriculum:Curriculum)-> Dict[int, int]: mapped_ids[lo.id] = lo.vertex_id[curriculum.id] return mapped_ids -def course(curric:Curriculum, prefix:str, num:str, name:str, institution:str) -> None: +def course(curric:Curriculum, prefix:str, num:str, name:str, institution:str) -> Course: "Compute the hash value used to create the id for a course, and return the course if it exists in the curriculum supplied as input" hash_val = hash(name + prefix + num + institution) if hash_val in (c.id for c in curric.courses): diff --git a/src/DataTypes/Simulation.py b/src/DataTypes/Simulation.py index 5e44bc2..8051e48 100644 --- a/src/DataTypes/Simulation.py +++ b/src/DataTypes/Simulation.py @@ -1,66 +1,67 @@ from typing import List +from src.DataTypes.DegreePlan import DegreePlan from src.DataTypes.Student import Student class Simulation: - degree_plan:DegreePlan - "The curriculum that is simulated" - duration:int - "The number of terms the simulation runs for" - course_attempt_limit:int - "The number of times that a course is allowed to take" + degree_plan: DegreePlan + "The curriculum that is simulated" + duration: int + "The number of terms the simulation runs for" + course_attempt_limit: int + "The number of times that a course is allowed to take" - prediction_model:Module - "Module that implements the model for predicting student's performance in courses" + prediction_model: Module + "Module that implements the model for predicting student's performance in courses" - num_students:int - "The number of students in the simulation" - enrolled_students:List[Student] - "Array of students that are enrolled" - graduated_students:List[Student] - "Array of students that have graduated" - stopout_students:List[Student] - "Array of students who stopped out" + num_students: int + "The number of students in the simulation" + enrolled_students: List[Student] + "Array of students that are enrolled" + graduated_students: List[Student] + "Array of students that have graduated" + stopout_students: List[Student] + "Array of students who stopped out" - reach_attempts_students:List[Student] - "Array of students who have reached max course attempts" - reach_attempts_rates:List[float] - "Array of student reaching max course attemps rates" + reach_attempts_students: List[Student] + "Array of students who have reached max course attempts" + reach_attempts_rates: List[float] + "Array of student reaching max course attemps rates" - student_progress:List[int] - "Indicates wheter students have passed each course" - student_attemps:List[int] - "Number of attemps that students have taken for each course" + student_progress: List[int] + "Indicates wheter students have passed each course" + student_attemps: List[int] + "Number of attemps that students have taken for each course" - grad_rate:float - "Graduation rate at the end of the simulation" - term_grad_rates:List[float] - "Array of graduation rates at the end of the simulation" - time_to_degree:float - "Average number of semesters it takes to graduate students" - stopout_rate:float - "Stopout rate at the end of the simulation" - term_stopout_rates:List[float] - "Array of stopout rates for each term" + grad_rate: float + "Graduation rate at the end of the simulation" + term_grad_rates: List[float] + "Array of graduation rates at the end of the simulation" + time_to_degree: float + "Average number of semesters it takes to graduate students" + stopout_rate: float + "Stopout rate at the end of the simulation" + term_stopout_rates: List[float] + "Array of stopout rates for each term" - def __init__(self,degree_plan:DegreePlan) -> None: + def __init__(self, degree_plan: DegreePlan) -> None: - self.degree_plan = degree_plan - self.enrolled_students = [] - self.graduated_students = [] - self.stopout_students = [] + self.degree_plan = degree_plan + self.enrolled_students = [] + self.graduated_students = [] + self.stopout_students = [] - # Set up degree plan - degree_plan.metadata["stopout_model"] = {} + # Set up degree plan + degree_plan.metadata["stopout_model"] = {} - # Set up courses - for (id, course) in enumerate(degree_plan.curriculum.courses) - course.metadata["id"] = id - course.metadata["failures"] = 0 - course.metadata["enrolled"] = 0 - course.metadata["passrate"] = 0 - course.metadata["term_req"] = 0 - course.metadata["grades"] = [] - course.metadata["students"] = [] - course.metadata["model"] = {} + # Set up courses + for (id, course) in enumerate(degree_plan.curriculum.courses): + course.metadata["id"] = id + course.metadata["failures"] = 0 + course.metadata["enrolled"] = 0 + course.metadata["passrate"] = 0 + course.metadata["term_req"] = 0 + course.metadata["grades"] = [] + course.metadata["students"] = [] + course.metadata["model"] = {} diff --git a/src/DegreePlanCreation.py b/src/DegreePlanCreation.py index 0d3093e..02ab21c 100644 --- a/src/DegreePlanCreation.py +++ b/src/DegreePlanCreation.py @@ -47,9 +47,9 @@ def bin_filling( term_credits = c.credit_hours # if c serves as a strict-corequisite for other courses, include them in current term too for course in UC: - for req in course.requisites: - if req[1] == c.id: - if req[2] == strict_co: + for req in course.requisites.items(): + if req[0] == c.id: + if req[1] == strict_co: UC.remove(course) term_courses.append(course) term_credits = term_credits + course.credit_hours