Skip to content

Commit

Permalink
Merge branch 'master' into update-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
lgpage committed Jan 14, 2017
2 parents dd1d35e + 893b3fd commit 6c24b40
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 175 deletions.
11 changes: 11 additions & 0 deletions nbgrader/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from . import utils

import contextlib

from sqlalchemy import (create_engine, ForeignKey, Column, String, Text,
DateTime, Interval, Float, Enum, UniqueConstraint, Boolean)
from sqlalchemy.orm import sessionmaker, scoped_session, relationship, column_property
Expand Down Expand Up @@ -2410,3 +2412,12 @@ def notebook_submission_dicts(self, notebook_id, assignment_id):
"failed_tests", "flagged"
]
return [dict(zip(keys, x)) for x in submissions]


@contextlib.contextmanager
def open_gradebook(db_url):
gradebook = Gradebook(db_url)
try:
yield gradebook
finally:
gradebook.close()
181 changes: 86 additions & 95 deletions nbgrader/apps/dbapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from traitlets import default, Unicode, Bool

from . import NbGrader
from ..api import Gradebook, MissingEntry
from ..api import open_gradebook, MissingEntry

aliases = {
'log-level': 'Application.log_level',
Expand Down Expand Up @@ -65,9 +65,8 @@ def start(self):
}

self.log.info("Creating/updating student with ID '%s': %s", student_id, student)
gb = Gradebook(self.db_url)
gb.update_or_create_student(student_id, **student)
gb.close()
with open_gradebook(self.db_url) as gb:
gb.update_or_create_student(student_id, **student)

student_remove_flags = {}
student_remove_flags.update(flags)
Expand Down Expand Up @@ -96,23 +95,22 @@ def start(self):

student_id = self.extra_args[0]

gb = Gradebook(self.db_url)
try:
student = gb.find_student(student_id)
except MissingEntry:
self.fail("No such student: '%s'", student_id)
with open_gradebook(self.db_url) as gb:
try:
student = gb.find_student(student_id)
except MissingEntry:
self.fail("No such student: '%s'", student_id)

if len(student.submissions) > 0:
if self.force:
self.log.warn("Removing associated grades")
else:
self.log.warn("!!! There are grades in the database for student '%s'.", student_id)
self.log.warn("!!! Removing this student will also remove these grades.")
self.fail("!!! If you are SURE this is what you want to do, rerun with --force.")
if len(student.submissions) > 0:
if self.force:
self.log.warn("Removing associated grades")
else:
self.log.warn("!!! There are grades in the database for student '%s'.", student_id)
self.log.warn("!!! Removing this student will also remove these grades.")
self.fail("!!! If you are SURE this is what you want to do, rerun with --force.")

self.log.info("Removing student with ID '%s'", student_id)
gb.remove_student(student_id)
gb.close()
self.log.info("Removing student with ID '%s'", student_id)
gb.remove_student(student_id)


class DbStudentImportApp(NbGrader):
Expand All @@ -134,31 +132,30 @@ def start(self):
self.fail("No such file: '%s'", path)
self.log.info("Importing students from: '%s'", path)

gb = Gradebook(self.db_url)
allowed_keys = ["last_name", "first_name", "email", "id"]

with open(path, 'r') as fh:
reader = csv.DictReader(fh)
for row in reader:
if "id" not in row:
self.fail("Malformatted CSV file: must contain a column for 'id'")

# make sure all the keys are actually allowed in the database,
# and that any empty strings are parsed as None
student = {}
for key, val in row.items():
if key not in allowed_keys:
continue
if val == '':
student[key] = None
else:
student[key] = val
student_id = student.pop("id")

self.log.info("Creating/updating student with ID '%s': %s", student_id, student)
gb.update_or_create_student(student_id, **student)

gb.close()
with open_gradebook(self.db_url) as gb:
with open(path, 'r') as fh:
reader = csv.DictReader(fh)
for row in reader:
if "id" not in row:
self.fail("Malformatted CSV file: must contain a column for 'id'")

# make sure all the keys are actually allowed in the database,
# and that any empty strings are parsed as None
student = {}
for key, val in row.items():
if key not in allowed_keys:
continue
if val == '':
student[key] = None
else:
student[key] = val
student_id = student.pop("id")

self.log.info("Creating/updating student with ID '%s': %s", student_id, student)
gb.update_or_create_student(student_id, **student)


class DbStudentListApp(NbGrader):

Expand All @@ -171,11 +168,10 @@ class DbStudentListApp(NbGrader):
def start(self):
super(DbStudentListApp, self).start()

gb = Gradebook(self.db_url)
print("There are %d students in the database:" % len(gb.students))
for student in gb.students:
print("%s (%s, %s) -- %s" % (student.id, student.last_name, student.first_name, student.email))
gb.close()
with open_gradebook(self.db_url) as gb:
print("There are %d students in the database:" % len(gb.students))
for student in gb.students:
print("%s (%s, %s) -- %s" % (student.id, student.last_name, student.first_name, student.email))


assignment_add_aliases = {}
Expand Down Expand Up @@ -210,9 +206,8 @@ def start(self):
}

self.log.info("Creating/updating assignment with ID '%s': %s", assignment_id, assignment)
gb = Gradebook(self.db_url)
gb.update_or_create_assignment(assignment_id, **assignment)
gb.close()
with open_gradebook(self.db_url) as gb:
gb.update_or_create_assignment(assignment_id, **assignment)


assignment_remove_flags = {}
Expand Down Expand Up @@ -242,23 +237,22 @@ def start(self):

assignment_id = self.extra_args[0]

gb = Gradebook(self.db_url)
try:
assignment = gb.find_assignment(assignment_id)
except MissingEntry:
self.fail("No such assignment: '%s'", assignment_id)
with open_gradebook(self.db_url) as gb:
try:
assignment = gb.find_assignment(assignment_id)
except MissingEntry:
self.fail("No such assignment: '%s'", assignment_id)

if len(assignment.submissions) > 0:
if self.force:
self.log.warn("Removing associated grades")
else:
self.log.warn("!!! There are grades in the database for assignment '%s'.", assignment_id)
self.log.warn("!!! Removing this assignment will also remove these grades.")
self.fail("!!! If you are SURE this is what you want to do, rerun with --force.")
if len(assignment.submissions) > 0:
if self.force:
self.log.warn("Removing associated grades")
else:
self.log.warn("!!! There are grades in the database for assignment '%s'.", assignment_id)
self.log.warn("!!! Removing this assignment will also remove these grades.")
self.fail("!!! If you are SURE this is what you want to do, rerun with --force.")

self.log.info("Removing assignment with ID '%s'", assignment_id)
gb.remove_assignment(assignment_id)
gb.close()
self.log.info("Removing assignment with ID '%s'", assignment_id)
gb.remove_assignment(assignment_id)


class DbAssignmentImportApp(NbGrader):
Expand All @@ -280,31 +274,29 @@ def start(self):
self.fail("No such file: '%s'", path)
self.log.info("Importing assignments from: '%s'", path)

gb = Gradebook(self.db_url)
allowed_keys = ["duedate", "name"]

with open(path, 'r') as fh:
reader = csv.DictReader(fh)
for row in reader:
if "name" not in row:
self.fail("Malformatted CSV file: must contain a column for 'name'")

# make sure all the keys are actually allowed in the database,
# and that any empty strings are parsed as None
assignment = {}
for key, val in row.items():
if key not in allowed_keys:
continue
if val == '':
assignment[key] = None
else:
assignment[key] = val
assignment_id = assignment.pop("name")

self.log.info("Creating/updating assignment with name '%s': %s", assignment_id, assignment)
gb.update_or_create_assignment(assignment_id, **assignment)

gb.close()
with open_gradebook(self.db_url) as gb:
with open(path, 'r') as fh:
reader = csv.DictReader(fh)
for row in reader:
if "name" not in row:
self.fail("Malformatted CSV file: must contain a column for 'name'")

# make sure all the keys are actually allowed in the database,
# and that any empty strings are parsed as None
assignment = {}
for key, val in row.items():
if key not in allowed_keys:
continue
if val == '':
assignment[key] = None
else:
assignment[key] = val
assignment_id = assignment.pop("name")

self.log.info("Creating/updating assignment with name '%s': %s", assignment_id, assignment)
gb.update_or_create_assignment(assignment_id, **assignment)


class DbAssignmentListApp(NbGrader):
Expand All @@ -318,13 +310,12 @@ class DbAssignmentListApp(NbGrader):
def start(self):
super(DbAssignmentListApp, self).start()

gb = Gradebook(self.db_url)
print("There are %d assignments in the database:" % len(gb.assignments))
for assignment in gb.assignments:
print("%s (due: %s)" % (assignment.name, assignment.duedate))
for notebook in assignment.notebooks:
print(" - %s" % notebook.name)
gb.close()
with open_gradebook(self.db_url) as gb:
print("There are %d assignments in the database:" % len(gb.assignments))
for assignment in gb.assignments:
print("%s (due: %s)" % (assignment.name, assignment.duedate))
for notebook in assignment.notebooks:
print(" - %s" % notebook.name)


class DbStudentApp(NbGrader):
Expand Down
5 changes: 4 additions & 1 deletion nbgrader/nbformat/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def _upgrade_v0_to_v1(self, cell):
del meta['points']

if 'points' in meta:
meta['points'] = float(meta['points'])
if meta['points'] == '':
meta['points'] = 0.0
else:
meta['points'] = float(meta['points'])

allowed = set(self.schema["properties"].keys())
keys = set(meta.keys()) - allowed
Expand Down
Loading

0 comments on commit 6c24b40

Please sign in to comment.