Skip to content

Commit 2f42701

Browse files
aleksanderilinrkdarst
authored andcommitted
nbgrader collect: allow collection *only* of submissions before due date
- Because by default, collect will fetch *all* assignments, even though which are past the deadline - which thus could get zero points, while one submitted right before the deadline would get points. Of course it depends on how grading is set up. - Controlled with the "nbgrader collect --before-duedate". In the future there could be a "--before=TIMESTAMP" option. - If there are no assignments submitted before the due date, take the latest assignment, even after the due date. - There could be partial credit for things after the due date, so the it makes sense to take something better after the due date than worse before. But, nbgrader can only store one submission and the evaluation is separate from the collection, so we can't support that easily yet. - This initial patch contributed by @aleksanderilin under the nbgrader license.
1 parent 4c5d6f6 commit 2f42701

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

nbgrader/apps/collectapp.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
{'ExchangeCollect' : {'update': True}},
2121
"Update existing submissions with ones that have newer timestamps."
2222
),
23+
'before_duedate': (
24+
{'ExchangeCollect' : {'before_duedate': True}},
25+
"Collect the last submission before due date or the last submission if no submission before due date."
26+
),
2327
})
2428

2529
class CollectApp(NbGrader):

nbgrader/exchange/collect.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import sys
55
from collections import defaultdict
66
from textwrap import dedent
7+
import datetime
78

89
from traitlets import Bool
910

1011
from .exchange import Exchange
12+
from ..api import Gradebook, MissingEntry
1113
from ..utils import check_mode, parse_utc
1214

1315
# pwd is for matching unix names with student ide, so we shouldn't import it on
@@ -31,6 +33,11 @@ class ExchangeCollect(Exchange):
3133
help="Update existing submissions with ones that have newer timestamps."
3234
).tag(config=True)
3335

36+
before_duedate = Bool(
37+
False,
38+
help="Collect the last submission before due date or the last submission if no submission before due date."
39+
).tag(config=True)
40+
3441
check_owner = Bool(
3542
default_value=True,
3643
help="Whether to cross-check the student_id with the UNIX-owner of the submitted directory."
@@ -63,7 +70,24 @@ def init_src(self):
6370
pattern = os.path.join(self.inbound_path, '{}+{}+*'.format(student_id, self.coursedir.assignment_id))
6471
records = [self._path_to_record(f) for f in glob.glob(pattern)]
6572
usergroups = groupby(records, lambda item: item['username'])
66-
self.src_records = [self._sort_by_timestamp(v)[0] for v in usergroups.values()]
73+
74+
with Gradebook(self.coursedir.db_url, self.coursedir.course_id) as gb:
75+
try:
76+
assignment = gb.find_assignment(self.coursedir.assignment_id)
77+
self.duedate = assignment.duedate
78+
except MissingEntry:
79+
self.duedate = None
80+
if self.duedate is None or not self.before_duedate:
81+
self.src_records = [self._sort_by_timestamp(v)[0] for v in usergroups.values()]
82+
else:
83+
self.src_records = []
84+
for v in usergroups.values():
85+
records = self._sort_by_timestamp(v)
86+
records_before_duedate = [record for record in records if record['timestamp'] <= self.duedate]
87+
if records_before_duedate:
88+
self.src_records.append(records_before_duedate[0])
89+
else:
90+
self.src_records.append(records[0])
6791

6892
def init_dest(self):
6993
pass
@@ -108,6 +132,10 @@ def copy_files(self):
108132
if self.update and (existing_timestamp is None or new_timestamp > existing_timestamp):
109133
copy = True
110134
updating = True
135+
elif self.before_duedate and existing_timestamp != new_timestamp:
136+
copy = True
137+
updating = True
138+
111139
else:
112140
copy = True
113141

0 commit comments

Comments
 (0)