Files
CSC110/assignments/a2/a2_part4.py
T
2021-10-03 16:05:00 -04:00

170 lines
6.9 KiB
Python

"""CSC110 Fall 2020 Assignment 2, Part 4: Processing Raw Course Data
Instructions (READ THIS FIRST!)
===============================
This Python module contains the functions you should complete for Part 4 of this assignment.
Your task is to complete this module by writing the body of the functions so that they do what
their descriptions claim.
You may, but are not required, to write doctests for this part.
Copyright and Usage Information
===============================
This file is provided solely for the personal and private use of students
taking CSC110 at the University of Toronto St. George campus. All forms of
distribution of this code, whether as given or with any changes, are
expressly prohibited. For more information on copyright for CSC110 materials,
please consult our Course Syllabus.
This file is Copyright (c) 2021 David Liu, Mario Badr, and Tom Fairgrieve.
"""
import datetime
import json
import a2_part3
###################################################################################################
# Part 4: Processing Raw Data
###################################################################################################
def read_course_data(file: str) -> dict:
"""Return a dictionary mapping course codes to course data from the data in the given file.
In the returned dictionary:
- each key is a string representing the course code
- each corresponding value is a tuple representing a course value, in the format
descried in Part 3 of the assignment handout.
Note that the implementation of this function provided to you is INCOMPLETE since it just
returns a dictionary in the same format as the raw JSON file. It's your job to implement
the functions below, and then modify this function body to get the returned data
in the right format.
Preconditions:
- file is the path to a JSON file containing course data using the same format as
the data in data/course_data_small.json.
file is the name (or path) of a JSON file containing course data using the format in
the sample file course_data_small.json.
"""
with open(file) as json_file:
data = json.load(json_file)
return {raw['courseCode']: transform_course_data(raw) for raw in data.values()}
def transform_course_data(course_data: dict) -> tuple[str, str, set]:
"""Transform the given course_data into a tuple representing that course.
The returned tuple is in the course format described on the assignment handout.
Preconditions:
- course_data is a dictionary containing data about a single course, in the format
found in course_data_small.json.
"""
return course_data['courseCode'], \
course_data['courseTitle'], \
{transform_section_data(s) for s in course_data['sections']}
def transform_section_data(section_data: dict) -> tuple[str, str, tuple]:
"""Transform the given section_data into a tuple representing that section.
The returned tuple is in the "section" format described on the assignment handout.
Preconditions:
- section_data is a dictionary containing data about a single section, in the format
found in course_data_small.json.
"""
return section_data['sectionCode'], \
section_data['term'], \
tuple([transform_meeting_time_data(m) for m in section_data['meetingTimes']])
def transform_meeting_time_data(meeting_time_data: dict) \
-> tuple[str, datetime.time, datetime.time]:
"""Transform the given meeting_time_data into a tuple representing that section.
The returned tuple is in the "meeting time" format described on the assignment handout.
Preconditions:
- meeting_time_data is a dictionary containing data about a single meeting time, in the
format found in course_data_small.json.
Hint: The times in the JSON file are length-5 strings in format HH:MM using a 24-hour clock.
You'll need to do some string processing to extract the hours and minutes, and convert
these to ints and then to a datetime.time. The str.split method is one approach.
"""
return str(meeting_time_data['day']), \
datetime.time(int(meeting_time_data['startTime'][:2])), \
datetime.time(int(meeting_time_data['endTime'][:2]))
def get_valid_schedules(course_data: dict[str, tuple[str, str, set]],
courses: set[str],
term: str) -> list[dict[str, tuple]]:
"""Return a list of all valid schedules for the given courses and in the given term.
courses is a set of course codes; use the given course_data to look up each course code
to get the corresponding course tuple.
All sections in each returned schedule should meet in the given term; 'Y' sections meet
in both 'F' and 'S' terms.
Return an empty list if there are no valid schedules for the given course codes, or if
at least one of the courses does not have any sections that meet in the given term.
Preconditions:
- len(courses) == 5
- term in {'F', 'S'}
- all({course_code in course_data for course_code in courses})
Hints:
1. You can use a2_part3.valid_five_course_schedules.
2. You'll need to process each course to filter to keep only the sections
that appear in the given term. See the function we've started for you below.
"""
valid_courses = [course_data[code] for code in course_data if code in courses]
a, b, c, d, e = [filter_by_term(course, term) for course in valid_courses]
return a2_part3.valid_five_course_schedules(a, b, c, d, e)
def filter_by_term(course: tuple[str, str, set], term: str) -> tuple[str, str, set]:
"""Return a copy of the given course with only sections that meet in the given term.
The returned tuple has the same course code and title as the given course, and its
sections set is a subset of the original.
Note that a 'Y' section meets in BOTH 'F' and 'S' terms, and so should always be
included in the returned course tuple.
Preconditions:
- term in {'F', 'S'}
"""
return course[0], course[1], {s for s in course[2] if s[1] == 'Y' or s[1] == term}
if __name__ == '__main__':
import python_ta
import python_ta.contracts
python_ta.contracts.DEBUG_CONTRACTS = False
python_ta.contracts.check_all_contracts()
import doctest
doctest.testmod()
print(read_course_data('data/course_data_small.json'))
# When you are ready to check your work with python_ta, uncomment the following lines.
# (Delete the "#" and space before each line.)
# IMPORTANT: keep this code indented inside the "if __name__ == '__main__'" block
# IMPORTANT: Leave this code uncommented when you submit your files.
# python_ta.check_all(config={
# 'extra-imports': ['a2_part3', 'datetime', 'json', 'python_ta.contracts'],
# 'max-line-length': 100,
# 'disable': ['R1705'],
# 'allowed-io': ['read_course_data']
# })