Ejemplo n.º 1
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.º 2
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.º 3
0
    async def add_user_to_nbgrader_gradebook(
            self, course_id: str, username: str,
            lms_user_id: str) -> Awaitable['HTTPResponse']:
        """
        Adds a user to the nbgrader gradebook database for the course.

        Args:
            course_id: The normalized string which represents the course label.
            username: The user's username
        Raises:
            InvalidEntry: when there was an error adding the user to the database
        """
        if not course_id:
            raise ValueError('course_id missing')
        if not username:
            raise ValueError('username missing')
        if not lms_user_id:
            raise ValueError('lms_user_id missing')
        grader_name = f'grader-{course_id}'
        db_url = Path('/home', grader_name, course_id, 'gradebook.db')
        db_url.parent.mkdir(exist_ok=True, parents=True)
        self.log.debug('Database url path is %s' % db_url)
        if not db_url.exists():
            self.log.debug('Gradebook database file does not exist')
            return
        gradebook = Gradebook(f'sqlite:///{db_url}', course_id=course_id)
        try:
            gradebook.update_or_create_student(username,
                                               lms_user_id=lms_user_id)
            self.log.debug('Added user %s with lms_user_id %s to gradebook' %
                           (username, lms_user_id))
        except InvalidEntry as e:
            self.log.debug('Error during adding student to gradebook: %s' % e)
        gradebook.close()
Ejemplo n.º 4
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.º 5
0
    def submit_autograding(self, docker):
        # create the autograded assignment file path
        self.autograded_assignment_path = os.path.join(self.grader_repo_path, self.grader_local_autograded_folder)
        self.autograde_fail_flag_path = os.path.join(self.grader_repo_path, 'autograde_failed_'+self.asgn.name+'-'+self.stu.canvas_id)

        print('Autograding submission ' + self.asgn.name+':'+self.stu.canvas_id)

        if os.path.exists(self.autograde_fail_flag_path):
            print('Autograde failed previously. Returning')
            return SubmissionStatus.AUTOGRADE_FAILED_PREVIOUSLY

        if os.path.exists(self.autograded_assignment_path):
            print('Assignment previously autograded & validated.')
            return SubmissionStatus.AUTOGRADED
        else:
            print('Removing old autograding result from DB if it exists')
            try:
                gb = Gradebook('sqlite:///'+self.grader_repo_path +'/gradebook.db')
                gb.remove_submission(self.asgn.name, self.student_prefix+self.stu.canvas_id)
            except MissingEntry as e:
                pass
            finally:
                gb.close()
            print('Submitting job to docker pool for autograding')
            self.autograde_docker_job_id = docker.submit('nbgrader autograde --force --assignment=' + self.asgn.name + ' --student='+self.student_prefix+self.stu.canvas_id, self.grader_repo_path)
            return SubmissionStatus.NEEDS_AUTOGRADE
Ejemplo n.º 6
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
    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.º 8
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.º 9
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])
Ejemplo n.º 10
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.º 11
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.º 12
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.º 13
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.º 14
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.º 15
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.º 16
0
def del_nbgrader_user(user, course):
    print(f"del {user} from course {course}")
    home = get_home_dir(f"grader-{course}")
    course_dir = f"{home}/{course}"
    gradebook = Gradebook(f"sqlite:///{course_dir}/gradebook.db",
                          course_id=course)
    gradebook.remove_student(user)
    gradebook.close()
    for subdir in ("autograded", "feedback", "submitted"):
        os.system(f"rm -rf {course_dir}/{subdir}/{user}")
Ejemplo n.º 17
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.º 18
0
def add_nbgrader_user(user, first_name, last_name, course):
    print(f"add {user} ({last_name}, {first_name}) to course {course}")
    home = get_home_dir(f"grader-{course}")
    course_dir = f"{home}/{course}"
    gradebook = Gradebook(f"sqlite:///{course_dir}/gradebook.db",
                          course_id=course)
    gradebook.update_or_create_student(user,
                                       first_name=first_name,
                                       last_name=last_name)
    gradebook.close()
Ejemplo n.º 19
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)
    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.º 21
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.º 22
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.º 23
0
    def start(self):
        super(FormgradeApp, self).start()

        app.notebook_dir = self.base_directory
        app.notebook_dir_format = self.directory_format
        app.exporter = HTMLExporter(config=self.config)

        url = "http://{:s}:{:d}/".format(self.ip, self.port)
        self.log.info("Form grader running at {}".format(url))
        self.log.info("Use Control-C to stop this server")

        app.gradebook = Gradebook(self.db_name, ip=self.db_ip, port=self.db_port)
        app.run(host=self.ip, port=self.port, debug=True, use_reloader=False)
Ejemplo n.º 24
0
    def export(self, gradebook):
        # Create the connection to the database
        with Gradebook('sqlite:///gradebook.db') as gb:

            # Loop over each assignment in the database
            for assignment in gb.assignments:
                print("Exporting...")
                print("     Course-ID: " + assignment.course_id)
                print("     Assignment-Name: " + assignment.name)

                # Loop over each student in the database
                for student in gb.students:

                    # Check if file with lis-Parameters exists
                    path = ('/opt/tljh/exchange/' + assignment.course_id + ''
                            '/inbound/log/' + assignment.name + ''
                            '/' + student.id + '.txt')

                    if os.path.isfile(path):
                        print("         Student-ID: " + student.id)

                        # Get stored parameters from the file
                        parameters = {}
                        with open(path, 'r') as log:
                            lines = log.read().splitlines()
                            parameters = {
                                'lis_outcome_service_url': lines[0],
                                'lis_result_sourcedid': lines[1]
                            }

                        # Try to find the submission in the database. If it doesn't exist, the
                        # `MissingEntry` exception will be raised, which means the student
                        # didn't submit anything, so we assign them a score of zero.
                        try:
                            submission = gb.find_submission(
                                assignment.name, student.id)
                        except MissingEntry:
                            parameters['score'] = 0.0
                        else:
                            # Four digits shown in Moodle
                            resultscore = round(
                                submission.score / assignment.max_score, 4)
                            if resultscore > 1:
                                resultscore = 1
                            parameters['score'] = resultscore

                        self.post_grades(parameters)

                    else:
                        print("         No LTI-Parameters found for: " +
                              student.id)
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.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.º 26
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.º 27
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.º 28
0
    def test_add_extra_notebooks_with_submissions(self, db):
        """Is an error thrown when new notebooks are added and there are existing submissions?"""
        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

        gb.add_student("hacker123")
        gb.add_submission("ps1", "hacker123")

        self._copy_file("files/test.ipynb", "source/ps1/test2.ipynb")
        run_command(["nbgrader", "assign", "ps1", "--db", db, "--force"],
                    retcode=1)
Ejemplo n.º 29
0
    def __init__(self, db_url, **settings):
        if not settings.get('auth_token'):
            gen_log.info(
                'Auth token not set. Authentication will be disabled!')

        self.gradebook = Gradebook(db_url)

        handlers = [
            (r'/assignments', AssignmentHandler),
            (r'/assignments/(.*)', AssignmentDetailHandler),
        ]

        default_settings = dict(default_handler_class=NotFoundHandler, )

        default_settings.update(**settings)

        super(Application, self).__init__(handlers, **default_settings)
Ejemplo n.º 30
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