def _possible_correct_naming(self, file_name, student_names, problems, correct_file_name_end): for student_name in file_name.split("_"): parts = re.findall(r'[A-Z](?:[a-zöäüß]+|[A-Z]*(?=[A-Z]|$))', student_name) if len(parts) > 0: student_name = ("-".join(parts)) student_name = student_name.split("-") student_name = " ".join(student_name) if len(student_name) > 0: student_names.append(student_name) students = list() needed_manual_help = False for student_name in student_names: if any(char.isdigit() for char in student_name): if self.printer.ask(f"Is '{student_name}' really a student name? (y/n)?") != 'y': self.printer.inform("Skip") continue student = select_student_by_name(student_name, self._storage, self.printer, students.append, mode='my') if student is None: self.printer.error(f"Some error happened processing '{file_name}'") self.printer.error(f"Did not find a match for '{student_name}'") self.printer.error("Increasing scope ... ") student = select_student_by_name(student_name, self._storage, self.printer, students.append, mode='all') if student is not None: self.printer.inform(f"Found the student - consider to import '{student_name}'") else: needed_manual_help = True student = self._manual_student_selection() if student is not None: students.append(student) else: self.printer.error("Manual correction failed!") student_names = [] def to_name(s): if type(s) == str: return s else: return s.muesli_name for student_name in sorted([to_name(student) for student in students]): name_parts = [_ for _ in student_name.split() if len(_) > 0 and '.' not in _] student_names.append(f'{name_parts[0].replace("-", "")}-{name_parts[-1].replace("-", "")}') if len(student_names) < 2: problems.append("Submission groups should consist at least of 2 members!") if 3 < len(student_names): problems.append("Submission groups should consist at most of 3 members!") result = '_'.join(student_names) + correct_file_name_end if needed_manual_help: problems.append( f"Please use the correct file format! For this submission it would have been '{result}.zip'" ) return result
def __call__(self, *args): if not self._storage.muesli_data.presentation.supports_presentations: self.printer.error( "Presenting is not supported. Please change config.json if you want to enable it." ) else: name = args[0] select_student_by_name(name, self._storage, self.printer, self._update_presented_in_muesli, mode='my')
def __call__(self, *args): if not self._storage.muesli_data.presentation.supports_presentations: self.printer.error( "Presenting is not supported. Please change config.json if you want to enable it." ) else: name = args[0] student = select_student_by_name(name, self._storage, self.printer, mode='my') if student is None: self.printer.warning(f"Student {name} could not be found.") else: success, update_count = self._muesli. \ updated_presented(self.printer, self._storage.muesli_data.presentation.name, [student]) if success: self.printer.confirm(f"MÜSLI: {student} has presented") self._storage.set_presented_for(student) else: self.printer.error( "MÜSLI: Some error occurred. Please check connection state." )
def _identify_students(self, name_part): self._printer.inform(f"Finding students in '{self._file_name}'.") student_names = [] for student_name in name_part.split("__"): student_name = student_name.replace("_", " ") if len(student_name) > 0: student_names.append(student_name) for student_name in student_names: if any(char.isdigit() for char in student_name): if self.ask_retry( f"Is '{student_name}' really a student name? (y/n)?", f"'{student_name}' could not be interpreted as a student name." ) != 'y': self._printer.inform("Skip") continue # Try to find student student = select_student_by_name(student_name, self._storage, self._printer, mode='all') # Look up matches in previous sheets if student is None and student_name in self._storage.student_name_matches: student = self._storage.student_name_matches[student_name] if student is None: student = self._manual_single_student(student_name) # Store this match so that no manual correction is needed in the future self._storage.add_student_name_match(student_name, student) self.students.append(student)
def __call__(self, *args, **kwargs): value = args[0] student = select_student_by_name(value, self._storage, self.printer, self._storage.export_student, mode='my') if student is not None: tutorial = self._storage.get_tutorial_by_id(student.tutorial_id) self.printer.inform( f"The student '{student}' from {tutorial.time} was exported.") self.printer.inform(f"Workflow commands will ignore this student.")
def __call__(self, *args, **kwargs): value = args[0] student = select_student_by_name(value, self._storage, self.printer, self._storage.import_student, mode='other') if student is not None: tutorial = self._storage.get_tutorial_by_id(student.tutorial_id) self.printer.inform( f"The student '{student}' from {tutorial.time} was imported.") self.printer.inform( f"Workflow commands will also consider this student now as your own." )
def __call__(self, *args, **kwargs): value = args[0] student = select_student_by_name(value, self._storage, self.printer, mode='my') if student is not None: self._storage.export_student(student) tutorial = self._storage.get_tutorial_by_id(student.tutorial_id) self.printer.inform( f"The student '{student}' from {tutorial.time} was deregistered from your group." ) self.printer.inform(f"Workflow commands will ignore this student.") else: self.printer.warning(f"Student {value} could not be found")
def __call__(self, *args, **kwargs): value = args[0] student = select_student_by_name(value, self._storage, self.printer, mode='other') if student is not None: self._storage.import_student(student) tutorial = self._storage.get_tutorial_by_id(student.tutorial_id) self.printer.inform( f"The student '{student}' from {tutorial.time} was registered as your student." ) self.printer.inform( f"Workflow commands will also consider this student now as your own." ) else: self.printer.warning(f"Student {value} could not be found.")
def _identify_students(self, name_part): self._printer.inform(f"Finding students in '{self._file_name}'.") student_names = [] for student_name in name_part.split("_"): parts = re.findall(r'[A-Z](?:[a-zöäüß]+|[A-Z]*(?=[A-Z]|$))', student_name) if len(parts) > 0: student_name = ("-".join(parts)) student_name = student_name.split("-") student_name = " ".join(student_name) if len(student_name) > 0: student_names.append(student_name) for student_name in student_names: if any(char.isdigit() for char in student_name): if self.ask_retry( f"Is '{student_name}' really a student name? (y/n)?", f"'{student_name}' could not be interpreted as a student name." ) != 'y': self._printer.inform("Skip") continue # Try to find student student = select_student_by_name(student_name, self._storage, self._printer, mode='all') if student is None: student = self._manual_single_student(student_name) if student is None: self._printer.error( "Manual correction failed! Ignoring student.") if student is not None: self.students.append(student)
def __call__(self, present_name): folder = Path(self._storage.get_presented_folder(present_name)) if not folder.is_dir(): folder.mkdir(parents=True) names = {} names_file = folder / "names.json" if names_file.is_file(): with open(names_file, "r") as fp: names = { name: self._storage.get_student_by_muesli_id(muesli_id) for name, muesli_id in load(fp).items() } if len(names) > 0: self.printer.warning( f"{len(names)} names were already parsed.") self.printer.inform("You have the following options:") self.printer.indent() self.printer.inform("a) Restart from scratch,") self.printer.inform("b) Keep existing names and add any new,") self.printer.inform("c) Abort.") self.printer.outdent() while True: answer = self.printer.ask( "Please choose an option (a/b/c):") if answer in "abc": if answer == "a": names = {} elif answer == "b": pass elif answer == "c": return break self.printer.inform("Please put .txt files with the students' names " f"into {folder}.") self.printer.indent() for name_file in folder.glob("*.txt"): self.printer.inform(f"- Found: {name_file.name}") self.printer.outdent() self.printer.inform("You can now put additional files in the folder, " "then hit enter.") self.printer.ask("") name_files = sorted(folder.glob("*.txt")) names_by_file = {} for name_file in name_files: name_file_names = set() with open(name_file, "r") as fp: for line in fp: line = line.strip() if len(line) > 0: name_file_names.add(line) names_by_file[name_file.name] = name_file_names present_all_files = set.intersection(*names_by_file.values()) present_any_file = set.union(*names_by_file.values()) self.printer.confirm(f"Found a total of {len(present_any_file)} names " f"in {len(name_files)} files.") reference_names = None self.printer.indent() for name_file, name_file_names in names_by_file.items(): if reference_names is None: self.printer.inform(f"{name_file}: {len(name_file_names)}") else: new_students = name_file_names - reference_names gone_students = reference_names - name_file_names self.printer.inform(f"{name_file}: {len(name_file_names)} " f"(+{len(new_students)}, " f"-{len(gone_students)})") reference_names = name_file_names self.printer.inform(f"{len(present_all_files)} present in all files.") self.printer.outdent() for name in sorted(present_any_file, key=str.casefold): student = select_student_by_name(name, self._storage, self.printer) if student is None and name in self._storage.student_name_matches: student = self._storage.student_name_matches[name] self.printer.inform(f"Loaded '{name}' -> {student} from " f"previous manual choice.") if student is None: self.printer.warning("Manual correction needed! Who is " f"'{name}'?") self.printer.inform(f"Please enter a new name or type '-':") while True: answer = self.printer.ask("Alternative name: ") if answer == "-": self.printer.warning(f"Ignoring '{name}'.") break student = select_student_by_name(answer, self._storage, self.printer) if student is None: self.printer.warning( f"Could not find student '{answer}'. Please " f"try again or type '-'. Who is '{name}'?") else: self.printer.confirm(f"{name} is {student}.") self._storage.add_student_name_match(name, student) break if student is not None: names[name] = student with open(names_file, "w") as fp: dump( { name: student.muesli_student_id for name, student in names.items() }, fp) self._storage.save_student_name_matches() self.printer.confirm(f"Stored {len(names)} names.") yes_students = list(names.values()) self.printer.inform("Saving to Muesli …") with self._muesli: self._muesli.updated_presented(present_name, self.printer, yes_students) self.printer.confirm("Saved to Muesli.") all_students = self._storage.get_all_students_of_tutorial( yes_students[0].tutorial_id) no_students = [ student for student in all_students if student not in yes_students ] if self.printer.yes_no( f"Grade remaining {len(no_students)} students " f"with zero points?"): self.printer.inform("Saving to Muesli …") self._muesli.updated_presented(present_name, self.printer, no_students, value=0) self.printer.confirm("Saved to Muesli.")