def getSubmissions(self): submissions = dict() files = os.listdir(self.config.dir_assignments) for f in files: if f in self.config.blacklist: logMsg(self.config, "Ignoring {0}, is in blacklist".format(f)) continue #TODO parse out the student comments for the selected file if f == "index.html": continue si = f.split('-') print(si) student = studentHelper(si[0] + si[1], si[2].strip().split(' ')[0], si[2].strip().split(' ')[1]) date = fixUpDate(si[3]).strip() # Check if the student submitted multiple files, take the one with # the newest date if student.sid in submissions: oldEntry = datetime.strptime(submissions[student.sid].date, '%b %d, %Y %I%M %p') newEntry = datetime.strptime(date, '%b %d, %Y %I%M %p') if oldEntry > newEntry: continue #TODO parse d2l html file for student comments and add them here submission = submissionHelper( student, date, self.config.dir_assignments + '/' + f, "", "", self.config.max_points, 0) submissions[student.sid] = submission return submissions
def d2lEp(config): d2ltools = d2lHelper(config) if not d2ltools.assignmentsExist(): quit() if config.noGrade: d2ltools.generateFeedback() d2ltools.generateGrades() quit() logMsg(config, "Getting list of submissions") submissions = d2ltools.getSubmissions() logMsg(config, "Unzipping all submissions") d2ltools.unzip(submissions) logMsg(config, "Getting unit tests for assignment") unitTests = getUnitTests(config) logMsg(config, "Preparing to run tests on submissions") runTests(submissions, unitTests, config) logMsg(config, "Cleaning up working folder") shutil.rmtree(config.workingFolder) d2ltools.generateFeedback() d2ltools.generateGrades()
def unzip(self, submissions): if not os.path.isdir(self.config.workingFolder): os.makedirs(self.config.workingFolder) for sid, sub in submissions.items(): try: zf = zipfile.ZipFile(sub.path) zi = zf.infolist() # make unique outer folder unzippedFolder = self.config.workingFolder + '/' + sid if not os.path.isdir(unzippedFolder): os.makedirs(unzippedFolder) zf.extractall(unzippedFolder) # check to see if the student zipped a directory with code or # just zipped the files together if zi[0].is_dir(): sub.workingPath = unzippedFolder + '/' + zi[0].filename else: sub.workingPath = unzippedFolder except zipfile.BadZipfile: logMsg( self.config, "ERROR: bad zip file {0}".format(submissions[sid].path)) except zipfile.LargeZipFile: logMsg(self.config, "ERROR: need zip64 {0}".format(submissions[sid].path))
def removeAssignment(config, aid, r_ut): dir_list = [config.dir_submissions, config.dir_output, config.dir_tests] for d in dir_list: if d == config.dir_tests and r_ut[0] != 'y': continue folder = d + '/' + aid logMsg(config, "Removing folder at {0}".format(folder)) if os.path.isdir(folder): shutil.rmtree(folder)
def assignmentsExist(self): # Check if the submissions are in the submissions director if not os.path.exists(self.config.dir_assignments): logMsg(self.config,"ERROR: {0} does not exists, can't grade whats not there :(".\ format(self.config.dir_assignments)) return False # Check if there are folders in the directory if len([f for f in os.listdir(self.config.dir_assignments)\ if os.path.isfile(os.path.join(self.config.dir_assignments, f))]) < 1: logMsg(self.config, "ERROR: {0} is empty, can't grade whats not there :(".\ format(self.config.dir_assignments)) return False return True
def createAssignment(config, aid): dir_list = [config.dir_submissions, config.dir_output, config.dir_tests] for d in dir_list: folder = d + '/' + aid logMsg(config, "Making folder at {0}".format(folder)) if not os.path.isdir(folder): os.makedirs(folder) # the test folder requires a few extra steps if d == config.dir_tests: ut_files = os.listdir(d + '/template') for file_name in ut_files: full_file_name = os.path.join(d + '/template', file_name) if (os.path.isfile(full_file_name)): shutil.copy(full_file_name, folder)
def printResults(submissions, config): for sid, sub in submissions.items(): logMsg( config, "Results for {0} - {1}".format( sid, sub.student.fName + " " + sub.student.lName)) logMsg( config, "Total score: {0} of {1} possible".format(sub.totalPoints, sub.maxPoints)) logMsg(config, "Individual test results") for r in sub.results: msg = "\tTest: {0}\n\tPassed: {1}\n\tPoints: {2} of {3}\n\tComments: {4}\n"\ .format(r.name, str(r.passed), r.points, r.maxPoints, r.comments) logMsg(config, msg)
help="generate feedback and grade files", action='store_true') parser.add_argument('-ng','--nograde', help="do not automatically grade assignments"\ "can be used with -g to generate grades and feedback after manually adjusting"\ "grades and feedback", action='store_true') args = parser.parse_args() # Save the assignment id that is to be graded if args.aid: config = gbconfig(args.aid) else: config = gbconfig() # set up logging configureLogging(config) logMsg(config, "***********************************************************") logMsg(config, "-- GRADEBOT STARTING --") # Make sure the correct flags are used together if (args.dataprovider and not args.aid)\ or (args.aid and not args.dataprovider): print("Data provider and assignment are both required together") quit() # Parse the data provider and set the correction option in the config if args.dataprovider == "d2l": logMsg(config, "Selected D2l as the data provider") config.dataProvider = dataProvider.D2L elif args.dataprovider == "bb": logMsg(config, "Selected BitBucket as the data provider") config.dataProvider = dataProvider.BITBUCKET
def run(self, submission): logMsg(self.config, "Running unit test: " + self.name) return self.result