Ejemplo n.º 1
0
    def test_grade_timestamp(self, gradebook):
        """Is a timestamp correctly read in?"""
        self._copy_file("files/submitted-unchanged.ipynb",
                        "source/ps1/p1.ipynb")
        run_command(["nbgrader", "assign", "ps1", "--db", gradebook])

        self._copy_file("files/submitted-unchanged.ipynb",
                        "submitted/foo/ps1/p1.ipynb")
        self._make_file('submitted/foo/ps1/timestamp.txt',
                        "2015-02-02 15:58:23.948203 PST")

        self._copy_file("files/submitted-changed.ipynb",
                        "submitted/bar/ps1/p1.ipynb")
        self._make_file('submitted/bar/ps1/timestamp.txt',
                        "2015-02-01 14:58:23.948203 PST")

        run_command(["nbgrader", "autograde", "ps1", "--db", gradebook])

        assert os.path.isfile("autograded/foo/ps1/p1.ipynb")
        assert os.path.isfile("autograded/foo/ps1/timestamp.txt")
        assert os.path.isfile("autograded/bar/ps1/p1.ipynb")
        assert os.path.isfile("autograded/bar/ps1/timestamp.txt")

        gb = Gradebook(gradebook)
        submission = gb.find_submission('ps1', 'foo')
        assert submission.total_seconds_late > 0
        submission = gb.find_submission('ps1', 'bar')
        assert submission.total_seconds_late == 0

        # make sure it still works to run it a second time
        run_command(["nbgrader", "autograde", "ps1", "--db", gradebook])
    def test_add_remove_extra_notebooks(self, db):
        """Are extra notebooks added and removed?"""
        gb = Gradebook(db)
        assignment = gb.add_assignment("ps1")

        self._copy_file("files/test.ipynb", "source/ps1/test.ipynb")
        run_command(["nbgrader", "assign", "ps1", "--db", db])

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 1
        notebook1 = gb.find_notebook("test", "ps1")

        self._copy_file("files/test.ipynb", "source/ps1/test2.ipynb")
        run_command(["nbgrader", "assign", "ps1", "--db", db, "--force"])

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 2
        gb.db.refresh(notebook1)
        notebook2 = gb.find_notebook("test2", "ps1")

        os.remove("source/ps1/test2.ipynb")
        run_command(["nbgrader", "assign", "ps1", "--db", db, "--force"])

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 1
        gb.db.refresh(notebook1)
        with pytest.raises(InvalidRequestError):
            gb.db.refresh(notebook2)
Ejemplo n.º 3
0
    def _clean_old_notebooks(self, assignment_id, student_id):
        gb = Gradebook(self.db_url)
        assignment = gb.find_assignment(assignment_id)
        regexp = os.path.join(
            self._format_source("(?P<assignment_id>.*)", "(?P<student_id>.*)"),
            "(?P<notebook_id>.*).ipynb")

        # find a set of notebook ids for new notebooks
        new_notebook_ids = set([])
        for notebook in self.notebooks:
            m = re.match(regexp, notebook)
            if m is None:
                raise RuntimeError("Could not match '%s' with regexp '%s'", notebook, regexp)
            gd = m.groupdict()
            if gd['assignment_id'] == assignment_id and gd['student_id'] == student_id:
                new_notebook_ids.add(gd['notebook_id'])

        # pull out the existing notebook ids
        old_notebook_ids = set(x.name for x in assignment.notebooks)

        # no added or removed notebooks, so nothing to do
        if old_notebook_ids == new_notebook_ids:
            return

        # some notebooks have been removed, but there are submissions associated
        # with the assignment, so we don't want to overwrite stuff
        if len(assignment.submissions) > 0:
            self.fail("Cannot modify existing assignment '%s' because there are submissions associated with it", assignment)

        # remove the old notebooks
        for notebook_id in (old_notebook_ids - new_notebook_ids):
            self.log.warning("Removing notebook '%s' from the gradebook", notebook_id)
            gb.remove_notebook(notebook_id, assignment_id)
Ejemplo n.º 4
0
    def test_grade_timestamp(self, gradebook):
        """Is a timestamp correctly read in?"""
        self._copy_file("files/submitted-unchanged.ipynb", "source/ps1/p1.ipynb")
        run_command('nbgrader assign ps1 --db="{}" '.format(gradebook))

        self._copy_file("files/submitted-unchanged.ipynb", "submitted/foo/ps1/p1.ipynb")
        self._make_file('submitted/foo/ps1/timestamp.txt', "2015-02-02 15:58:23.948203 PST")

        self._copy_file("files/submitted-changed.ipynb", "submitted/bar/ps1/p1.ipynb")
        self._make_file('submitted/bar/ps1/timestamp.txt', "2015-02-01 14:58:23.948203 PST")

        run_command('nbgrader autograde ps1 --db="{}"'.format(gradebook))

        assert os.path.isfile("autograded/foo/ps1/p1.ipynb")
        assert os.path.isfile("autograded/foo/ps1/timestamp.txt")
        assert os.path.isfile("autograded/bar/ps1/p1.ipynb")
        assert os.path.isfile("autograded/bar/ps1/timestamp.txt")

        gb = Gradebook(gradebook)
        submission = gb.find_submission('ps1', 'foo')
        assert submission.total_seconds_late > 0
        submission = gb.find_submission('ps1', 'bar')
        assert submission.total_seconds_late == 0

        # make sure it still works to run it a second time
        run_command('nbgrader autograde ps1 --db="{}"'.format(gradebook))
    def test_grade(self, gradebook):
        """Can files be graded?"""
        self._copy_file("files/submitted-unchanged.ipynb", "source/ps1/p1.ipynb")
        run_command('nbgrader assign ps1 --db="{}" '.format(gradebook))

        self._copy_file("files/submitted-unchanged.ipynb", "submitted/foo/ps1/p1.ipynb")
        self._copy_file("files/submitted-changed.ipynb", "submitted/bar/ps1/p1.ipynb")
        run_command('nbgrader autograde ps1 --db="{}"'.format(gradebook))

        assert os.path.isfile("autograded/foo/ps1/p1.ipynb")
        assert not os.path.isfile("autograded/foo/ps1/timestamp.txt")
        assert os.path.isfile("autograded/bar/ps1/p1.ipynb")
        assert not os.path.isfile("autograded/bar/ps1/timestamp.txt")

        gb = Gradebook(gradebook)
        notebook = gb.find_submission_notebook("p1", "ps1", "foo")
        assert notebook.score == 1
        assert notebook.max_score == 4
        assert notebook.needs_manual_grade == False

        comment1 = gb.find_comment(0, "p1", "ps1", "foo")
        comment2 = gb.find_comment(1, "p1", "ps1", "foo")
        assert comment1.comment == "No response."
        assert comment2.comment == "No response."

        notebook = gb.find_submission_notebook("p1", "ps1", "bar")
        assert notebook.score == 2
        assert notebook.max_score == 4
        assert notebook.needs_manual_grade == True

        comment1 = gb.find_comment(0, "p1", "ps1", "bar")
        comment2 = gb.find_comment(1, "p1", "ps1", "bar")
        assert comment1.comment == None
        assert comment2.comment == None
Ejemplo n.º 6
0
    def test_add_remove_extra_notebooks(self, db):
        """Are extra notebooks added and removed?"""
        gb = Gradebook(db)
        assignment = gb.add_assignment("ps1")

        self._copy_file("files/test.ipynb", "source/ps1/test.ipynb")
        run_command('nbgrader assign ps1 --db="{}"'.format(db))

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 1
        notebook1 = gb.find_notebook("test", "ps1")

        self._copy_file("files/test.ipynb", "source/ps1/test2.ipynb")
        run_command('nbgrader assign ps1 --db="{}" --force'.format(db))

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 2
        gb.db.refresh(notebook1)
        notebook2 = gb.find_notebook("test2", "ps1")

        os.remove("source/ps1/test2.ipynb")
        run_command('nbgrader assign ps1 --db="{}" --force'.format(db))

        gb.db.refresh(assignment)
        assert len(assignment.notebooks) == 1
        gb.db.refresh(notebook1)
        with pytest.raises(InvalidRequestError):
            gb.db.refresh(notebook2)
Ejemplo n.º 7
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.db_url = resources['nbgrader']['db_url']

        if self.notebook_id == '':
            raise ValueError("Invalid notebook id: '{}'".format(
                self.notebook_id))
        if self.assignment_id == '':
            raise ValueError("Invalid assignment id: '{}'".format(
                self.assignment_id))

        # create a place to put new cell information
        self.new_grade_cells = {}
        self.new_solution_cells = {}
        self.new_source_cells = {}

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        nb, resources = super(SaveCells, self).preprocess(nb, resources)

        # create the notebook and save it to the database
        self._create_notebook()

        return nb, resources
Ejemplo n.º 8
0
    def test_grade_timestamp(self):
        """Is a timestamp correctly read in?"""
        with self._temp_cwd(["files/submitted-unchanged.ipynb", "files/submitted-changed.ipynb"]):
            dbpath = self._setup_db()

            os.makedirs('source/ps1')
            shutil.copy('submitted-unchanged.ipynb', 'source/ps1/p1.ipynb')
            self._run_command('nbgrader assign ps1 --db="{}" '.format(dbpath))

            os.makedirs('submitted/foo/ps1')
            shutil.move('submitted-unchanged.ipynb', 'submitted/foo/ps1/p1.ipynb')
            with open('submitted/foo/ps1/timestamp.txt', 'w') as fh:
                fh.write("2015-02-02 15:58:23.948203 PST")

            os.makedirs('submitted/bar/ps1')
            shutil.move('submitted-changed.ipynb', 'submitted/bar/ps1/p1.ipynb')
            with open('submitted/bar/ps1/timestamp.txt', 'w') as fh:
                fh.write("2015-02-01 14:58:23.948203 PST")

            self._run_command('nbgrader autograde ps1 --db="{}"'.format(dbpath))

            assert os.path.isfile("autograded/foo/ps1/p1.ipynb")
            assert os.path.isfile("autograded/foo/ps1/timestamp.txt")
            assert os.path.isfile("autograded/bar/ps1/p1.ipynb")
            assert os.path.isfile("autograded/bar/ps1/timestamp.txt")

            gb = Gradebook(dbpath)
            submission = gb.find_submission('ps1', 'foo')
            assert submission.total_seconds_late > 0
            submission = gb.find_submission('ps1', 'bar')
            assert submission.total_seconds_late == 0

            # make sure it still works to run it a second time
            self._run_command('nbgrader autograde ps1 --db="{}"'.format(dbpath))
Ejemplo n.º 9
0
 def _setup_db(self):
     dbpath = self._init_db()
     gb = Gradebook(dbpath)
     gb.add_assignment("ps1", duedate="2015-02-02 14:58:23.948203 PST")
     gb.add_student("foo")
     gb.add_student("bar")
     return dbpath
Ejemplo n.º 10
0
 def needs_manual_grading(self):
     try:
         gb = Gradebook('sqlite:///'+self.grader_repo_path +'/gradebook.db')
         subm = gb.find_submission(self.asgn.name, self.student_prefix+self.stu.canvas_id)
         flag = subm.needs_manual_grade
     finally:
         gb.close()
     return flag
Ejemplo n.º 11
0
def extract_grades(labSec, aNo):
    labSec = "AY"+labSec if len(labSec) == 1 else labSec
    gb = Gradebook('sqlite:////class/cs101/etc/sxns/'+labSec+'/gradebook.db')
    aNo = "lab" + aNo if len(aNo) == 2 else "lab0" + aNo
    grades = {}
    #print (gb.assignment_submissions)
    for s in gb.assignment_submissions(aNo):
        grades[s.student_id] = float(s.score)
    return grades
Ejemplo n.º 12
0
class GetGrades(NbGraderPreprocessor):
    """Preprocessor for saving grades from the database to the notebook"""
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.student_id = resources['nbgrader']['student']
        self.db_url = resources['nbgrader']['db_url']

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        # process the cells
        nb, resources = super(GetGrades, self).preprocess(nb, resources)

        submission = self.gradebook.find_submission_notebook(
            self.notebook_id, self.assignment_id, self.student_id)
        resources['nbgrader']['score'] = submission.score
        resources['nbgrader']['max_score'] = submission.max_score

        return nb, resources

    def _get_comment(self, cell, resources):
        """Graders can optionally add comments to the student's solutions, so
        add the comment information into the database if it doesn't
        already exist. It should NOT overwrite existing comments that
        might have been added by a grader already.

        """

        # retrieve or create the comment object from the database
        comment = self.gradebook.find_comment(
            cell.metadata['nbgrader']['grade_id'], self.notebook_id,
            self.assignment_id, self.student_id)

        # save it in the notebook
        cell.metadata.nbgrader['comment'] = comment.comment

    def _get_score(self, cell, resources):
        grade = self.gradebook.find_grade(
            cell.metadata['nbgrader']['grade_id'], self.notebook_id,
            self.assignment_id, self.student_id)

        cell.metadata.nbgrader['score'] = grade.score
        cell.metadata.nbgrader['points'] = grade.max_score

    def preprocess_cell(self, cell, resources, cell_index):
        # if it's a solution cell, then add a comment
        if utils.is_solution(cell):
            self._get_comment(cell, resources)

        # if it's a grade cell, the add a grade
        if utils.is_grade(cell):
            self._get_score(cell, resources)

        return cell, resources
Ejemplo n.º 13
0
    def preprocess(self, nb, resources):
        # connect to the mongo database
        self.gradebook = Gradebook(self.db_name, ip=self.db_ip, port=self.db_port)
        self.assignment = self.gradebook.find_assignment(
            assignment_id=self.assignment_id)
        self.notebook_id = resources['unique_key']

        nb, resources = super(OverwriteGradeCells, self).preprocess(nb, resources)

        return nb, resources
Ejemplo n.º 14
0
def assignmentWithSubmissionNoMarks(assignmentWithTask: Gradebook) -> Gradebook:
    assignmentWithTask.add_student('hacker123')
    assignmentWithTask.add_student('bitdiddle')
    assignmentWithTask.add_student('louisreasoner')
    s1 = assignmentWithTask.add_submission('foo', 'hacker123')
    s2 = assignmentWithTask.add_submission('foo', 'bitdiddle')
    s1.flagged = True
    s2.flagged = False
    assignmentWithTask.db.commit()
    return assignmentWithTask
Ejemplo n.º 15
0
    def test_save_cells(self, db):
        """Ensure cells are saved into the database"""
        self._copy_file("files/test.ipynb", "source/ps1/test.ipynb")

        gb = Gradebook(db)
        gb.add_assignment("ps1")

        run_command(["nbgrader", "assign", "ps1", "--db", db])

        notebook = gb.find_notebook("test", "ps1")
        assert len(notebook.grade_cells) == 6
Ejemplo n.º 16
0
    def test_save_cells(self, db):
        """Ensure cells are saved into the database"""
        self._copy_file("files/test.ipynb", "source/ps1/test.ipynb")

        gb = Gradebook(db)
        gb.add_assignment("ps1")

        run_command('nbgrader assign ps1 --db="{}"'.format(db))

        notebook = gb.find_notebook("test", "ps1")
        assert len(notebook.grade_cells) == 8
Ejemplo n.º 17
0
    def init_assignment(self, assignment_id, student_id):
        super(AutogradeApp, self).init_assignment(assignment_id, student_id)

        # try to get the student from the database, and throw an error if it
        # doesn't exist
        gb = Gradebook(self.db_url)
        try:
            gb.find_student(student_id)
        except MissingEntry:
            if self.create_student:
                self.log.warning("Creating student with ID '%s'", student_id)
                gb.add_student(student_id)
            else:
                self.fail("No student with ID '%s' exists in the database", student_id)

        # try to read in a timestamp from file
        src_path = self._format_source(assignment_id, student_id)
        timestamp = self._get_existing_timestamp(src_path)
        if timestamp:
            submission = gb.update_or_create_submission(
                assignment_id, student_id, timestamp=timestamp)
            self.log.info("%s submitted at %s", submission, timestamp)

            # if the submission is late, print out how many seconds late it is
            if timestamp and submission.total_seconds_late > 0:
                self.log.warning("%s is %s seconds late", submission, submission.total_seconds_late)

        else:
            submission = gb.update_or_create_submission(assignment_id, student_id)

        # copy files over from the source directory
        self.log.info("Overwriting files with master versions from the source directory")
        dest_path = self._format_dest(assignment_id, student_id)
        source_path = self.directory_structure.format(
            nbgrader_step=self.source_directory,
            student_id='.',
            assignment_id=assignment_id)
        source_files = utils.find_all_files(source_path, self.ignore + ["*.ipynb"])

        # copy them to the build directory
        for filename in source_files:
            dest = os.path.join(dest_path, os.path.relpath(filename, source_path))
            ensure_dir_exists(os.path.dirname(dest))
            if not os.path.normpath(dest) == os.path.normpath(filename):
                self.log.info("Linking %s -> %s", filename, dest)
                link_or_copy(filename, dest)

        # ignore notebooks that aren't in the database
        notebooks = []
        for notebook in self.notebooks:
            notebook_id = os.path.splitext(os.path.basename(notebook))[0]
            try:
                gb.find_notebook(notebook_id, assignment_id)
            except MissingEntry:
                self.log.warning("Skipping unknown notebook: %s", notebook)
                continue
            else:
                notebooks.append(notebook)
        self.notebooks = notebooks
Ejemplo n.º 18
0
def test_find_comment(assignmentWithSubmissionWithMarks: Gradebook) -> None:
    s = assignmentWithSubmissionWithMarks.find_submission('foo', 'hacker123')
    for n in s.notebooks:
        comments = n.comments

        for c1 in comments:
            c2 = assignmentWithSubmissionWithMarks.find_comment(c1.name, n.name, 'foo', 'hacker123')
            assert c1 == c2

        with pytest.raises(MissingEntry):
            assignmentWithSubmissionWithMarks.find_comment('asdf', n.name, 'foo', 'hacker123')
    def test_remove_student_db(self, tmpdir_factory):
        self._mock_remove_student()
        tmp_dir = tmpdir_factory.mktemp(self.course_id)
        os.chdir(tmp_dir)
        self._add_empty_gradebook(tmp_dir)
        gb = Gradebook('sqlite:///gradebook.db', course_id=self.course_id)
        gb.add_student(self.student_id)

        # test valid
        cm.main(['remove_students', self.course_id, self.student_id])
        assert len(gb.students) == 0
Ejemplo n.º 20
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.db_url = resources['nbgrader']['db_url']

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        nb, resources = super(OverwriteCells, self).preprocess(nb, resources)

        return nb, resources
Ejemplo n.º 21
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.student_id = resources['nbgrader']['student']
        self.db_url = resources['nbgrader']['db_url']

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        # process the cells
        nb, resources = super(SaveAutoGrades, self).preprocess(nb, resources)

        return nb, resources
Ejemplo n.º 22
0
    def init_assignment(self, assignment_id, student_id):
        super(AssignApp, self).init_assignment(assignment_id, student_id)

        # try to get the assignment from the database, and throw an error if it
        # doesn't exist
        gb = Gradebook(self.db_url)
        try:
            gb.find_assignment(assignment_id)
        except MissingEntry:
            if self.create_assignment:
                self.log.warning("Creating assignment '%s'", assignment_id)
                gb.add_assignment(assignment_id)
            else:
                self.fail("No assignment called '%s' exists in the database", assignment_id)
Ejemplo n.º 23
0
    def test_save_cells(self):
        """Ensure cells are saved into the database"""
        with self._temp_cwd(["files/test.ipynb"]):
            os.makedirs('source/ps1')
            shutil.move("test.ipynb", "source/ps1/test.ipynb")

            dbpath = self._init_db()
            gb = Gradebook(dbpath)
            gb.add_assignment("ps1")

            self._run_command('nbgrader assign ps1 --db="{}"'.format(dbpath))

            notebook = gb.find_notebook("test", "ps1")
            assert_equal(len(notebook.grade_cells), 8)
Ejemplo n.º 24
0
def check_needs_manual_grading(course, anm, stu, grader):
    gradebook_file = os.path.join(course['course_storage_path'], grader,
                                  course['instructor_repo_path'],
                                  course['gradebook_filename'])
    gb = Gradebook('sqlite:///' + gradebook_file)

    try:
        subm = gb.find_submission(anm, course['student_name_prefix'] + stu)
        flag = subm.needs_manual_grade
    except MissingEntry as e:
        print(e)
    finally:
        gb.close()

    return flag
Ejemplo n.º 25
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.db_url = resources['nbgrader']['db_url']

        if self.notebook_id == '':
            raise ValueError("Invalid notebook id: '{}'".format(self.notebook_id))
        if self.assignment_id == '':
            raise ValueError("Invalid assignment id: '{}'".format(self.assignment_id))

        # create a place to put new cell information
        self.new_grade_cells = {}
        self.new_solution_cells = {}
        self.new_source_cells = {}

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        nb, resources = super(SaveCells, self).preprocess(nb, resources)

        # create the notebook and save it to the database
        self._create_notebook()

        return nb, resources
Ejemplo n.º 26
0
 def get_max_nb_score(self):
     """Return the max code score from the gradebook"""
     nb_name = os.path.splitext(self.nb_filename)[0]
     with Gradebook(self.db_path) as gb:
         nb = gb.find_notebook(nb_name, self.pset_id)
         max_score = nb.max_code_score
     return max_score
Ejemplo n.º 27
0
    def _retrieve_grades_from_db(self):
        db_url = Path(self.gradebook_dir, 'gradebook.db')
        # raise an error if the database does not exist
        if not db_url.exists():
            logger.error(
                f'Gradebook database file does not exist at: {db_url}.')
            raise GradesSenderCriticalError

        out = []
        max_score = 0
        # Create the connection to the gradebook database
        with Gradebook(f'sqlite:///{db_url}', course_id=self.course_id) as gb:
            try:
                # retrieve the assignment record
                assignment_row = gb.find_assignment(self.assignment_name)
                max_score = assignment_row.max_score
                submissions = gb.assignment_submissions(self.assignment_name)
                logger.info(
                    f'Found {len(submissions)} submissions for assignment: {self.assignment_name}'
                )
            except MissingEntry as e:
                logger.info(
                    'Assignment or Submission is missing in database: %s' % e)
                raise GradesSenderMissingInfoError

            for submission in submissions:
                # retrieve the student to use the lms id
                student = gb.find_student(submission.student_id)
                out.append({
                    'score': submission.score,
                    'lms_user_id': student.lms_user_id
                })
        logger.info(f'Grades found: {out}')
        logger.info('max_score for this assignment %s' % max_score)
        return max_score, out
Ejemplo n.º 28
0
    def _get_db(cls, course_id: str) -> Gradebook:
        '''
        Create new connection to sqlite database.
        '''

        return Gradebook(f'sqlite:////home/{grader / course_id}/grader.db',
                         course_id=course_id)
Ejemplo n.º 29
0
    def register_assignment(self, assignment_name: str,
                            **kwargs: dict) -> Assignment:
        """
        Adds an assignment to nbgrader database

        Args:
            assignment_name: The assingment's name
        Raises:
            InvalidEntry: when there was an error adding the assignment to the database
        """
        if not assignment_name:
            raise ValueError('assignment_name missing')
        logger.debug('Assignment name normalized %s to save in gradebook' %
                     assignment_name)
        assignment = None
        with Gradebook(self.db_url, course_id=self.course_id) as gb:
            try:
                assignment = gb.update_or_create_assignment(
                    assignment_name, **kwargs)
                logger.debug('Added assignment %s to gradebook' %
                             assignment_name)
            except InvalidEntry as e:
                logger.debug(
                    'Error ocurred by adding assignment to gradebook: %s' % e)
        return assignment
Ejemplo n.º 30
0
 def gradebook(self):
     gb = self.settings['nbgrader_gradebook']
     if gb is None:
         self.log.debug("creating gradebook")
         gb = Gradebook(self.db_url, self.coursedir.course_id)
         self.settings['nbgrader_gradebook'] = gb
     return gb
Ejemplo n.º 31
0
    def upload_grade(self, canvas, failed = False):

        if self.grade_uploaded:
            print('Grade already uploaded. Returning')
            return SubmissionStatus.GRADE_UPLOADED

        print('Uploading grade for submission ' + self.asgn.name+':'+self.stu.canvas_id)
        if failed:
            score = 0
        else:
            try:
                gb = Gradebook('sqlite:///'+self.grader_repo_path +'/gradebook.db')
                subm = gb.find_submission(self.asgn.name, self.student_prefix+self.stu.canvas_id)
                score = subm.score
            except Exception as e:
                print('Error when accessing grade from gradebook db')
                print(e)
                self.error = e
                return SubmissionStatus.ERROR
            finally:
                gb.close()

        try:
            max_score = self.compute_max_score()
        except Exception as e:
            print('Error when trying to compute max score from release notebook')
            print(e)
            self.error = e
            return SubmissionStatus.ERROR

        self.score = score
        self.max_score = max_score
        pct = "{:.2f}".format(100*score/max_score)
    
        print('Student ' + self.stu.canvas_id + ' assignment ' + self.asgn.name + ' score: ' + str(score) + (' [HARDFAIL]' if failed else ''))
        print('Assignment ' + self.asgn.name + ' max score: ' + str(max_score))
        print('Pct Score: ' + pct)
        print('Posting to canvas...')
        try:
            canvas.put_grade(self.asgn.canvas_id, self.stu.canvas_id, pct)
        except GradeNotUploadedError as e: 
            print('Error when uploading grade')
            print(e.message)
            self.error = e
            return SubmissionStatus.ERROR
        self.grade_uploaded = True
        return SubmissionStatus.GRADE_UPLOADED
Ejemplo n.º 32
0
class SaveGradeCells(Preprocessor):
    """A preprocessor to save information about grade cells."""

    db_name = Unicode("gradebook", config=True, help="Database name")
    db_ip = Unicode("localhost",
                    config=True,
                    help="IP address for the database")
    db_port = Integer(27017, config=True, help="Port for the database")

    assignment_id = Unicode(u'assignment', config=True, help="Assignment ID")

    def preprocess(self, nb, resources):
        # connect to the mongo database
        self.gradebook = Gradebook(self.db_name,
                                   ip=self.db_ip,
                                   port=self.db_port)
        self.assignment = self.gradebook.find_assignment(
            assignment_id=self.assignment_id)
        self.notebook_id = resources['unique_key']

        nb, resources = super(SaveGradeCells, self).preprocess(nb, resources)

        return nb, resources

    def preprocess_cell(self, cell, resources, cell_index):
        if utils.is_grade(cell):
            grade_cell = self.gradebook.find_or_create_grade_cell(
                grade_id=cell.metadata.nbgrader.grade_id,
                notebook_id=self.notebook_id,
                assignment=self.assignment)

            grade_cell.max_score = float(cell.metadata.nbgrader['points'])

            # we only want the source and checksum for non-solution cells
            if utils.is_solution(cell):
                grade_cell.source = None
                grade_cell.checksum = None
            else:
                grade_cell.source = cell.source
                grade_cell.checksum = cell.metadata.nbgrader['checksum']

            self.gradebook.update_grade_cell(grade_cell)
            self.log.debug("Recorded grade cell %s into database",
                           grade_cell.grade_id)

        return cell, resources
Ejemplo n.º 33
0
 def get_course(self) -> Course:
     """
     Gets the course model instance
     """
     with Gradebook(self.db_url, course_id=self.course_id) as gb:
         course = gb.check_course(self.course_id)
         logger.debug(f'course got from db:{course}')
         return course
Ejemplo n.º 34
0
 def get_total_score(self):
     """Return total student score for notebook"""
     nb_name = os.path.splitext(self.nb_filename)[0]
     with Gradebook(self.db_path) as gb:
         nb = gb.find_submission_notebook(nb_name, self.pset_id,
                                          self.username)
         score = nb.code_score
     return score
Ejemplo n.º 35
0
class OverwriteGradeCells(Preprocessor):
    """A preprocessor to save information about grade cells."""

    db_name = Unicode("gradebook", config=True, help="Database name")
    db_ip = Unicode("localhost", config=True, help="IP address for the database")
    db_port = Integer(27017, config=True, help="Port for the database")

    assignment_id = Unicode(u'assignment', config=True, help="Assignment ID")

    def preprocess(self, nb, resources):
        # connect to the mongo database
        self.gradebook = Gradebook(self.db_name, ip=self.db_ip, port=self.db_port)
        self.assignment = self.gradebook.find_assignment(
            assignment_id=self.assignment_id)
        self.notebook_id = resources['unique_key']

        nb, resources = super(OverwriteGradeCells, self).preprocess(nb, resources)

        return nb, resources

    def preprocess_cell(self, cell, resources, cell_index):
        if utils.is_grade(cell):
            try:
                grade_cell = self.gradebook.find_grade_cell(
                    grade_id=cell.metadata.nbgrader.grade_id,
                    notebook_id=self.notebook_id,
                    assignment=self.assignment)
            except:
                return cell, resources

            cell.metadata.nbgrader['points'] = grade_cell.max_score

            # we only want the source and checksum for non-solution cells
            if not utils.is_solution(cell) and grade_cell.source:
                old_checksum = grade_cell.checksum
                new_checksum = utils.compute_checksum(cell)

                if old_checksum != new_checksum:
                    self.log.warning("Checksum for grade cell %s has changed!", grade_cell.grade_id)

                cell.source = grade_cell.source
                cell.metadata.nbgrader['checksum'] = grade_cell.checksum

            self.log.debug("Overwrote grade cell %s", grade_cell.grade_id)

        return cell, resources
Ejemplo n.º 36
0
def gradebook(request, tempdir):
    # create a "class files" directory
    origdir = os.getcwd()
    os.mkdir("class_files")
    os.chdir("class_files")

    # copy files from the user guide
    source_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "docs", "source", "user_guide", "source")
    submitted_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "docs", "source", "user_guide", "submitted")

    shutil.copytree(os.path.join(os.path.dirname(__file__), source_path), "source")
    shutil.copytree(os.path.join(os.path.dirname(__file__), submitted_path), "submitted")

    # create the gradebook
    gb = Gradebook("sqlite:///gradebook.db")
    gb.add_assignment("Problem Set 1")
    gb.add_student("Bitdiddle", first_name="Ben", last_name="B")
    gb.add_student("Hacker", first_name="Alyssa", last_name="H")
    gb.add_student("Reasoner", first_name="Louis", last_name="R")

    # run nbgrader assign
    run_command([
        "nbgrader", "assign", "Problem Set 1",
        "--IncludeHeaderFooter.header=source/header.ipynb"
    ])

    # run the autograder
    run_command(["nbgrader", "autograde", "Problem Set 1"])

    def fin():
        os.chdir(origdir)
        shutil.rmtree("class_files")
    request.addfinalizer(fin)

    return gb
Ejemplo n.º 37
0
    def init_assignment(self, assignment_id, student_id):
        super(AssignApp, self).init_assignment(assignment_id, student_id)

        # try to get the assignment from the database, and throw an error if it
        # doesn't exist
        gb = Gradebook(self.db_url)
        try:
            gb.find_assignment(assignment_id)
        except MissingEntry:
            if self.create_assignment:
                self.log.warning("Creating assignment '%s'", assignment_id)
                gb.add_assignment(assignment_id)
            else:
                self.fail("No assignment called '%s' exists in the database", assignment_id)
        else:
            # check if there are any extra notebooks in the db that are no longer
            # part of the assignment, and if so, remove them
            if self.notebook_id == "*":
                self._clean_old_notebooks(assignment_id, student_id)
Ejemplo n.º 38
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.student_id = resources['nbgrader']['student']
        self.db_url = resources['nbgrader']['db_url']

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        # process the cells
        nb, resources = super(GetGrades, self).preprocess(nb, resources)

        submission = self.gradebook.find_submission_notebook(
            self.notebook_id, self.assignment_id, self.student_id)
        resources['nbgrader']['score'] = submission.score
        resources['nbgrader']['max_score'] = submission.max_score

        return nb, resources
Ejemplo n.º 39
0
 def get_section_scores(self):
     """Return student score for each problem in notebook"""
     grades = []
     nb_name = os.path.splitext(self.nb_filename)[0]
     with Gradebook(self.db_path) as gb:
         nb = gb.find_submission_notebook(nb_name, self.pset_id,
                                          self.username)
         for problem in nb.grades:
             grades.append(problem.to_dict())
     return grades
Ejemplo n.º 40
0
def GetAssignmentList():
    assignment_list = []
    with Gradebook('sqlite:///test/gradebook.db') as gb:
        for assignment in gb.assignments:
            temp_dict = {}
            temp_dict["assignment"] = assignment.name
            temp_dict["problem"] = []
            for notebook in assignment.notebooks:
                temp_dict["problem"].append(notebook.name)
            assignment_list.append(temp_dict)
    return jsonify(assignment_list)
Ejemplo n.º 41
0
    def export(self, gradebook: Gradebook) -> None:
        """Creates a CSV file from nbgrader's gradebook.

        Args:
            gradebook (Gradebook): an nbgrader gradebook instance.
        """
        if self.canvas_export == "":
            dest = "canvas_grades.csv"
        else:
            dest = self.to

        if self.canvas_import == "":
            canvas_import = "canvas.csv"
        else:
            canvas_import = self.canvas_import

        self.log.info("Exporting grades to %s", dest)

        with open(canvas_import, "r") as csv_file, open(dest, "w") as op_csv_file:
            csv_reader = csv.DictReader(csv_file)
            fields = csv_reader.fieldnames
            csv_writer = csv.DictWriter(op_csv_file, fields)
            csv_writer.writeheader()
            for row in csv_reader:
                if "Points Possible" in row["Student"]:
                    self.log.info("Skipping second row")
                    csv_writer.writerow(row)
                    continue
                self.log.info("Finding student with ID %s", row["ID"])
                for column in fields:
                    if " (" not in column:
                        continue
                    assignment_name = column.split(" (")[0]
                    self.log.info(
                        "Finding submission of Student '%s' for Assignment '%s'",
                        row["ID"],
                        assignment_name,
                    )
                    submission = None
                    try:
                        submission = gradebook.find_submission(
                            assignment_name, row["ID"]
                        )
                        row[column] = max(
                            0.0, submission.score - submission.late_submission_penalty
                        )
                    except MissingEntry:
                        self.log.info(
                            "Submission of Student '%s' for Assignment '%s' not found",
                            row["ID"],
                            assignment_name,
                        )
                        continue
                csv_writer.writerow(row)
Ejemplo n.º 42
0
def extractGrades(gradebookDB, section, labNo):
    '''
    Open the specified grade database and return grades.

    Input:
        filename    str

    Output:
        grades      dict
    '''
    import sys

    from nbgrader.api import Gradebook
    gb = Gradebook(gradebookDB)
    #gb = Gradebook( f'sqlite:////class/cs101/etc/sxns/{section}/gradebook.db')

    grades = {}
    for s in gb.assignment_submissions("lab" + labNo):
        grades[s.student_id] = float(s.score)
    return grades
Ejemplo n.º 43
0
def test_update_or_create_solution_cell(gradebook: Gradebook) -> None:
    # first test creating it
    gradebook.add_assignment('foo')
    gradebook.add_notebook('p1', 'foo')
    sc1 = gradebook.update_or_create_solution_cell('test1', 'p1', 'foo')
    assert gradebook.find_solution_cell('test1', 'p1', 'foo') == sc1

    # now test finding/updating it
    sc2 = gradebook.update_or_create_solution_cell('test1', 'p1', 'foo')
    assert sc1 == sc2
Ejemplo n.º 44
0
    def preprocess(self, nb, resources):
        # pull information from the resources
        self.notebook_id = resources['nbgrader']['notebook']
        self.assignment_id = resources['nbgrader']['assignment']
        self.db_url = resources['nbgrader']['db_url']

        # connect to the database
        self.gradebook = Gradebook(self.db_url)

        nb, resources = super(OverwriteCells, self).preprocess(nb, resources)

        return nb, resources
Ejemplo n.º 45
0
    def test_grade(self):
        """Can files be graded?"""
        with self._temp_cwd(["files/submitted-unchanged.ipynb", "files/submitted-changed.ipynb"]):
            dbpath = self._setup_db()

            os.makedirs('source/ps1')
            shutil.copy('submitted-unchanged.ipynb', 'source/ps1/p1.ipynb')
            self._run_command('nbgrader assign ps1 --db="{}" '.format(dbpath))

            os.makedirs('submitted/foo/ps1')
            shutil.move('submitted-unchanged.ipynb', 'submitted/foo/ps1/p1.ipynb')
            os.makedirs('submitted/bar/ps1')
            shutil.move('submitted-changed.ipynb', 'submitted/bar/ps1/p1.ipynb')
            self._run_command('nbgrader autograde ps1 --db="{}"'.format(dbpath))

            assert os.path.isfile("autograded/foo/ps1/p1.ipynb")
            assert not os.path.isfile("autograded/foo/ps1/timestamp.txt")
            assert os.path.isfile("autograded/bar/ps1/p1.ipynb")
            assert not os.path.isfile("autograded/bar/ps1/timestamp.txt")

            gb = Gradebook(dbpath)
            notebook = gb.find_submission_notebook("p1", "ps1", "foo")
            assert_equal(notebook.score, 1)
            assert_equal(notebook.max_score, 4)
            assert_equal(notebook.needs_manual_grade, False)

            comment1 = gb.find_comment(0, "p1", "ps1", "foo")
            comment2 = gb.find_comment(1, "p1", "ps1", "foo")
            assert_equal(comment1.comment, "No response.")
            assert_equal(comment2.comment, "No response.")

            notebook = gb.find_submission_notebook("p1", "ps1", "bar")
            assert_equal(notebook.score, 2)
            assert_equal(notebook.max_score, 4)
            assert_equal(notebook.needs_manual_grade, True)

            comment1 = gb.find_comment(0, "p1", "ps1", "bar")
            comment2 = gb.find_comment(1, "p1", "ps1", "bar")
            assert_equal(comment1.comment, None)
            assert_equal(comment2.comment, None)
Ejemplo n.º 46
0
def class_files(request, tempdir):
    # copy files from the user guide
    source_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "docs", "source", "user_guide", "source")
    shutil.copytree(os.path.join(os.path.dirname(__file__), source_path), "source")

    # create a fake ps1
    os.mkdir(os.path.join("source", "ps1"))
    with open(os.path.join("source", "ps1", "problem 1.ipynb"), "w") as fh:
        write_nb(new_notebook(), fh, 4)

    # create the gradebook
    gb = Gradebook("sqlite:///gradebook.db")
    gb.add_assignment("Problem Set 1")
    gb.add_assignment("ps1")
    gb.add_student("Bitdiddle", first_name="Ben", last_name="B")
    gb.add_student("Hacker", first_name="Alyssa", last_name="H")
    gb.add_student("Reasoner", first_name="Louis", last_name="R")

    return tempdir