mailpipe: use `messages.sort(...)`, not `m = sorted(m, ...)`.
[pygrader.git] / README
1 ``pygrader`` is a directory-based grade database for grading course
2 assignments.  Besides tracking grades locally, you can also use it to
3 automatically mail grades to students and professors associated with
4 the course.  For secure communication, PGP_ can be used to sign and/or
5 encrypt any of these emails.
6
7 Installation
8 ============
9
10 Packages
11 --------
12
13 Gentoo
14 ~~~~~~
15
16 I've packaged ``pygrader`` for Gentoo_.  You need layman_ and
17 my `wtk overlay`_.  Install with::
18
19   # emerge -av app-portage/layman
20   # layman --add wtk
21   # emerge -av dev-python/pygrader
22
23 Dependencies
24 ------------
25
26 ``pygrader`` is a simple package.  The only external dependency
27 outside the Python 3 standard library is my `pgp-mime`_ package.
28
29 If you are developing ``pygrader``, you can use `update-copyright`_ to
30 keep the copyright blurbs up to date.
31
32 Installing by hand
33 ------------------
34
35 ``pygrader`` is available as a Git_ repository::
36
37   $ git clone git://tremily.us/pygrader.git
38
39 See the homepage_ for details.  To install the checkout, run the
40 standard::
41
42   $ python setup.py install
43
44 Usage
45 =====
46
47 Pygrader will help keep you organized in a course where the students
48 submit homework via email, or the homework submissions are otherwise
49 digital (i.e. scanned in after submission).  There is currently no
50 support for multiple graders, although I will likely add this in the
51 future.  In the following sections, I'll walk you through
52 administering the homework for the ``test`` course.
53
54 All of the processing involves using the ``pg.py`` command.  Run::
55
56   $ pg.py --help
57
58 for details.
59
60 Sending email
61 -------------
62
63 Pygrader receives submissions and assigns grades via email.  In order
64 to send email, it needs to connect to an SMTP_ server.  See the
65 pgp-mime documentation for details on configuring you SMTP connection.
66 You can test your SMTP configuration by sending yourself a test
67 message::
68
69   $ pg.py -VVV smtp -a rincewind@uu.edu -t rincewind@uu.edu
70
71 Defining the course
72 -------------------
73
74 Once you've got email submission working, you need to configure the
75 course you'll be grading.  Each course lives in its own directory, and
76 the basic setup looks like the ``test`` example distributed with
77 pygrader.  The file that you need to get started is the config file in
78 the course directory::
79
80   $ cat test/course.conf
81   [course]
82   name: Physics 101
83   assignments: Attendance 1, Attendance 2, Attendance 3, Attendance 4,
84     Attendance 5, Attendance 6, Attendance 7, Attendance 8, Attendance 9,
85     Assignment 1, Assignment 2, Exam 1, Exam 2
86   robot: Robot101
87   professors: Gandalf
88   assistants: Sauron
89   students: Bilbo Baggins, Frodo Baggins, Aragorn
90
91   [Attendance 1]
92   points: 1
93   weight: 0.1/9
94   due: 2011-10-03
95
96   [Attendance 2]
97   points: 1
98   weight: 0.1/9
99   due: 2011-10-04
100
101   …
102
103   [Assignment 1]
104   points: 10
105   weight: 0.4/2
106   due: 2011-10-10
107   submittable: yes
108
109   …
110
111   [Exam 2]
112   points: 10
113   weight: 0.4/2
114   due: 2011-10-17
115
116   [Robot101]
117   nickname: phys-101 robot
118   emails: phys101@tower.edu
119   pgp-key: 4332B6E3
120
121   [Gandalf]
122   nickname: G-Man
123   emails: g@grey.edu
124   pgp-key: 4332B6E3
125
126   [Sauron]
127   emails: eye@tower.edu
128
129   [Bilbo Baggins]
130   nickname: Bill
131   emails: bb@shire.org, bb@greyhavens.net
132
133   …
134
135 The format is a bit wordy, but it is also explicit and easily
136 extensible.  The time it takes to construct this configuration file
137 should be a small portion of the time you will spend grading
138 submissions.
139
140 If a person has the ``pgp-key`` option set, that key will be used to
141 encrypt messages to that person and sign messages from that person
142 with PGP_.  It will also be used to authenticate ownership of incoming
143 emails.  You'll need to have GnuPG_ on your local host for this to
144 work, and the user running pygrader should have the associated keys in
145 their keychain.
146
147 The ``course.robot`` option defines a dummy person used to sign
148 automatically generated emails (e.g. responses to mailpipe-processed
149 submissions).
150
151 The ``submittable`` option marks assignments that accept direct
152 submission from students (e.g. homeworks).  You probably don't want to
153 set this option for attendance, since it would allow students to mark
154 themselves as having attended a class.  ``submittable`` default to
155 ``False``.
156
157 Processing submissions
158 ----------------------
159
160 As the due date approaches, student submissions will start arriving in
161 your inbox.  Use ``pg.py``'s ``mailpipe`` command to sort them into
162 directories (using the ``pygrader.handler.submission`` handler).  This
163 will also extract any files that were attached to the emails and place
164 them in that persons assignment directory::
165
166   $ pg.py -d test mailpipe -m maildir -i ~/.maildir -o ./mail-old
167
168 Use ``pg.py``'s ``todo`` command to check for ungraded submissions::
169
170   $ pg.py -d test todo mail grade
171
172 Then create ``grade`` files using your favorite editor.  The first
173 line of the grade file should be the student's grade for that
174 assigment, expressed in a syntax that Python's ``float()`` understands
175 (``1``, ``95``, ``2.5``, ``6.022e23``, etc.).  If you wish, you may
176 add additional comment lines after the grade line, offering
177 suggestions for improvement, etc.  This comment (if present) will be
178 mailed to the student along with the grade itself.  There are a number
179 of example grade files in the ``test`` directory in ``pygrader``'s Git
180 source.
181
182 To see how everyone's doing, you can print a table of grades with
183 ``pg.py``'s ``tabulate`` command::
184
185   $ pg.py -d test tabulate -s
186
187 When you want to notify students of their grades, you can send them
188 all out with ``pg.py``'s ``email`` command::
189
190   $ pg.py -d test email assignment 'Exam 1'
191
192 Mailpipe details
193 ~~~~~~~~~~~~~~~~
194
195 Mailpipe is the most complicated part of ``pygrader``, and the place
196 where things are most likely to get sticky.  Since there are several
197
198 If you get tired of filtering your inbox by hand using ``pg.py
199 mailpipe``, you can (depending on how your mail delivery is setup) use
200 procmail_ to automatically run ``mailpipe`` automatically on incoming
201 email.  There is an example ``.procmailrc`` in the
202 ``pygrader.mailpipe.mailpipe`` docstring that runs ``mailpipe``
203 whenever incoming emails have ``[phys160:submit]`` in their subject
204 somewhere.
205
206 The use of ``[TARGET]`` tags in the email subject allows users to
207 unambiguously specify the purpose of their email.  Currently supported
208 targets include (see the ``handlers`` argument to
209 ``pygrader.mailpipe``):
210
211 ``submit``
212   student assignment submission.  The remainder of the email subject
213   should include the case insensitive name of the assignment being
214   submitted (see ``pygrader.handler.submission._match_assignment``).
215   An example subject would be::
216
217     [submit] assignment 1
218
219 ``get``
220   request information from the grade database.  For students, the
221   remainder of the email subject is irrelevant.  Grades and comments
222   for all graded assignments are returned in a single email.  An
223   example subject would be::
224
225     [get] my grades
226
227   Professors and TAs may request either a table of all grades for the
228   course (à la ``tabulate``), the full grades for a particular
229   student, or a particular student's submission for a particular
230   assignment.  Example subjects are (respectively):
231
232     [get] don't match any student names
233     [get] Bilbo Baggins
234     [get] Bilbo Baggins Assignment 1
235
236 To allow you to easily sort the email, you can also prefix the target
237 with additional information (see
238 ``pygrader.mailpipe._get_message_target``).  For example, if you were
239 running several courses from the same email account, you'd want a way
240 for users to specify which course they were interacting with so you
241 could filter appropriately in your procmail rules.  Everything in the
242 subject tag before an optional semicolon is ignored by ``mailpipe``,
243 so the following subjects will be handled identically::
244
245   [submit] assignment 1
246   [phys101:submit] assignment 1
247   [phys101:section2:submit] assignment 1
248
249 Testing
250 =======
251
252 Run the internal unit tests using nose_::
253
254   $ nosetests --with-doctest --doctest-tests pygrader
255
256 If a Python-3-version of ``nosetests`` is not the default on your
257 system, you may need to try something like::
258
259   $ nosetests-3.2 --with-doctest --doctest-tests pygrader
260
261 Licence
262 =======
263
264 This project is distributed under the `GNU General Public License
265 Version 3`_ or greater.
266
267 Author
268 ======
269
270 W. Trevor King
271 wking@tremily.us
272
273 Related work
274 ============
275
276 For a similar project, see `Alex Heitzmann's pygrade`_, which keeps
277 the grade history in a single log file and provides more support for
278 using graphical interfaces.
279
280
281 .. _PGP: http://en.wikipedia.org/wiki/Pretty_Good_Privacy
282 .. _Gentoo: http://www.gentoo.org/
283 .. _layman: http://layman.sourceforge.net/
284 .. _wtk overlay: http://blog.tremily.us/posts/Gentoo_overlay/
285 .. _pgp-mime: http://blog.tremily.us/posts/pgp-mime/
286 .. _update-copyright: http://blog.tremily.us/posts/update-copyright/
287 .. _Git: http://git-scm.com/
288 .. _homepage: http://blog.tremily.us/posts/pygrader/
289 .. _SMTP: http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
290 .. _GnuPG: http://www.gnupg.org/
291 .. _procmail: http://www.procmail.org/
292 .. _nose: http://readthedocs.org/docs/nose/en/latest/
293 .. _GNU General Public License Version 3: http://www.gnu.org/licenses/gpl.html
294 .. _Alex Heitzmann's pygrade: http://code.google.com/p/pygrade/