def init_dest(self): if self.coursedir.course_id == '': self.fail("No course id specified. Re-run with --course flag.") if not self.authenticator.has_access(self.coursedir.student_id, self.coursedir.course_id): self.fail("You do not have access to this course.") self.inbound_path = os.path.join(self.root, self.coursedir.course_id, 'inbound') if not os.path.isdir(self.inbound_path): self.fail("Inbound directory doesn't exist: {}".format(self.inbound_path)) if not check_mode(self.inbound_path, write=True, execute=True): self.fail("You don't have write permissions to the directory: {}".format(self.inbound_path)) self.cache_path = os.path.join(self.cache, self.coursedir.course_id) if self.coursedir.student_id != '*': # An explicit student id has been specified on the command line; we use it as student_id if '*' in self.coursedir.student_id or '+' in self.coursedir.student_id: self.fail("The student ID should contain no '*' nor '+'; got {}".format(self.coursedir.student_id)) student_id = self.coursedir.student_id else: student_id = get_username() if self.add_random_string: random_str = base64.urlsafe_b64encode(os.urandom(9)).decode('ascii') self.assignment_filename = '{}+{}+{}+{}'.format( student_id, self.coursedir.assignment_id, self.timestamp, random_str) else: self.assignment_filename = '{}+{}+{}'.format( student_id, self.coursedir.assignment_id, self.timestamp)
def init_dest(self): self.course_path = os.path.join(self.exchange_directory, self.course_id) self.inbound_path = os.path.join(self.course_path, 'inbound') self.assignment_filename = get_username() + '+' + self.assignment_id + '+' + self.timestamp self.dest_path = os.path.join(self.inbound_path, self.assignment_filename) if not os.path.isdir(self.inbound_path): self.fail("Inbound directory doesn't exist: {}".format(self.inbound_path)) if not check_mode(self.inbound_path, write=True, execute=True): self.fail("You don't have write permissions to the directory: {}".format(self.inbound_path))
def init_dest(self): if self.course_id == '': self.fail("No course id specified. Re-run with --course flag.") self.inbound_path = os.path.join(self.exchange_directory, self.course_id, 'inbound') if not os.path.isdir(self.inbound_path): self.fail("Inbound directory doesn't exist: {}".format(self.inbound_path)) if not check_mode(self.inbound_path, write=True, execute=True): self.fail("You don't have write permissions to the directory: {}".format(self.inbound_path)) self.cache_path = os.path.join(self.cache_directory, self.course_id) self.assignment_filename = '{}+{}+{}'.format(get_username(), self.assignment_id, self.timestamp)
def init_dest(self): if self.coursedir.course_id == "": self.fail("No course id specified. Re-run with --course flag.") if not self.authenticator.has_access( self.coursedir.student_id, self.coursedir.course_id ): self.fail("You do not have access to this course.") self.inbound_path = os.path.join( self.root, self.coursedir.course_id, self.inbound_directory ) if self.personalized_inbound: self.inbound_path = os.path.join( self.inbound_path, os.getenv("JUPYTERHUB_USER") ) if not os.path.isdir(self.inbound_path): self.log.warning( "Inbound directory doesn't exist, creating {}".format( self.inbound_path ) ) # 0777 with set GID so student instructors can read students' submissions self.ensure_directory( self.inbound_path, S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | (S_IRGRP if self.coursedir.groupshared else 0), ) if not os.path.isdir(self.inbound_path): self.fail("Inbound directory doesn't exist: {}".format(self.inbound_path)) if not check_mode(self.inbound_path, write=True, execute=True): self.fail( "You don't have write permissions to the directory: {}".format( self.inbound_path ) ) self.cache_path = os.path.join(self.cache, self.coursedir.course_id) if self.coursedir.student_id != "*": # An explicit student id has been specified on the command line; we use it as student_id if "*" in self.coursedir.student_id or "+" in self.coursedir.student_id: self.fail( "The student ID should contain no '*' nor '+'; got {}".format( self.coursedir.student_id ) ) student_id = self.coursedir.student_id else: student_id = get_username() if self.add_random_string: random_str = base64.urlsafe_b64encode(os.urandom(9)).decode("ascii") self.assignment_filename = "{}+{}+{}+{}".format( student_id, self.coursedir.assignment_id, self.timestamp, random_str ) else: self.assignment_filename = "{}+{}+{}".format( student_id, self.coursedir.assignment_id, self.timestamp )
def copy_files(self): self.init_release() hashcode = "No hashcode present" # Original notebook file student_notebook_file = os.path.join( self.src_path, f"{self.coursedir.assignment_id}.ipynb" ) if os.path.isfile(student_notebook_file): nb = nbformat.read(student_notebook_file, as_version=4) nb = append_timestamp(nb, self.timestamp) nbformat.write(nb, student_notebook_file) hashcode = truncate_hashcode( compute_hashcode(student_notebook_file, method="sha1") ) username = get_username() generate_student_info( os.path.join(self.src_path, f"{username}_info.txt"), username, hashcode, self.timestamp, ) nb = append_hashcode(nb, hashcode) generate_html( nb, os.path.join( self.src_path, f"{self.coursedir.assignment_id}_hashcode.html" ), ) else: self.log.warning( "Can not generate hashcode, notebook and assignment name does not match." ) dest_path = os.path.join(self.inbound_path, self.assignment_filename) if self.add_random_string: cache_path = os.path.join( self.cache_path, self.assignment_filename.rsplit("+", 1)[0] ) else: cache_path = os.path.join(self.cache_path, self.assignment_filename) self.log.info("Source: {}".format(self.src_path)) self.log.info("Destination: {}".format(dest_path)) # copy to the real location self.check_filename_diff() self.do_copy(self.src_path, dest_path) with open(os.path.join(dest_path, "timestamp.txt"), "w") as fh: fh.write(self.timestamp) self.set_perms( dest_path, fileperms=(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), dirperms=( S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ), ) # Make this 0777=ugo=rwx so the instructor can delete later. Hidden from other users by the timestamp. os.chmod( dest_path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH, ) # also copy to the cache if not os.path.isdir(self.cache_path): os.makedirs(self.cache_path) self.do_copy(self.src_path, cache_path) with open(os.path.join(cache_path, "timestamp.txt"), "w") as fh: fh.write(self.timestamp) self.log.info( "Submitted as: {} {} {}".format( self.coursedir.course_id, self.coursedir.assignment_id, str(self.timestamp), ) ) return hashcode, self.timestamp
def init_src(self): if self.coursedir.course_id == "": self.fail("No course id specified. Re-run with --course flag.") self.course_path = os.path.join(self.root, self.coursedir.course_id) self.outbound_path = os.path.join(self.course_path, self.feedback_directory) self.src_path = os.path.join(self.outbound_path) self.cache_path = os.path.join(self.cache, self.coursedir.course_id) if self.coursedir.student_id != "*": # An explicit student id has been specified on the command line; we use it as student_id if "*" in self.coursedir.student_id or "+" in self.coursedir.student_id: self.fail( "The student ID should contain no '*' nor '+'; got {}". format(self.coursedir.student_id)) student_id = self.coursedir.student_id else: student_id = get_username() if not os.path.isdir(self.src_path): self._assignment_not_found(self.src_path, os.path.join(self.outbound_path, "*")) if not check_mode(self.src_path, execute=True): self.fail( "You don't have execute permissions for the directory: {}". format(self.src_path)) assignment_id = (self.coursedir.assignment_id if self.coursedir.assignment_id else "*") pattern = os.path.join(self.cache_path, "*+{}+*".format(assignment_id)) self.log.debug( "Looking for submissions with pattern: {}".format(pattern)) self.feedback_files = [] submissions = [os.path.split(x)[-1] for x in glob.glob(pattern)] for submission in submissions: _, assignment_id, timestamp = submission.split("/")[-1].split("+") self.log.debug( "Looking for feedback for '{}/{}' submitted at {}".format( self.coursedir.course_id, assignment_id, timestamp)) pattern = os.path.join(self.cache_path, submission, "*.ipynb") notebooks = glob.glob(pattern) for notebook in notebooks: notebook_id = os.path.splitext(os.path.split(notebook)[-1])[0] # Check if personalized_feedback is used if self.personalized_feedback: feedbackpath = os.path.join( self.outbound_path, student_id, assignment_id, "{}.html".format(notebook_id), ) self.log.debug("Feedback file: ", feedbackpath) if os.path.exists(feedbackpath): self.feedback_files.append( (notebook_id, timestamp, feedbackpath)) self.log.info( "Found feedback for '{}/{}/{}' submitted at {}". format( self.coursedir.course_id, assignment_id, notebook_id, timestamp, )) continue # If we reached here, then there's no feedback available self.log.warning( "Could not find feedback for '{}/{}/{}' submitted at {}" .format( self.coursedir.course_id, assignment_id, notebook_id, timestamp, )) else: unique_key = make_unique_key( self.coursedir.course_id, assignment_id, notebook_id, student_id, timestamp, ) # Look for the feedback using new-style of feedback self.log.debug("Unique key is: {}".format(unique_key)) nb_hash = notebook_hash(notebook, unique_key) feedbackpath = os.path.join(self.outbound_path, "{0}.html".format(nb_hash)) if os.path.exists(feedbackpath): self.feedback_files.append( (notebook_id, timestamp, feedbackpath)) self.log.info( "Found feedback for '{}/{}/{}' submitted at {}". format( self.coursedir.course_id, assignment_id, notebook_id, timestamp, )) continue # If it doesn't exist, try the legacy hashing nb_hash = notebook_hash(notebook) feedbackpath = os.path.join(self.outbound_path, "{0}.html".format(nb_hash)) if os.path.exists(feedbackpath): self.feedback_files.append( (notebook_id, timestamp, feedbackpath)) self.log.warning( "Found legacy feedback for '{}/{}/{}' submitted at {}" .format( self.coursedir.course_id, assignment_id, notebook_id, timestamp, )) continue # If we reached here, then there's no feedback available self.log.warning( "Could not find feedback for '{}/{}/{}' submitted at {}" .format( self.coursedir.course_id, assignment_id, notebook_id, timestamp, ))
from nbgrader.utils import get_username c = get_config() c.NbGrader.course_id = "demo" c.NbGrader.db_assignments = [dict(name="ps1")] c.NbGrader.db_students = [dict(id=get_username())]