def collectSubmissionDirs(config, baseDir=None, includeBoth=False): if baseDir is None: baseDir = config.baseDir dirs1 = shell.ls(baseDir, config.submissionDirGlob) dirs2 = [] if includeBoth: dirs2 = shell.ls(config.baseDir, config.submissionDirTextGlob) result = [d for d in dirs1 + dirs2 if shell.isdir(d)] return sorted(result)
def findSubmissionDirForId(config, x): """ Returns the submission directory for a student with ID x. Prefers _file_ directory over _onlinetext_. """ dirs = [d for d in shell.ls(config.baseDir, f'*_{x}_*') if shell.isdir(d)] if len(dirs) == 0: return None for d in dirs: if d.endswith('_file_'): return d return dirs[0]
def withFilenames(config, what, action): submissionDirs = collectSubmissionDirs(config) for d in submissionDirs: student = shell.basename(d) verbose(f'{what} filenames for student {student}') for k, assList in config.assignmentsGroupedByKind.items(): ass = assList[0] files = set([ shell.basename(f) for f in shell.ls(d, ass.submissionFileGlob) ]) expected = set([ shell.basename(f) for a in assList if (f := a.getMainFile(student)) is not None ]) missing = expected - files superfluous = files - expected verbose( f'{what} filenames for student {student} and kind {k}. files={files}, expected={expected}, missing={missing}, superflous={superfluous}' ) action(student, k, d, missing, superfluous)
def checkFilenames(config): submissionDirs = collectSubmissionDirs(config) for d in submissionDirs: student = shell.basename(d) files = set([ shell.basename(f) for f in shell.ls(d, config.submissionFileGlob) ]) expected = set(config.assignments) missing = expected - files superfluous = files - expected if len(missing) > 0: if len(superfluous) > 0: warn( f'{student} misses assignments {missing} but has the following extra files: {superfluous}' ) else: verbose( f'{student} misses assignments {missing} and there are no extra files.' ) else: verbose(f'{student} has all assignments')
def fixFilenames(config): submissionDirs = collectSubmissionDirs(config) for d in submissionDirs: student = shell.basename(d) files = set([ shell.basename(f) for f in shell.ls(d, config.submissionFileGlob) ]) expected = set(config.assignments) missing = expected - files superfluous = files - expected for m in missing: candidates = [] for s in superfluous: if s.endswith(m) or len(superfluous) == 1: candidates.append(s) if len(candidates) > 1: print( f'Cannot fix name of assignment {m} for {student} because there is more than one matching file' ) elif len(candidates) == 1: c = candidates[0] # Windows shell.run(['mv', '-i', shell.pjoin(d, c), shell.pjoin(d, m)])
def assertExists(path): if not shell.isFile(path): d = shell.dirname(path) files = shell.ls(d, '*') abort(f'File {path} does not exist, existing files: {files}')
def fun(c): fixFilenames(c) studDir = shell.pjoin(c.baseDir, student) existingFiles = [shell.basename(p) for p in shell.ls(studDir)] self.assertEqual(sorted(expectedFiles), sorted(existingFiles))
def collectSubmissionFiles(config, d): files = shell.ls(d, config.submissionFileGlob) expected = set(config.assignments) return sorted([f for f in files if shell.basename(f) in expected])