3 # Copyright (C) 2012 W. Trevor King <wking@drexel.edu>
5 # This file is part of pygrader.
7 # pygrader is free software: you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation, either version 3 of the License, or (at your option) any later
12 # pygrader is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # pygrader. If not, see <http://www.gnu.org/licenses/>.
19 """Manage grades from the command line
22 import configparser as _configparser
23 from email.mime.text import MIMEText as _MIMEText
24 import email.utils as _email_utils
25 import inspect as _inspect
26 import logging as _logging
27 import os.path as _os_path
30 import pgp_mime as _pgp_mime
32 from pygrader import __version__
33 from pygrader import LOG as _LOG
34 from pygrader.email import test_smtp as _test_smtp
35 from pygrader.mailpipe import mailpipe as _mailpipe
36 from pygrader.storage import initialize as _initialize
37 from pygrader.storage import load_course as _load_course
38 from pygrader.tabulate import tabulate as _tabulate
39 from pygrader.template import assignment_email as _assignment_email
40 from pygrader.template import course_email as _course_email
41 from pygrader.template import student_email as _student_email
42 from pygrader.todo import print_todo as _todo
45 if __name__ == '__main__':
46 from argparse import ArgumentParser as _ArgumentParser
48 parser = _ArgumentParser(
49 description=__doc__, version=__version__)
51 '-d', '--base-dir', dest='basedir', default='.',
52 help='Base directory containing grade data')
54 '-c', '--color', default=False, action='store_const', const=True,
55 help='Color printed output with ANSI escape sequences')
57 '-V', '--verbose', default=0, action='count',
58 help='Increase verbosity')
59 subparsers = parser.add_subparsers(title='commands')
61 smtp_parser = subparsers.add_parser(
62 'smtp', help=_test_smtp.__doc__.splitlines()[0])
63 smtp_parser.set_defaults(func=_test_smtp)
64 smtp_parser.add_argument(
66 help='Your address (email author)')
67 smtp_parser.add_argument(
68 '-t', '--target', dest='targets', action='append',
69 help='Address for the email recipient')
71 initialize_parser = subparsers.add_parser(
72 'initialize', help=_initialize.__doc__.splitlines()[0])
73 initialize_parser.set_defaults(func=_initialize)
74 initialize_parser.add_argument(
75 '-D', '--dry-run', default=False, action='store_const', const=True,
76 help="Don't actually send emails, create files, etc.")
78 tabulate_parser = subparsers.add_parser(
79 'tabulate', help=_tabulate.__doc__.splitlines()[0])
80 tabulate_parser.set_defaults(func=_tabulate)
81 tabulate_parser.add_argument(
82 '-s', '--statistics', default=False, action='store_const', const=True,
83 help='Calculate mean and standard deviation for each assignment')
85 email_parser = subparsers.add_parser(
86 'email', help='Send emails containing grade information')
87 email_parser.add_argument(
88 '-D', '--dry-run', default=False, action='store_const', const=True,
89 help="Don't actually send emails, create files, etc.")
90 email_parser.add_argument(
91 '-a', '--author', default='Trevor King',
92 help='Your name (email author)')
93 email_parser.add_argument(
94 '--cc', action='append', help='People to carbon copy')
95 email_subparsers = email_parser.add_subparsers(title='type')
96 assignment_parser = email_subparsers.add_parser(
97 'assignment', help=_assignment_email.__doc__.splitlines()[0])
98 assignment_parser.set_defaults(func=_assignment_email)
99 assignment_parser.add_argument(
100 'assignment', help='Name of the target assignment')
101 student_parser = email_subparsers.add_parser(
102 'student', help=_student_email.__doc__.splitlines()[0])
103 student_parser.set_defaults(func=_student_email)
104 student_parser.add_argument(
105 '-o', '--old', default=False, action='store_const', const=True,
106 help='Include already-notified information in emails')
107 student_parser.add_argument(
108 '-s', '--student', dest='student',
109 help='Explicitly select the student to notify (instead of everyone)')
110 course_parser = email_subparsers.add_parser(
111 'course', help=_course_email.__doc__.splitlines()[0])
112 course_parser.set_defaults(func=_course_email)
113 course_parser.add_argument(
114 '-t', '--target', dest='targets', action='append',
115 help='Name, alias, or group for the email recipient(s)')
117 mailpipe_parser = subparsers.add_parser(
118 'mailpipe', help=_mailpipe.__doc__.splitlines()[0])
119 mailpipe_parser.set_defaults(func=_mailpipe)
120 mailpipe_parser.add_argument(
121 '-D', '--dry-run', default=False, action='store_const', const=True,
122 help="Don't actually send emails, create files, etc.")
123 mailpipe_parser.add_argument(
124 '-m', '--mailbox', choices=['maildir', 'mbox'],
125 help=('Instead of piping a message in via stdout, you can also read '
126 'directly from a mailbox. This option specifies the format of '
127 'your target mailbox.'))
128 mailpipe_parser.add_argument(
129 '-i', '--input', dest='input_', metavar='INPUT',
130 help='Path to the mailbox containing messages to be processed')
131 mailpipe_parser.add_argument(
133 help=('Path to the mailbox that will recieve successfully processed '
134 'messages. If not given, successfully processed messages will '
135 'be left in the input mailbox'))
136 mailpipe_parser.add_argument(
137 '-l', '--max-late', default=0, type=float,
138 help=('Grace period in seconds before an incoming assignment is '
139 'actually marked as late'))
141 todo_parser = subparsers.add_parser(
142 'todo', help=_todo.__doc__.splitlines()[0])
143 todo_parser.set_defaults(func=_todo)
144 todo_parser.add_argument(
145 'source', help='Name of source file/directory')
146 todo_parser.add_argument(
147 'target', help='Name of target file/directory')
150 # p.add_option('-t', '--template', default=None)
152 args = parser.parse_args()
155 _LOG.setLevel(max(_logging.DEBUG, _LOG.level - 10*args.verbose))
156 _pgp_mime.LOG.setLevel(_LOG.level)
158 config = _configparser.ConfigParser()
160 _os_path.expanduser(_os_path.join('~', '.config', 'smtplib.conf')),
163 func_args = _inspect.getargspec(args.func).args
166 if 'basedir' in func_args:
167 kwargs['basedir'] = args.basedir
169 if 'course' in func_args:
170 course = _load_course(basedir=args.basedir)
171 active_groups = course.active_groups()
172 kwargs['course'] = course
173 if hasattr(args, 'assignment'):
174 kwargs['assignment'] = course.assignment(name=args.assignment)
175 if hasattr(args, 'cc') and args.cc:
176 kwargs['cc'] = [course.person(name=cc) for cc in args.cc]
177 for attr in ['author', 'student']:
178 if hasattr(args, attr):
179 name = getattr(args, attr)
180 kwargs[attr] = course.person(name=name)
181 for attr in ['targets']:
182 if hasattr(args, attr):
183 people = getattr(args, attr)
185 people = ['professors'] # for the course email
187 for person in people:
188 if person in active_groups:
189 kwargs[attr].extend(course.find_people(group=person))
191 kwargs[attr].extend(course.find_people(name=person))
192 for attr in ['dry_run', 'mailbox', 'output', 'input_', 'max_late',
193 'old', 'statistics']:
194 if hasattr(args, attr):
195 kwargs[attr] = getattr(args, attr)
196 elif args.func == _test_smtp:
197 for attr in ['author', 'targets']:
198 if hasattr(args, attr):
199 kwargs[attr] = getattr(args, attr)
200 elif args.func == _todo:
201 for attr in ['source', 'target']:
202 if hasattr(args, attr):
203 kwargs[attr] = getattr(args, attr)
205 if 'use_color' in func_args:
206 kwargs['use_color'] = args.color
208 if ('smtp' in func_args and
209 not kwargs.get('dry_run', False) and
210 'smtp' in config.sections()):
211 params = _pgp_mime.get_smtp_params(config)
212 kwargs['smtp'] = _pgp_mime.get_smtp(*params)
215 _LOG.debug('execute {} with {}'.format(args.func, kwargs))
217 ret = args.func(**kwargs)
219 smtp = kwargs.get('smtp', None)
221 _LOG.info('disconnect from SMTP server')