Source code for uw.local.teaching.bin.submit_grade_revisions

"""Automatic submission of grade revisions.

Python process to submit pending grade revisions to the Registar's Office.
"""

import argparse
from itertools import groupby
from operator import attrgetter
from sys import exit

from uw.emailutils import emailaddr
from uw.sql.wrap import open_psycopg2_db_service_cursor
from uw.web.html.format import format_datetime

from ...outgoing.make_mail import mailout
from ...util.mail import odyssey_email

from ..db.cursor import Cursor

mathuo_email = emailaddr ('Math Undergrad Office', 'hankmuo4@uwaterloo.ca')
rogrades_email = emailaddr ('RO Grades', 'records.math@uwaterloo.ca')

mail_width = 76

[docs]def main (): """Main program to submit grade revisions. Either --pending or --resend N must be specified. The first option submits any pending revisions while the other re-sends the information for a previous submission. Additionally, --daily may be specified, which will cause the program to do nothing if ran on a non-business day; and --versose may be specified to cause an explanation to be printed if the program decides to do nothing. """ parser = argparse.ArgumentParser () parser.add_argument ('--verbose', action='store_true') parser.add_argument ('--daily', action='store_true') group = parser.add_mutually_exclusive_group (required=True) group.add_argument ('--pending', action='store_true') group.add_argument ('--resend', nargs="?", default=argparse.SUPPRESS, type=int, metavar='submission_id') parser.add_argument ('--debug', action='store_true') args = parser.parse_args () cursor = open_psycopg2_db_service_cursor (cursor_class=Cursor) if args.pending: if args.daily and cursor.execute_required_value ("select business_day is null from uw_date where date = current_date"): if args.verbose: print("Not a business day, won't submit grade revisions") exit () submission_id = cursor.callproc_required_value ("grade_record_submission") else: submission_id = args.resend current_time = cursor.execute_required_value ("select localtimestamp") revisions = cursor.execute_tuples ("select grc.*, off_course_section_format (term_id, class_id) as section, uw_term_format (term_id) as term, group_code, program_code from grade_revision_complete as grc join std_term_program using (term_id, uw_id) join pps_program using (program_code) where submission_id = %(submission_id)s order by term_id, class_id, surname, givennames, uw_id", submission_id=submission_id) if not revisions: if args.verbose: print("No pending revisions, won't submit grade revisions") exit () preparers = cursor.execute_tuples ("select distinct pp.*, external_id as userid from person_person pp natural join (select * from person_identity where external_id_type = 'USER') t join grade_revision_submitted on (pp.person_id = preparer_person_id) where submission_id = %(submission_id)s", submission_id=submission_id) preparer_descriptions = dict ((r.person_id, '%(surname)s, %(givennames)s (%(userid)s)' % r._asdict ()) for r in preparers) content_lines = [ 'The following grade revisions have been submitted (submission_id=%d):' % submission_id, ] for term, r in groupby (revisions, attrgetter ('term_id', 'term')): content_lines.extend ([ '', '', ('**** %04d ** %s ' % term).ljust (mail_width, '*'), ]) for section, s in groupby (r, attrgetter ('class_id', 'section')): s = tuple (s) content_lines.extend ([ '', ('-- %04d -- %s ' % section).ljust (mail_width, '-'), ]) preparers = set (p.preparer_person_id for p in s) if len (preparers) != 1: prepared_lines = [] footnotes = {} def footnote (person_id): if person_id in footnotes: return footnotes[person_id] else: result = len (footnotes) + 1 footnotes[person_id] = result prepared_lines.append ('*%d: %s' % (result, preparer_descriptions[person_id])) return result for t in s: t = t._asdict () t['names'] = '%(surname)s, %(givennames)s' % t line = '%(group_code)s-%(program_code)s %(external_id)s %(course_grade)3s -> %(student_grade)3s %(names)-30.30s' % t if len (preparers) != 1: line += ' *%d' % footnote (t['preparer_person_id']) content_lines.append (line) if len (preparers) == 1: (p,) = preparers content_lines.append ('Prepared by: %s' % preparer_descriptions[p]) else: content_lines.append ('Prepared by:') content_lines.extend (prepared_lines) content = '\n'.join (content_lines) if args.debug: print(content) else: message = mailout (cursor, odyssey_email, 'Grade Revisions Submitted %s' % format_datetime (current_time), content) message.add_recipient ('To', rogrades_email) message.add_recipient ('Cc', mathuo_email) message.add_recipient ('Cc', odyssey_email) message.done () cursor.connection.commit ()