canvasapp/semesters.py

493 lines
12 KiB
Python

# Try to gather all the different formats and ways of labeling a semester, along with their associated dates.
import json, funcy, re, sys
# sem_to_short = { 'Summer 2021': 'su21', 'Fall 2021':'fa21', 'Winter 2022':'wi22', 'Spring 2022':'sp22', 'Summer 2022':'su22', 'Fall 2022':'fa22' }
season_to_number = { 'Fall': '70', 'Summer': '50', 'Spring': '30', 'Winter': '10'}
# Inverse
number_to_season = {v: k for k, v in season_to_number.items()}
s_to_n = {'sp':'30','su':'50','fa':'70'}
season_to_short = {
'Summer': 'su',
'Fall': 'fa',
'Winter': 'wi',
'Spring': 'sp'
}
# Given 'fa22' return 202270
def short_to_sis(s):
season = s[0:2]
return "20" + s[2:5] + s_to_n[season]
# go from sp20 to 2020spring
def short_to_long(s):
parts = re.search(r'(\w\w)(\d\d)', s)
yr = parts.group(2)
season = parts.group(1)
seasons = {'sp':'spring','su':'summer','fa':'fall','wi':'winter'}
return '20'+yr+seasons[season]
# from "Summer 2024" or "2024 Summer" to ("Summer", 2024)
def normalize(label):
"""Return (season, year) tuple, or None if not standard."""
m = re.search(r'(Fall|Summer|Spring|Winter)\s+(\d{4})', label, re.I)
if m:
return (m.group(1).title(), int(m.group(2)))
else:
m = re.search(r'(\d{4})\s+(Fall|Summer|Spring|Winter)', label, re.I)
if m:
return (m.group(2), int(m.group(1).title()))
return None
# from "Summer 2024" to 202450
def human_to_sis(semester):
try:
# Split the semester into its components
parts = semester.split()
# Extract the season and year
season = parts[0]
year = parts[1]
# Generate the code in the format "YYYYSS"
return f"{year}{season_to_number[season]}"
except Exception as e:
print(f"Couldn't parse semester: {semester}'")
return ''
# from 202450 to "Summer 2024"
def sis_to_human(sis_code):
try:
# Extract the year and season code
year = sis_code[:4]
season_code = sis_code[4:]
# Convert season code back to season name
season = number_to_season.get(season_code, "Unknown")
return f"{season} {year}"
except Exception as e:
print(f"Couldn't parse SIS code: {sis_code}")
return ''
# from "Summer 2024" to su24
def human_to_short(semester):
# Split the semester into its components
parts = semester.split()
# Extract the season and year
season = parts[0]
year = parts[1][2:] # Take the last two digits of the year
# Generate the short form
return f"{season_to_short[season]}{year}"
# given human readable form (Spring 2023) return that of the previous semester. Excluding winter.
def get_previous_season(season_year_str):
season_order = {"Spring": "Fall", "Summer": "Spring", "Fall": "Summer"}
try:
season, year = season_year_str.split()
year = int(year)
if season not in season_order or not (2000 <= year <= 2030):
raise ValueError("Invalid season or year")
previous_season = season_order[season]
# Decrement the year if transitioning from Spring to Fall
if season == "Spring":
year -= 1
return f"{previous_season} {year}"
except Exception as e:
return f"Error: {e}"
standard = ['Fall 2026', 'Summer 2026', 'Spring 2026', 'Winter 2026',
'Fall 2025', 'Summer 2025', 'Spring 2025', 'Winter 2025',
'Fall 2024', 'Summer 2024', 'Spring 2024', 'Winter 2024',
'Fall 2023', 'Summer 2023', 'Spring 2023', 'Winter 2023',
'Fall 2022', 'Summer 2022', 'Spring 2022', 'Winter 2022',
'Fall 2021', 'Summer 2021', 'Spring 2021',
'Fall 2020', 'Summer 2020', 'Spring 2020', 'Winter 2020',
'Fall 2019', 'Summer 2019', 'Spring 2019', 'Winter 2019',
'Fall 2018', 'Summer 2018', 'Spring 2018',
'Fall 2017', 'Summer 2017', 'Spring 2017', ]
code = 'fa26,su26,sp26,wi26,fa25,su25,sp25,wi25,fa24,su24,sp24,wi24,fa23,su23,sp23,wi23,fa22,su22,sp22,wi22,fa21,su21,sp21,fa20,su20,sp20,wi20,fa19,su19,sp19,wi19,fa18,su18,sp18,fa17,su17,sp17'.split(',')
begin = ['08/25','05/22','01/26','01/01', # not sure on fa26
'08/25','05/27','01/27','01/02',
'08/26','06/10','01/29','01/02',
'08/28','06/12','01/30','01/03',
'08/22','06/13','01/31','01/04',
'08/23','06/14','02/01',
'08/24','06/15','01/27','01/02',
'08/26','06/17','01/28','01/02',
'08/27','06/18','01/29',
'08/28','06/19','01/30']
canvas_label = []
sems_by_human_name = {}
startdate_by_code = dict(zip(code,begin))
for s in list(zip(standard,code,begin)):
season,year = s[0].split(' ')
cl = year + " " + season
sem_record = {'name': s[0], 'code': s[1], 'start': s[2] + '/' + s[1][-2:], 'number': year + season_to_number[s[0].split(' ')[0]]}
sems_by_human_name[s[0]] = sem_record
sems_by_human_name[s[1]] = sem_record
canvas_label.append(cl)
sems_by_human_name[cl] = sem_record
sems_by_short_name = funcy.project(sems_by_human_name, code)
def dump():
print("BY HUMAN READABLE NAME")
print(json.dumps(sems_by_human_name,indent=2))
print("\n\nBY SEM SHORTCODE")
print(json.dumps(sems_by_short_name,indent=2))
GET_FRESH_TERMS = 1
if (GET_FRESH_TERMS):
from pipelines import url, fetch_collapse
import codecs
canvas_terms = fetch_collapse(f'{url}/api/v1/accounts/1/terms', 'enrollment_terms')
ff = codecs.open('cache/courses/terms.txt', 'w', 'utf-8') # TODO unsafe overwrite
ff.write(json.dumps(canvas_terms, indent=2))
ff.close()
else:
canvas_terms = json.loads(open('cache/courses/terms.txt', 'r').read())
# Build main records from standard list
records = {}
for std, code_str, start in zip(standard, code, begin):
season, year = normalize(std)
records[(season, year)] = {
'standard': std,
'code': code_str,
'begin': start,
'canvas_term_id': None,
'canvas_name': None,
'canvas_start_at': None,
'canvas_end_at': None
}
# Attach canvas term ids where possible
for term in canvas_terms: # term_id, label
key = normalize(term['name'])
if key and key in records:
records[key]['canvas_term_id'] = term['id']
records[key]['canvas_name'] = term['name']
records[key]['canvas_start_at'] = term['start_at']
records[key]['canvas_end_at'] = term['end_at']
# Build alias lookup
lookup = {}
for key, rec in records.items():
season, year = key
aliases = [
rec['standard'],
f"{year} {season}",
f"{season} {year}",
rec['code'],
rec['canvas_name'] if rec['canvas_name'] else None,
str(rec['canvas_term_id'])
]
for alias in aliases:
if alias:
lookup[alias.lower()] = rec
def find_term(s):
return lookup.get(s.lower())
#print(find_term("2025 Fall"))
# {'standard': 'Fall 2025', 'code': 'fa25', 'begin': '08/25',
# 'canvas_term_id': 289, 'canvas_label': '2025 Fall'}
#print(find_term("fa25"))
# Same record as above
#print(find_term("Fall 2025"))
# Same record as above
def weeks_from_date():
from datetime import datetime, timedelta
weeks = int( input("how many weeks ahead? "))
# Replace this with your starting date
x = datetime.strptime("2025-05-27", "%Y-%m-%d")
# Add six weeks
six_weeks_later = x + timedelta(weeks=weeks)
print("Six weeks later:", six_weeks_later.strftime("%Y-%m-%d"))
if __name__ == "__main__":
print ('')
options = { 1: ['print semester info',dump] ,
2: ['compute x weeks from date', weeks_from_date ],
}
if len(sys.argv) > 1 and re.search(r'^\d+',sys.argv[1]):
resp = int(sys.argv[1])
print("\n\nPerforming: %s\n\n" % options[resp][0])
else:
print ('')
for key in options:
print(str(key) + '.\t' + options[key][0])
print('')
resp = input('Choose: ')
# Call the function in the options dict
options[ int(resp)][1]()
"""
semester_list = {
"Fall 2022": {
"name": "Fall 2022",
"code": "fa22",
"start": "08/22/22"
},
"fa22": {
"name": "Fall 2022",
"code": "fa22",
"start": "08/22/22"
},
"2022 Fall": {
"name": "Fall 2022",
"code": "fa22",
"start": "08/22/22"
},
"Summer 2022": {
"name": "Summer 2022",
"code": "su22",
"start": "06/13/22"
},
"su22": {
"name": "Summer 2022",
"code": "su22",
"start": "06/13/22"
},
"2022 Summer": {
"name": "Summer 2022",
"code": "su22",
"start": "06/13/22"
},
"Spring 2022": {
"name": "Spring 2022",
"code": "sp22",
"start": "01/31/22"
},
"sp22": {
"name": "Spring 2022",
"code": "sp22",
"start": "01/31/22"
},
"2022 Spring": {
"name": "Spring 2022",
"code": "sp22",
"start": "01/31/22"
},
"Fall 2021": {
"name": "Fall 2021",
"code": "fa21",
"start": "08/23/21"
},
"fa21": {
"name": "Fall 2021",
"code": "fa21",
"start": "08/23/21"
},
"2021 Fall": {
"name": "Fall 2021",
"code": "fa21",
"start": "08/23/21"
},
"Summer 2021": {
"name": "Summer 2021",
"code": "su21",
"start": "06/14/21"
},
"su21": {
"name": "Summer 2021",
"code": "su21",
"start": "06/14/21"
},
"2021 Summer": {
"name": "Summer 2021",
"code": "su21",
"start": "06/14/21"
},
"Spring 2021": {
"name": "Spring 2021",
"code": "sp21",
"start": "02/01/21"
},
"sp21": {
"name": "Spring 2021",
"code": "sp21",
"start": "02/01/21"
},
"2021 Spring": {
"name": "Spring 2021",
"code": "sp21",
"start": "02/01/21"
},
"Fall 2020": {
"name": "Fall 2020",
"code": "fa20",
"start": "08/24/20"
},
"fa20": {
"name": "Fall 2020",
"code": "fa20",
"start": "08/24/20"
},
"2020 Fall": {
"name": "Fall 2020",
"code": "fa20",
"start": "08/24/20"
},
"Summer 2020": {
"name": "Summer 2020",
"code": "su20",
"start": "06/15/20"
},
"su20": {
"name": "Summer 2020",
"code": "su20",
"start": "06/15/20"
},
"2020 Summer": {
"name": "Summer 2020",
"code": "su20",
"start": "06/15/20"
},
"Spring 2020": {
"name": "Spring 2020",
"code": "sp20",
"start": "01/27/20"
},
"sp20": {
"name": "Spring 2020",
"code": "sp20",
"start": "01/27/20"
},
"2020 Spring": {
"name": "Spring 2020",
"code": "sp20",
"start": "01/27/20"
},
"Fall 2019": {
"name": "Fall 2019",
"code": "fa19",
"start": "08/26/19"
},
"fa19": {
"name": "Fall 2019",
"code": "fa19",
"start": "08/26/19"
},
"2019 Fall": {
"name": "Fall 2019",
"code": "fa19",
"start": "08/26/19"
},
"Summer 2019": {
"name": "Summer 2019",
"code": "su19",
"start": "06/17/19"
},
"su19": {
"name": "Summer 2019",
"code": "su19",
"start": "06/17/19"
},
"2019 Summer": {
"name": "Summer 2019",
"code": "su19",
"start": "06/17/19"
},
"Spring 2019": {
"name": "Spring 2019",
"code": "sp19",
"start": "01/28/19"
},
"sp19": {
"name": "Spring 2019",
"code": "sp19",
"start": "01/28/19"
},
"2019 Spring": {
"name": "Spring 2019",
"code": "sp19",
"start": "01/28/19"
},
"Fall 2018": {
"name": "Fall 2018",
"code": "fa18",
"start": "08/27/18"
},
"fa18": {
"name": "Fall 2018",
"code": "fa18",
"start": "08/27/18"
},
"2018 Fall": {
"name": "Fall 2018",
"code": "fa18",
"start": "08/27/18"
},
"Summer 2018": {
"name": "Summer 2018",
"code": "su18",
"start": "06/18/18"
},
"su18": {
"name": "Summer 2018",
"code": "su18",
"start": "06/18/18"
},
"2018 Summer": {
"name": "Summer 2018",
"code": "su18",
"start": "06/18/18"
},
"Spring 2018": {
"name": "Spring 2018",
"code": "sp18",
"start": "01/29/18"
},
"sp18": {
"name": "Spring 2018",
"code": "sp18",
"start": "01/29/18"
},
"2018 Spring": {
"name": "Spring 2018",
"code": "sp18",
"start": "01/29/18"
}
}
"""