#!/usr/bin/python3 # Create HTML files with Selection evaluation results for each participant # in current directory. Creates evaluation.html and reviews/ # # cd Selection # usage: python3 ../create-evaluation-files.py \ # ../registrations.csv ../reviews.csv [../assign-*.csv] # # Some --- columns needs to be renamed in evaluation-results.csv # First column --- to -o- # Column --- for each preference stating Does not meet requirements needs to be renamed to -n- # import sys import csv import os import re import string from posix import unlink from datetime import datetime from collections import Counter import glob # enter SoHPC year SoHPC_year = "2022" # # Basic skeleton of html file (header, footer and content in the middle (parameter 3) # Also include place holders for file title (0) and date (1) skeleton = """ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="CACHE-CONTROL" content="NO-CACHE"> <meta http-equiv="EXPIRES" content="0"> <title>{{TITLE}}</title> <script type="text/javascript"> function goto_project(){ var myselect = document.getElementById("project_id_list"); window.location.href = '#project_'+myselect.options[myselect.selectedIndex].value; } </script> <style> body {background-color:white} .size { background-color: white; margin:0 auto; font-family: arial; font-size: 12px; } div.title { font-size: 16px; font-weight: bold;} div {margin-bottom: 2px;} table.list { width: 100%; padding: 0px; margin: 0px; -webkit-border-vertical-spacing: 0px; } table.list tr:nth-child(even) { background-color: #EFEFEF; } table.list tr.head, table.list tr.foot { background-color: #BBBBBB; } table.list tr.head th { border-bottom: 1px solid #aaaaaa; } table.list tr.foot th { border-top: 1px solid #aaaaaa; } table.list tr td.id { text-align: right; padding-right: 5px; border-left: 0px; } table.list tr:hover { background-color: LightGreen; } td.dataCaptionTD { width: 150px; } td.dataSubCaptionTD { width: 150px; } th.overall_comment, td.overall_comment { width: 15%; vertical-align: top; } table.list tr table.no_bg_coloring tr { background-color: transparent; } table.list tr.registrant_selected { background-color: #ADBDE3; font-weight: bold; } table.list tr.registrant_selected_tentative { background-color: #ee9999; font-weight: bold; } table.list tr.registrant_selected_other { text-decoration: line-through; background-color: #00EFEF; font-style: italic; color: #999999; } table.list tr.registrant_selected_other a { color: #999999; } table.list tr.registrant_withdrawn { text-decoration: line-through; font-style: italic; color: #999999; } table.list tr.registrant_withdrawn a { color: #999999; } </style> </head> <body> <div class=size> <br> <br> <div style="font-size: 16px; text-align: center; font-weight: bold;">Summer of HPC project evaluation results</div> <br><br> <div ><span style="float:right;"><b>Date</b>: {{DATE}}</span></div> {{CONTENT}} </body> </html> """ # # Main content of index.html file. It holds list of projects and particiants (sorted by score) # index_data = """ <br> <a name="projects"></a> Content: [<a href="#projects">Project list</a>] [<a href="#registrants">Registrant list</a>] <br> <br> <h2>PROJECT LIST WITH REGISTRANTS</h2> <table> <tr valign="top"> <td> Projects and selected registrants (students): <table class="list" style="width: auto;"> <tr class="head"> <td>Project: ID - name</td> <td>Selected registrant (link to application)</td> <td>Country</td> <td>Gender</td> <td>Age</td> <td>E-mail</td> <td colspan="2">Evaluation<br>details</td> </tr> {{PROJECT_LIST_AND_SELECTED_PARTICIPANTS}} </table> </td> <td width="10%"> </td> <td> Countries - all and selected. <table class="list"> <tr class="head"> <th> </th> <th colspan="3">Registrants</th> </tr> <tr class="head"> <th>Country</th> <th width="60px">All</th> <th width="60px">Selected</th> <th width="60px">[%]</th> </tr> {{COUNTRY_PARTICIPANTS_LIST}} </table> </td> </tr> </table> <hr> {{CONTENT_PROJECTS}} <br> <br> <br> <hr> <br> <a name="registrants"></a> Content: [<a href="#projects">Project list</a>] [<a href="#registrants">Registrant list</a>] <br> <br> <h2>REGISTRANTS EVALUATIONS</h2> {{CONTENT_REGISTRANTS}} """ # layout of project in TOC project_selected_participant_row = """ <tr> <td rowspan="{{PROJECT_ROW_SPAN}}"><a href="#project_{{PROJECT_ID}}">{{PROJECT_ID}} - {{PROJECT_NAME}}</td> <td>{{PARTICIPANTS_LIST}}</td> </tr> """ # layout of list of participants; value is added to "skeleton" project_html_data = """ <br> <a name="project_{{PROJECT_ID}}"></a> <h3>{{PROJECT_ID}} - {{PROJECT_NAME}}</h3> On mouseover (put mouse cursor above mark) and additional explanation will be displayed. <div style="float: right;"><a href="#projects">[to top]</a></div> <table class="list"> <head> <tr class="head"> <th> </th> <th> </th> <th> </th> <th> </th> <th> </th> <th> </th> <th colspan="2">Comment</th> <th colspan="2">Pref.1</th> <th colspan="2">Pref.2</th> <th colspan="2">Pref.3</th> <th colspan="3">Motivation</th> <th colspan="3">Ambasador</th> <th colspan="3">Technical</th> <th> </th> </tr> <tr class="head"> <th>No.</th> <th>Name (ID)</th> <th>Country</th> <th>Gender</th> <th>Age</th> <th>Choice</th> <th class="overall_comment">P1</th> <th class="overall_comment">P2</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>Average</th> </tr> </thead> <tbody> {{REGISTRANT_DATA}} </tbody> </table> """ # row for project_user_row = """ <tr class="{{REGISTRANT_SELECTED}}"> <td class="id">{{I}}</td> <td><a href="{{HTML_FILENAME}}">{{NAME}} ({{ID}})</a> <a href='{{EVALUATION_HTML_LINK_1}}'>[eval1]</a> <a href='{{EVALUATION_HTML_LINK_2}}'>[eval2]</a></td> <td>{{COUNTRY}}</td> <td align="center">{{GENDER}}</td> <td align="center">{{AGE}}</td> <td class="{{CHOICE}}" align="center">{{CHOICE}}</td> <td align="left" class="overall_comment"><i>{{REVIEWER_1}}:</i><br>{{OVERALL_COMMENT_1}}</td> <td align="left" class="overall_comment"><i>{{REVIEWER_2}}:</i><br>{{OVERALL_COMMENT_2}}</td> <td align="center" title="{{PREFERENCE_1_COMPULSORY}}">{{PREFERENCE_1_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_1_DESIRABLE}}">{{PREFERENCE_1_SHORT_DESIRABLE}}</td> <td align="center" title="{{PREFERENCE_2_COMPULSORY}}">{{PREFERENCE_2_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_2_DESIRABLE}}">{{PREFERENCE_2_SHORT_DESIRABLE}}</td> <td align="center" title="{{PREFERENCE_3_COMPULSORY}}">{{PREFERENCE_3_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_3_DESIRABLE}}">{{PREFERENCE_3_SHORT_DESIRABLE}}</td> <td align="center" title="{{REVIEWER_1}}: {{MOTIVATION_COMMENT_P1}}">{{MOTIVATION_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{MOTIVATION_COMMENT_P2}}">{{MOTIVATION_P2}}</td> <td align="center">{{MOTIVATION_AVG}}</td> <td align="center" title="{{REVIEWER_1}}: {{AMBASADOR_COMMENT_P1}}">{{AMBASADOR_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{AMBASADOR_COMMENT_P2}}">{{AMBASADOR_P2}}</td> <td align="center">{{AMBASADOR_AVG}}</td> <td align="center" title="{{REVIEWER_1}}: {{TECHNICAL_COMMENT_P1}}">{{TECHNICAL_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{TECHNICAL_COMMENT_P2}}">{{TECHNICAL_P2}}</td> <td align="center">{{TECHNICAL_AVG}}</td> <td align="center">{{AVERAGE_P}}</td> </tr> """ # layout of single row for each participant; content is added to "person_data" registrant_list = """ On mouseover (put mouse cursor above mark) and additional explanation will be displayed. <table class="list"> <tr class="head"> <th> </th> <th> </th> <th colspan="2">Comment</th> <th colspan="2">Pref.1</th> <th colspan="2">Pref.2</th> <th colspan="2">Pref.3</th> <th colspan="3">Motivation</th> <th colspan="3">Ambasador</th> <th colspan="3">Technical</th> <th> </th> </tr> <tr class="head"> <th>No.</th> <th>Registrant</th> <th class="overall_comment">P1</th> <th class="overall_comment">P2</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th title="[X] = Student meet compulsory preferences.\n[ ] = Student DOES NOT meet compulsory preferences.">(?)</th> <th title="[X] = Student meet desirable prerequisites.\n[ ] = Student DOES NOT meet desirable preferences.">(?)</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>P1</th> <th>P2</th> <th>Avg</th> <th>Average</th> </tr> {0} <tr class="foot"> <th>No</th> <th>Registrant</th> <th colspan="2">Comment</th> <th colspan="2">Pref.1</th> <th colspan="2">Pref.2</th> <th colspan="2">Pref.3</th> <th colspan="3">Motivation</th> <th colspan="3">Ambasador</th> <th colspan="3">Technical</th> <th>Average</th> </tr> </table> """ # layout of registrant daata + scores of evaluation + average scores person_row = """ <tr class="{{REGISTRANT_SELECTED}}"> <td class="id">{{I}}</td> <td><a href="{{HTML_FILENAME}}">{{REGISTRANT_NAME}}; {{COUNTRY}}, {{GENDER}}, {{AGE}} years (ID: {{REGISTRANT_ID}})</a><br>Preferred projects: {{PROJECT_ID_LIST}}</td> <td align="left" class="overall_comment"><i>{{REVIEWER_1}}:</i><br>{{OVERALL_COMMENT_1}}</td> <td align="left" class="overall_comment"><i>{{REVIEWER_2}}:</i><br>{{OVERALL_COMMENT_2}}</td> <td align="center" title="{{PREFERENCE_1_COMPULSORY}}">{{PREFERENCE_1_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_1_DESIRABLE}}">{{PREFERENCE_1_SHORT_DESIRABLE}}</td> <td align="center" title="{{PREFERENCE_2_COMPULSORY}}">{{PREFERENCE_2_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_2_DESIRABLE}}">{{PREFERENCE_2_SHORT_DESIRABLE}}</td> <td align="center" title="{{PREFERENCE_3_COMPULSORY}}">{{PREFERENCE_3_SHORT_COMPULSORY}}</td> <td align="center" title="{{PREFERENCE_3_DESIRABLE}}">{{PREFERENCE_3_SHORT_DESIRABLE}}</td> <td align="center" title="{{REVIEWER_1}}: {{MOTIVATION_COMMENT_P1}}">{{MOTIVATION_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{MOTIVATION_COMMENT_P2}}">{{MOTIVATION_P2}}</td> <td align="center">{{MOTIVATION_AVG}}</td> <td align="center" title="{{REVIEWER_1}}: {{AMBASADOR_COMMENT_P1}}">{{AMBASADOR_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{AMBASADOR_COMMENT_P2}}">{{AMBASADOR_P2}}</td> <td align="center">{{AMBASADOR_AVG}}</td> <td align="center" title="{{REVIEWER_1}}: {{TECHNICAL_COMMENT_P1}}">{{TECHNICAL_P1}}</td> <td align="center" title="{{REVIEWER_2}}: {{TECHNICAL_COMMENT_P2}}">{{TECHNICAL_P2}}</td> <td align="center">{{TECHNICAL_AVG}}</td> <td align="center">{{AVERAGE_P}}</td> </tr> """ # # Save given title/date/content into given file # def save_content(filename, skeleton, title, date, content): skeleton = skeleton.replace("{{TITLE}}", title) skeleton = skeleton.replace("{{DATE}}", date) skeleton = skeleton.replace("{{CONTENT}}", content) # open file and write content f = open(filename, "w") f.write(skeleton) f.close() return # # Read file and return header and data rows # def read_csv_file(filename): # Open the CSV file for reading -- evaluation data reader = csv.reader(open(filename)) header_org = next(reader) header = [] # correct names of fields (columns); remove all non-printable chars and " include = set(string.printable) for key in header_org: # check all header names/columns name = "".join(ch for ch in key if ch in include) name = name.replace('"', "") header.append(name) #print(header) # get header len = number of fields/columns header_len = len(header) data_rows = [] # Read a single row from the CSV file for row in reader: if len(row) == 0: continue if row[0].startswith('#'): continue if len(row) != header_len: print("BAD DATA ROW ", ", ".join(row)) continue data_rows.append(row) return { "header": header, "rows": data_rows } # # Return number of points (score) for given evaluation part # 0 if not defined. Values are written as %d Points. # def get_points_from_evaluation(value): point = 0 if value: # check #print(value) tmp_point = value.split(" ")[0].strip() if tmp_point: point = int(tmp_point) return point #=========================================================== #== MAIN #=========================================================== # read both files tmp_user_data = read_csv_file(sys.argv[1]) eval_data = read_csv_file(sys.argv[2]) # # create user_data dictionary with id as key and other data as dictionay # for each row, keys are field names user_data = {} for row in tmp_user_data['rows']: # process all rows dic=dict(zip(tmp_user_data['header'], row)) #[print(key) for key in dic.keys()] if dic['ID'] == '': dic['ID'] = 0 id = int(dic['ID']) link = glob.glob('../Application_Form/*_%d' % id) if len(link) == 0: print('Missing Application form for id %d' % id) link = link[0] dic.update({'link_application': "%s/index.html" % link}) user_data.update({id:dic}) # load assignments for a in sys.argv[3:]: for row in read_csv_file(a)['rows']: id = int(row[0]) tentative = False if id < 0: id = -id tentative = True proj = row[1].strip() if user_data[id]['selected'] == proj: pass else: if user_data[id]['selected']: print("trying to reselect student %d from '%s' to '%s'\n" % (id, user_data[id]['selected'], proj)) else: user_data[id]['selected'] = proj user_data[id]['tentative'] = tentative #print(user_data) if not os.path.exists("reviews"): # if does not exist, create cubdir for storing HTML files os.makedirs("reviews") #get_file("cookies.txt", "54-0.pdf", "https://events.prace-ri.eu/event/367/manage/registration/users/54/attachments/0.pdf") print("Creating HTML files: ") # read registrant content template f = open("../evaluation-detail-format.html", "r") evaluation_content = f.read() f.close() n = datetime.now() generation_date = "{0}. {1}. {2} @ {3}:{4}".format(n.day, n.month, n.year, n.hour, n.minute) # data about projects and registrants sorted with project first, then all rgistrant data and scores... project_data = {} student_data = {} country_data = {} for id in user_data: # prepare array for student evaluation data student_data.update({id: {'motivation': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 'ambasador': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 'technical': {'p': ['', ''], 'comment': ['',''], 'avg': 0.}, 'average': 0., 'num_reviewers_done': 0, 'evaluation_detail_file': ['',''], 'reviewer': ['', ''], 'overall_comment': ['', ''], 'preference': [[['',''], ['',''], ['','']], [['',''], ['',''], ['','']]]} }) if user_data[id]['selected'] in ['invalid', 'withdrawn', 'declined']: continue # store countries into separate array ctryName = user_data[id]['Country'] if not ctryName in country_data: # add country to array country_data.update({ctryName : {'all': 0, 'selected': 0, 'percent': 0.0 }}) # add another student country_data[ctryName]['all'] += 1 #print(student_data) #print(eval_data) for row in eval_data['rows']: # loop over all evaluations done_keys = {} dic=dict(zip(eval_data['header'], row)) # print(dic) userID=int(dic["Applicant number"].replace("#","")) reviewerName=dic["Signature"].replace(" ","_") filename = "reviews/{0:03}_{1}.html".format(userID,reviewerName) #print("{0}: {1}".format(userID, user_data[userID]['Name'])) # print(" - evaluation defined") # store points form evaluation sum = 0 numReviewer = student_data[userID]['num_reviewers_done'] if numReviewer < 2: student_data[userID]['evaluation_detail_file'][numReviewer] = filename student_data[userID]['reviewer'][numReviewer] = dic["Signature"] student_data[userID]['overall_comment'][numReviewer] = dic["Overall recommendation and comment"] else: print("{0}: {1}".format(userID, user_data[userID]['Name'])) print(" -->> ERROR: too many reviewers!! -- {0}; only first 2 reviewers used.".format(numReviewer+1)) continue # 2019 remapping remap = { 'motivation': 'Motivation & Enthusiasm', 'ambasador': 'Ambassador Potential', 'technical': 'Technical ability' } for part in ['motivation', 'ambasador', 'technical']: # parse all fields, store the points and compute the average point = get_points_from_evaluation(dic[remap[part]]) #print(" - {0}: {1} -> {2} (reviever num: {3})".format(part, dic[remap[part]], point, numReviewer)) #print(dic[remap[part] + " comment"]) if numReviewer < 2: student_data[userID][part]['p'][numReviewer] = point student_data[userID][part]['comment'][numReviewer] = dic[remap[part] + " comment"] if numReviewer == 0: # average is current values student_data[userID][part]['avg'] = student_data[userID][part]['p'][0] sum += student_data[userID][part]['avg'] else: # compute average from both marks student_data[userID][part]['avg'] = 0.5*(student_data[userID][part]['p'][0]+student_data[userID][part]['p'][1]) sum += student_data[userID][part]['avg'] # compute the average student_data[userID]['average'] = sum/3. student_data[userID]['num_reviewers_done'] += 1 # print(" - avg: {0:.2f}".format(student_data[userID]['average']);) # # generate registrant presentation HTML # content = evaluation_content # current preference currentPreference = '' for i in range(0,len(eval_data['header'])): # loop over header to preserve key order key = eval_data['header'][i] value = row[i].strip().replace("#","") #print(key, "|" + value + "|") # replace value for all keys in row html_fld = key.replace(" ", "_").upper() #print("key: {0}".format(html_fld)) if html_fld in done_keys: # current key was already used in current row; add number at the end #print("found: {0}".format(html_fld)) done_keys[html_fld] += 1 html_fld = "{0}__{1}".format(html_fld, done_keys[html_fld]) else: # key not used; add it to array for checking later done_keys.update({html_fld: 1}) # print("key: " + key + ", html: " + html_fld + ", value=|" + value + "|") #print(done_keys) content = content.replace("{{" + html_fld + "}}", value) if key == "Applicant number": # replace also add/replace participant full name and formated UID {0:03} userID = int(value) tmp_title = user_data[userID]['Name'] formUID = value.strip().zfill(3) content = content.replace("{{REGISTRANT_NAME}}", tmp_title) content = content.replace("{{FORMATED_UID}}", formUID) elif key == "Submission Date": # 2019 format # 2019-03-26 00:33:44.289498+00:00 # display date + time in more nicer format #print(html_fld) if value != '': # n = datetime.strptime(value, '%y-%m-%d %H:%M:%S.%f+%z') # dateTime = "{0}. {1}. {2} @ {3}:{4}".format(n.day, n.month, n.year, n.hour, n.minute) content = content.replace("{{" + html_fld +"_DISP}}", value) else: content = content.replace("{{" + html_fld +"_DISP}}", "") elif key == 'Motivation & Enthusiasm': content = content.replace("{{%s}}" % "MOTIVATION", value) elif key == 'Motivation & Enthusiasm comment': content = content.replace("{{%s}}" % "MOTIVATION-COMMENT", value) elif key == 'Ambassador Potential': content = content.replace("{{%s}}" % "AMBASADOR", value) elif key == 'Ambassador Potential comment': content = content.replace("{{%s}}" % "AMBASADOR-COMMENT", value) elif key == 'Technical ability': content = content.replace("{{%s}}" % "TECHNICAL", value) elif key == 'Technical ability comment': content = content.replace("{{%s}}" % "TECHNICAL-COMMENT", value) elif key == 'Overall recommendation and comment': content = content.replace("{{%s}}" % "OVERALL", value) elif key.startswith("Project preference"): # process preference currentPreference = key[-1] #print('Current preference = ', currentPreference) currPrefIndex = int(currentPreference)-1 # The string is in form: # Student meet compulsory preferences.; Student meet desirable prerequisites if 'meet compulsory' in value: student_data[userID]['preference'][numReviewer][currPrefIndex][0] = "[X]" else: student_data[userID]['preference'][numReviewer][currPrefIndex][0] = "[ ]" if 'meet desirable' in value: student_data[userID]['preference'][numReviewer][currPrefIndex][1] = "[X]" else: student_data[userID]['preference'][numReviewer][currPrefIndex][1] = "[ ]" if "not fit" in value: #student_data[userID]['preference'][numReviewer][currPrefIndex][2] = "[X]" content = content.replace("{{PREFERENCE_" + currentPreference +"_DOESNOTFIT}}", "[X]") else: # student_data[userID]['preference'][numReviewer][currPrefIndex][2] = "[ ]"; content = content.replace("{{PREFERENCE_" + currentPreference +"_DOESNOTFIT}}", "[ ]") content = content.replace("{{PREFERENCE_" + currentPreference +"_COMPULSORY}}", student_data[userID]['preference'][numReviewer][currPrefIndex][0]) content = content.replace("{{PREFERENCE_" + currentPreference +"_DESIRABLE}}", student_data[userID]['preference'][numReviewer][currPrefIndex][1]) # add content into skeleton and write to file save_content(filename, skeleton, "Summer of HPC {0} - Registrant data".format(SoHPC_year), generation_date, content) # for fldName in ['First Choice', 'Second Choice', 'Third Choice']: #for fldName in ['1', '2', '3']: #for fldName in ['Choice 1', 'Choice 2', 'Choice 3']: # choice = fldName.split(" ")[1].strip() for fldName in ['1.', '2.', '3.']: choice = fldName[0:1] # get all three projects and first add all user's first choice, then second and then third choice for id in user_data: # loop over all users and extract projects and prepare arrays if user_data[id][fldName].strip(): # project is defined proj = user_data[id][fldName].split(" ", 1) projID = int(proj[0].strip()) projName = proj[1].strip() if not projID in project_data: # project does not exist; add an empty array for later addinf the data initData = {'name': projName, 'students': [], 'selected_student': {}} project_data.update({projID: initData}) project_data[projID]['students'].append({'id': id, 'choice': choice}) else: projID = 0 user_data[id]['Choice'+choice+"ID"] = projID for id in user_data: if user_data[id]['selected'].strip() in ['invalid', 'withdrawn', 'declined']: continue # loop over usr data and save selected students/registrants for each projct if user_data[id]['selected'].strip(): # get project ID and order from selected number: 2001.1 (project ID.order of selection) _tmp = [el.strip() for el in user_data[id]['selected'].split(".")] projID = int(_tmp[0]) projOrder = 0 if len(_tmp) == 2: # get order from second part of 'selected' column if len(_tmp[1]) > 0: projOrder = int(_tmp[1]) project_data[projID]['selected_student'][projOrder] = id # get student country and change country stat data ctryName = user_data[id]['Country'] country_data[ctryName]['selected'] += 1 # now display project and student data into evaluation.html file content_projects = "" content_registrants = registrant_list # sort projects by projectID project_ids = sorted(project_data) # # layout project data + registrants for each project # proj_rows = "" proj_select = "" for projID in project_ids: # loop over all projects proj_row = project_html_data proj_row = proj_row.replace("{{PROJECT_NAME}}", project_data[projID]['name']) proj_row = proj_row.replace("{{PROJECT_ID}}", "{0}".format(projID)) tmp_row = project_selected_participant_row.replace("{{PROJECT_ID}}", "{0}".format(projID)) tmp_row = tmp_row.replace("{{PROJECT_NAME}}", project_data[projID]['name']) tmp_row = tmp_row.replace("{{PROJECT_ROW_SPAN}}", str(max(1, len(project_data[projID]['selected_student'])))) if project_data[projID]['selected_student']: # add selected students in order defined in dict _cur_proj_students = "" _cur_proj_sep = "" for ordNum in sorted(project_data[projID]['selected_student'].keys()): # print students according to the order x = project_data[projID]['selected_student'][ordNum] _cur_proj_students += _cur_proj_sep+\ "<a href='{0}'>{1}</a> ({7})</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{8}</td><td align='center'><a href='{5}'>[1]</a></td><td align='center'><a href='{6}'>[2]</a></td>"\ .format(user_data[x]['link_application'], user_data[x]['Name'], user_data[x]['Country'], user_data[x]['Gender'], user_data[x]['Age (years)'], student_data[x]['evaluation_detail_file'][0], student_data[x]['evaluation_detail_file'][1], user_data[x]['ID'], user_data[x]['Email']) if user_data[x]['tentative']: _cur_proj_students += "<td>TENTATIVE</td>" if user_data[x]['I am confirming my participation for the selected project'] != "Yes": _cur_proj_students += "<td>online-only</td>" _cur_proj_sep = "</tr><tr><td>" tmp_row = tmp_row.replace("{{PARTICIPANTS_LIST}}", _cur_proj_students) else: tmp_row = tmp_row.replace("{{PARTICIPANTS_LIST}}", "") proj_select += tmp_row # proj_select += project_toc_row.format(projID, projID, project_data[projID]['name']); user_rows = "" no = 1 for student_row in sorted(project_data[projID]['students'], key=lambda student_row: (student_row['choice'], -student_data[student_row['id']]['average'], student_row['id'])): # display students according to (choice (asc), average value (desc), ID (asc)) id = student_row['id'] row = project_user_row row = row.replace("{{I}}", "{0}".format(no)) row = row.replace("{{NAME}}", user_data[id]['Name']) row = row.replace("{{ID}}", user_data[id]['ID']) row = row.replace("{{COUNTRY}}", user_data[id]['Country']) row = row.replace("{{GENDER}}", user_data[id]['Gender']) row = row.replace("{{AGE}}", user_data[id]['Age (years)']) row = row.replace("{{CHOICE}}", student_row['choice']) row = row.replace("{{OVERALL}}", student_row['choice']) row = row.replace("{{HTML_FILENAME}}", user_data[id]['link_application']) row = row.replace("{{EVALUATION_HTML_LINK_1}}", student_data[id]['evaluation_detail_file'][0]) row = row.replace("{{EVALUATION_HTML_LINK_2}}", student_data[id]['evaluation_detail_file'][1]) row = row.replace("{{REVIEWER_1}}", student_data[id]['reviewer'][0]) row = row.replace("{{REVIEWER_2}}", student_data[id]['reviewer'][1]) row = row.replace("{{OVERALL_COMMENT_1}}", student_data[id]['overall_comment'][0]) row = row.replace("{{OVERALL_COMMENT_2}}", student_data[id]['overall_comment'][1]) if user_data[id]['selected'] in ['invalid', 'withdrawn', 'declined']: style = "registrant_withdrawn" elif user_data[id]['selected'].startswith("%d" % projID): # current student is selected for the current project style = "registrant_selected" if user_data[id]['tentative']: style = "registrant_selected_tentative" elif user_data[id]['selected']: # current student is selected for a different project style = "registrant_selected_other" else: # ordinary row style = "" row = row.replace("{{REGISTRANT_SELECTED}}", style) for part in ['motivation','ambasador','technical']: # add all parts html_fld = part.upper() #print(student_data[id].keys()) #print(part in student_data[id]) row = row.replace("{{"+ html_fld +"_P1}}", "{0}".format(student_data[id][part]['p'][0])) row = row.replace("{{"+ html_fld +"_P2}}", "{0}".format(student_data[id][part]['p'][1])) row = row.replace("{{"+ html_fld +"_COMMENT_P1}}", "{0}".format(student_data[id][part]['comment'][0])) row = row.replace("{{"+ html_fld +"_COMMENT_P2}}", "{0}".format(student_data[id][part]['comment'][1])) if student_data[id][part]['avg'] > 0: row = row.replace("{{"+ html_fld +"_AVG}}", "{0:.2f}".format(student_data[id][part]['avg'])) else: row = row.replace("{{"+ html_fld +"_AVG}}", "") if student_data[id]['average'] > 0: row = row.replace("{{AVERAGE_P}}", "{0:.2f}".format(student_data[id]['average'])) else: row = row.replace("{{AVERAGE_P}}", "") for prefNo in range(1,4): # display all preferences row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_COMPULSORY}}", "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][0], student_data[id]['preference'][1][prefNo-1][0])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_DESIRABLE}}", "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][1], student_data[id]['preference'][1][prefNo-1][1])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_COMPULSORY}}", "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][0], student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][0])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_DESIRABLE}}", "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][1], student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][1])) user_rows += row no += 1 proj_row = proj_row.replace("{{REGISTRANT_DATA}}", user_rows) proj_rows += proj_row #print(project_data) #print(proj_select) #print(proj_rows) index_data = index_data.replace("{{PROJECT_LIST_AND_SELECTED_PARTICIPANTS}}", proj_select) content_projects = proj_rows # # display country statistics: all + selected registrants + percents country_rows = "" country_list_sorted = sorted(country_data) for ctryName in country_list_sorted: # loop over all countries row = "" perc = 100 * country_data[ctryName]['selected'] * 1.0 / country_data[ctryName]['all'] country_rows += "<tr><td>{0}</td><td class='id'>{1}</td><td class='id'>{2}</td><td class='id'>{3:.1f}</td></tr>".format( ctryName, country_data[ctryName]['all'], country_data[ctryName]['selected'], perc) index_data = index_data.replace("{{COUNTRY_PARTICIPANTS_LIST}}", country_rows) # layout of registrant data + scores of evaluation + average scores user_avg = {} for id in user_data: # loop over usr data and create {key: avg} for sorting user_avg.update({id: student_data[id]['average']}) # now sort it user_sorted = Counter(user_avg) rows = "" no = 1 for cell in user_sorted.most_common(): # loop over usr data and create registrant data id = cell[0] row = person_row row = row.replace("{{I}}", "{0}".format(no)) row = row.replace("{{REGISTRANT_NAME}}", user_data[id]['Name']) row = row.replace("{{COUNTRY}}", user_data[id]['Country']) row = row.replace("{{GENDER}}", user_data[id]['Gender']) row = row.replace("{{AGE}}", user_data[id]['Age (years)']) row = row.replace("{{REGISTRANT_ID}}", user_data[id]['ID']) row = row.replace("{{HTML_FILENAME}}", user_data[id]['link_application']) row = row.replace("{{REVIEWER_1}}", student_data[id]['reviewer'][0]) row = row.replace("{{REVIEWER_2}}", student_data[id]['reviewer'][1]) row = row.replace("{{OVERALL_COMMENT_1}}", student_data[id]['overall_comment'][0]) row = row.replace("{{OVERALL_COMMENT_2}}", student_data[id]['overall_comment'][1]) project_list_tmp = "" sep = "" if user_data[id]['selected'] in ['invalid', 'withdrawn', 'declined']: style = "registrant_withdrawn" elif user_data[id]['selected']: # current student is selected for project; display it in special way style = "registrant_selected" if user_data[id]['tentative']: style = "registrant_selected_tentative" else: # ordinary row style = "" row = row.replace("{{REGISTRANT_SELECTED}}", style) for fldName in ['Choice1ID', 'Choice2ID', 'Choice3ID']: # get all three projects and first add all user's first choise, then second and then third choice projID = user_data[id][fldName] if projID: other = user_data[id]['selected'] and not user_data[id]['selected'].startswith("%d" % projID) project_list_tmp += sep if other: project_list_tmp += "(" project_list_tmp += "<a href='#project_%(projID)s'>%(projID)s</a>" % {'projID': projID} if other: project_list_tmp += ")" sep = ", " row = row.replace("{{PROJECT_ID_LIST}}", project_list_tmp) for part in ['motivation','ambasador','technical']: # add all parts html_fld = part.upper() row = row.replace("{{"+ html_fld +"_P1}}", "{0}".format(student_data[id][part]['p'][0])) row = row.replace("{{"+ html_fld +"_P2}}", "{0}".format(student_data[id][part]['p'][1])) row = row.replace("{{"+ html_fld +"_COMMENT_P1}}", "{0}".format(student_data[id][part]['comment'][0])) row = row.replace("{{"+ html_fld +"_COMMENT_P2}}", "{0}".format(student_data[id][part]['comment'][1])) if student_data[id][part]['avg'] > 0: row = row.replace("{{"+ html_fld +"_AVG}}", "{0:.2f}".format(student_data[id][part]['avg'])) else: row = row.replace("{{"+ html_fld +"_AVG}}", "") if student_data[id]['average'] > 0: row = row.replace("{{AVERAGE_P}}", "{0:.2f}".format(student_data[id]['average'])) else: row = row.replace("{{AVERAGE_P}}", "") for prefNo in range(1,4): # display all preferences row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_COMPULSORY}}", "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][0], student_data[id]['preference'][1][prefNo-1][0])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_SHORT_DESIRABLE}}", "{0}<br>{1}".format(student_data[id]['preference'][0][prefNo-1][1], student_data[id]['preference'][1][prefNo-1][1])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_COMPULSORY}}", "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][0], student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][0])) row = row.replace("{{PREFERENCE_" + "{0}".format(prefNo) +"_DESIRABLE}}", "{0}: {1}\n{2}: {3}".format(student_data[id]['reviewer'][0], student_data[id]['preference'][0][prefNo-1][1], student_data[id]['reviewer'][1], student_data[id]['preference'][1][prefNo-1][1])) rows += row no += 1 content_registrants = registrant_list.format(rows) # add persons list into "index" file content content = index_data content = content.replace("{{CONTENT_PROJECTS}}", content_projects) content = content.replace("{{CONTENT_REGISTRANTS}}", content_registrants) save_content("evaluation.html", skeleton, "Summer of HPC {0} - Project evaluation results".format(SoHPC_year), generation_date, content) students_csv = "" for id in user_data: ud = user_data[id].copy() ud.update({'average': student_data[id]['average']}) students_csv += "%(ID)3s, %(average)4.2f, %(Choice1ID)4d, %(Choice2ID)4d, %(Choice3ID)4d, %(selected)6s, %(Name)s, %(Country)s, %(Gender)s, %(Age (years))s\n" % ud with open("students.csv", "w") as f: f.write(students_csv) print("All done!")