|
| 1 | +""" |
| 2 | + Create a script that will update availability and hours for mentors in preparation for adhoc registration for a specified month |
| 3 | +""" |
| 4 | +# !/usr/bin/env python |
| 5 | + |
| 6 | +import logging |
| 7 | +import sys |
| 8 | +import pandas as pd |
| 9 | +from ruamel.yaml import YAML |
| 10 | + |
| 11 | +yaml = YAML() |
| 12 | +yaml.width = 4096 |
| 13 | + |
| 14 | +TYPE_LONG_TERM = "long-term" |
| 15 | +TYPE_AD_HOC = "ad-hoc" |
| 16 | +TYPE_BOTH = "both" |
| 17 | + |
| 18 | +MONTHS_MAP = { |
| 19 | + 4: 'April', |
| 20 | + 5: 'May', |
| 21 | + 6: 'June', |
| 22 | + 7: 'July', |
| 23 | + 8: 'August', |
| 24 | + 9: 'September', |
| 25 | + 10: 'October', |
| 26 | + 11: 'November' |
| 27 | +} |
| 28 | + |
| 29 | + |
| 30 | +def get_available_mentor_sort(mentor, current_availability): |
| 31 | + """ |
| 32 | + Returns sort value for available mentors ONLY if: |
| 33 | + - mentor is new (current availability still contains full list of months), sort to highest: 500 |
| 34 | + - mentor has >3 available hours, sort to highest: 500 |
| 35 | + - 3 or less hours, sort: 200 |
| 36 | +
|
| 37 | + Note: sort logic for unavailable mentors is split on purpose (see update_mentor_availability function) |
| 38 | +
|
| 39 | + Guide: https://docs.google.com/document/d/1GwlleBNScHCQ3K8rgvYIB3upIr1BylgWjGR2jxwYWtI/edit?tab=t.0 |
| 40 | + """ |
| 41 | + |
| 42 | + if len(current_availability) > 1 or mentor.get('hours') > 3: |
| 43 | + return 500 |
| 44 | + |
| 45 | + return 200 |
| 46 | + |
| 47 | + |
| 48 | +def get_unavailable_mentor_sort(mentor): |
| 49 | + """ |
| 50 | + Returns sort value for unavailable mentor if: |
| 51 | + - mentor is ad-hoc only or both but no available hours for the month, sort: 100 |
| 52 | + - mentor is long-term only, sort: 10 |
| 53 | + - mentor is deactivated, sort: 1 |
| 54 | + """ |
| 55 | + if mentor.get("disabled", True): |
| 56 | + return 1 |
| 57 | + |
| 58 | + if mentor.get("type") == TYPE_LONG_TERM: |
| 59 | + return 10 |
| 60 | + |
| 61 | + return 100 |
| 62 | + |
| 63 | + |
| 64 | +def get_availability_update_dict(available_mentors): |
| 65 | + """ |
| 66 | + Returns a dictionary mapping mentor to their available hours (from spreadsheet file) |
| 67 | + - If hours column in spreadsheet is empty/non-numeric, the value will be None (indicating existing hours should be kept) |
| 68 | + """ |
| 69 | + availability_update_dict = {} |
| 70 | + |
| 71 | + for _, row in available_mentors.iterrows(): |
| 72 | + mentor_name = row['Mentor Name'].strip() |
| 73 | + updated_hours = row['Availability (Hours)'] |
| 74 | + |
| 75 | + if pd.isna(updated_hours) or str(updated_hours).strip() == "": |
| 76 | + availability_update_dict[mentor_name] = None |
| 77 | + else: |
| 78 | + availability_update_dict[mentor_name] = updated_hours |
| 79 | + |
| 80 | + return availability_update_dict |
| 81 | + |
| 82 | + |
| 83 | +def update_mentor_availability(month, xlsx_file_path, yml_file_path): |
| 84 | + """ |
| 85 | + Updates mentor availability and hours in the mentors.yml file based on the provided xlsx file for a given month. |
| 86 | + - Mentors not listed in the xlsx file are set to unavailable for the month. |
| 87 | + - Mentors listed in the xlsx file have their availability set to the specified month and hours updated if provided. |
| 88 | + - All mentors are re-sorted according to the guide: https://docs.google.com/document/d/1GwlleBNScHCQ3K8rgvYIB3upIr1BylgWjGR2jxwYWtI/edit?tab=t.0 |
| 89 | + """ |
| 90 | + |
| 91 | + df_available_mentors = pd.read_excel(xlsx_file_path) |
| 92 | + availability_updates = get_availability_update_dict(df_available_mentors) |
| 93 | + |
| 94 | + with open(yml_file_path, 'r') as input_yml: |
| 95 | + mentors = yaml.load(input_yml) or [] |
| 96 | + |
| 97 | + for mentor in mentors: |
| 98 | + yml_name = mentor['name'].strip() |
| 99 | + |
| 100 | + # if mentor is not included in availability file: update sort, set availability to none, and move to next mentor |
| 101 | + if yml_name not in availability_updates: |
| 102 | + mentor['sort'] = get_unavailable_mentor_sort(mentor) |
| 103 | + mentor['availability'] = [] |
| 104 | + continue |
| 105 | + |
| 106 | + # otherwise: mentor is available, update sort and reset availability to the current month only |
| 107 | + current_availability = mentor.get('availability', []) |
| 108 | + mentor['sort'] = get_available_mentor_sort(mentor, current_availability) |
| 109 | + mentor['availability'] = [month] |
| 110 | + |
| 111 | + # Only update hours if updated hours is not None |
| 112 | + updated_hours = availability_updates.get(yml_name) |
| 113 | + if updated_hours is not None: |
| 114 | + logging.info(f"Updating hours for {yml_name} to: {updated_hours}") |
| 115 | + mentor['hours'] = updated_hours |
| 116 | + |
| 117 | + with open(yml_file_path, 'w') as f: |
| 118 | + yaml.default_flow_style = True |
| 119 | + yaml.dump(mentors, f) |
| 120 | + |
| 121 | + print(f"Mentor availabilities updated for month {MONTHS_MAP[month]}.") |
| 122 | + |
| 123 | + |
| 124 | +def run_automation(): |
| 125 | + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
| 126 | + |
| 127 | + mentors_yml_file_path = "../_data/mentors.yml" |
| 128 | + |
| 129 | + if len(sys.argv) == 3: |
| 130 | + xlsx_file_path = sys.argv[1] |
| 131 | + month = int(sys.argv[2]) |
| 132 | + |
| 133 | + logging.info("Using values: xlsx: %s, month: %s", xlsx_file_path, month) |
| 134 | + else: |
| 135 | + xlsx_file_path = "samples/adhoc-prep.xlsx" |
| 136 | + month = 11 |
| 137 | + |
| 138 | + logging.info("Default values: xlsx: %s, month: %s", xlsx_file_path, month) |
| 139 | + |
| 140 | + update_mentor_availability(month, xlsx_file_path, mentors_yml_file_path) |
| 141 | + |
| 142 | + |
| 143 | +if __name__ == "__main__": |
| 144 | + run_automation() |
0 commit comments