Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F93077885
validate_groups
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Nov 26, 01:13
Size
9 KB
Mime Type
text/x-python
Expires
Thu, Nov 28, 01:13 (2 d)
Engine
blob
Format
Raw Data
Handle
22571120
Attached To
R3683 Slides
validate_groups
View Options
#!/usr/bin/env python3
import os
import subprocess
import Slides.mail_helper as mailer
import argparse
import getpass
import random
import Slides.class_helper as ch
config = ch.get_class_config()
parser = argparse.ArgumentParser(
description='Validate groups for homeworks')
parser.add_argument('-n', '--homework', type=str,
help='specify the homework label',
required=True)
parser.add_argument('-t', '--target', type=str,
help='Specify the name of a mail box'
' to send test messages, '
f'default : {config["teachers"][0]}',
default=config['teachers'][0])
parser.add_argument('-r', '--report', action='store_true',
help='Generate a org-mode file ready to grade')
parser.add_argument('-u', '--username', type=str,
help='Username to log to the SMTP server',
default=None)
parser.add_argument('-c', '--clone', action='store_true',
help='Tries to clone the repository of the group',
default=None)
args = parser.parse_args()
students_list = config['students']
students_list.rename(columns={"e-Mail": "email"},
inplace=True)
students_list = students_list.applymap(
lambda x: x.strip() if isinstance(x, str) else x)
students_list["in_group"] = False
students_list.set_index("email", inplace=True)
homework = config['homeworks'][args.homework]
group_list = homework['groups']
group_list.rename(columns={"Student #1 EPFL email": "email1",
"Student #2 EPFL email": "email2",
"Homeworks repository": "repository"
},
inplace=True)
group_list = group_list.applymap(
lambda x: x.strip() if isinstance(x, str) else x)
target = args.target
username = args.username
password = None
if username:
print('login:', username)
password = getpass.getpass()
# ###############################################################
# generate group keys
def make_group_keys(group):
emails = [group.email1, group.email2]
emails.sort()
if len(emails) < 2:
raise RuntimeError(
'invalid group: ' + str(emails))
print(emails)
key = '_'.join(emails)
return key
group_keys = group_list.apply(make_group_keys, axis=1)
group_list['group_key'] = group_keys
group_list.set_index('group_key', inplace=True)
# ###############################################################
def run_command(cmd, cwd=None):
if cwd is None:
cwd = os.getcwd()
process = subprocess.Popen(cmd, shell=True,
cwd=cwd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output = process.communicate()
output = [i.decode().strip() for i in output if i.decode().strip() != '']
output = '\n'.join(output)
ret = process.returncode
return ret, output
# ###############################################################
# search for failing to clone groups
try:
os.mkdir(os.path.join(config['git_root'], 'homeworks'))
except Exception:
pass
def clone_group_repo(group):
dirname = os.path.join(
config['git_root'], 'homeworks', args.homework+".repositories", group.name)
if os.path.isdir(dirname):
ret = 0
else:
clone_cmd = group.repository + ' ' + dirname
ret, out = run_command(clone_cmd)
if ret == 0:
print('Cloning_Success: group ' + group.name)
else:
print('Cloning_Failure: group ' + group.name)
return ret == 0, None, None
cmd = 'git rev-parse --abbrev-ref origin/HEAD'
ret, out = run_command(cmd, cwd=dirname)
remote, master = out.split('/')
cmd = ('git rev-list -n 1 --first-parent'
f' --before="{homework["deadline"]}" {master}')
ret, rev = run_command(cmd, cwd=dirname)
cmd = f'git checkout {rev}'
ret, out = run_command(cmd, cwd=dirname)
if ret != 0:
print(f"Failed to get revision: \n\n{out}")
return ret == 0, master, rev
if args.clone:
res = group_list.apply(
clone_group_repo, axis=1, result_type='expand')
group_list['clone_success'] = res[0]
group_list['master'] = res[1]
group_list['revision'] = res[2]
# ###############################################################
# construct invalid groups
def construct_valid_groups(group):
# check if in student list
try:
count1 = students_list.loc[group.email1].size
count2 = students_list.loc[group.email2].size
is_valid = (count1 > 0 and count2 > 0)
except KeyError:
is_valid = False
if is_valid:
students_list.loc[group.email1, 'in_group'] = True
students_list.loc[group.email2, 'in_group'] = True
return is_valid
valid_group = group_list.apply(construct_valid_groups, axis=1)
group_list['valid_group'] = valid_group
################################################################
# generate org report file
def append_group_in_report(f, group):
f.write(f"* {group.name}\n")
f.write(f"** {group.revision}\n\n")
if 'report_template' in homework:
f.write(homework['report_template'])
elif 'report_template' in config:
f.write(config['report_template'])
f.write("\n")
if args.report:
fname = os.path.join(config['git_root'],
'homeworks', args.homework+'.report.org')
if os.path.exists(fname):
print(
f"Warning: will not overwrite the report file: delete it manually ({fname})")
else:
f = open(fname, 'w')
group_list.apply(lambda g: append_group_in_report(f, g), axis=1)
f.close()
################################################################
# make random groups
unregistered_list = [
e.name for k, e in students_list.query('in_group==False').iterrows()]
random.shuffle(unregistered_list)
if len(unregistered_list):
if len(unregistered_list) % 2 == 0:
random_groups = [e for e in zip(
unregistered_list[::2], unregistered_list[1::2])]
else:
random_groups = [e for e in zip(
unregistered_list[:-1:2], unregistered_list[1:-1:2])]
random_groups[-1] = random_groups[-1][0], random_groups[-1][1], unregistered_list[-1]
random_groups = [" - {0}".format(", ".join(b))
for b in random_groups]
random_groups = '\n'.join(random_groups)
################################################################
# output info
print('\ntotal_students:', len(students_list))
print('registered_students:', len(students_list.query("in_group==True")))
print('unregistered_students:', len(students_list.query("in_group==False")))
print('invalid_groups:', len(group_list.query("valid_group==False")))
################################################################
# sending emails
# send emails o failed clones
def send_failed_clone_email(group):
mailer.mail(
username=username,
password=password,
sender_email=target,
subject='SP4E homeworks: error in cloning your project',
copy_emails=config['teachers']+config['assistants'],
message=f"""
Dear Students,
Apparently we cannot clone your repository:
{group.repository}
Please fix the permissions.
Best regards,
The teaching team.
""",
target_emails=[group.email1, group.email2]
)
def send_invalid_groups(group):
mailer.mail(
username=username,
password=password,
sender_email=target,
subject=f'{config["acronym"]} homeworks: invalid group',
message="""
Dear Students,
Your group is composed with at least a student not officially registered
for the class. Therefore I have to ask you to change the composition of
the group.
You have to understand that the grading of so many projects is a lot of work.
Therefore we will do it only for the registered students.
With my best regards,
The teaching team.
""",
copy_emails=config['teachers']+config['assistants'],
target_emails=[group.email1, group.email2]
)
# send email to unregistered people
def send_unregistered():
if 'group_form' in homework:
group_form = homework["group_form"]
else:
group_form = config["group_form"]
if 'unregistered_student_message' in config:
msg = config['unregistered_student_message']
else:
msg = """
Dear Students,
Apparently you did not register yet to any group.
Several reasons might explain this.
If it happens that you need to find a pair, please find below the
automatically created groups.
{random_groups}
If the situation does not suit you, please inform us as quickly as
possible.
You still have to create a repository to store your homework.
Please inform us of your repository URI, for instance by filling the
[form]({group_form})
With my best regards,
The teaching team.
"""
mailer.mail(
username=username,
password=password,
sender_email=target,
subject=f'{config["acronym"]} homeworks: not registered in a group',
message=msg.format(random_groups=random_groups,
unregistered_list=unregistered_list,
group_form=group_form),
copy_emails=config['teachers']+config['assistants'],
target_emails=unregistered_list,
markdown=True
)
if username:
if args.clone:
group_list.query("clone_success==False").apply(
send_failed_clone_email, axis=1)
group_list.query("valid_group==False").apply(
send_invalid_groups, axis=1)
if len(unregistered_list) > 0:
send_unregistered()
Event Timeline
Log In to Comment