122 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import glob
 | |
| import json
 | |
| import ntpath
 | |
| import os
 | |
| from typing import cast
 | |
| 
 | |
| from canvasapi.assignment import Assignment
 | |
| 
 | |
| from joint_teapot import Teapot, logger
 | |
| from joint_teapot.utils.main import default_repo_name_convertor, first, percentile
 | |
| 
 | |
| 
 | |
| class VE482Teapot(Teapot):
 | |
|     def p1_check(self) -> None:
 | |
|         fault_repos = []
 | |
|         for repo_name in self.gitea.get_all_repo_names():
 | |
|             if not repo_name.endswith("p1"):
 | |
|                 continue
 | |
|             faults = []
 | |
|             succeed = self.checkout_to_repo_by_release_name(repo_name, "p1")
 | |
|             if succeed:
 | |
|                 contain_c_file = False
 | |
|                 contain_readme_file = False
 | |
|                 for fn in glob.glob(f"{self.git.repos_dir}/{repo_name}/*"):
 | |
|                     basename = ntpath.basename(fn)
 | |
|                     if basename.endswith(".c"):
 | |
|                         contain_c_file = True
 | |
|                     if basename.lower().startswith("readme"):
 | |
|                         contain_readme_file = True
 | |
|                 if not contain_c_file:
 | |
|                     faults.append(
 | |
|                         "no C file found in root directory in release p1, "
 | |
|                         "can not compile on JOJ"
 | |
|                     )
 | |
|                 if not contain_readme_file:
 | |
|                     faults.append(
 | |
|                         "no README file found in root directory in release p1"
 | |
|                     )
 | |
|             else:
 | |
|                 faults.append("no release named p1")
 | |
|             if faults:
 | |
|                 fault_string = ""
 | |
|                 for fault in faults:
 | |
|                     fault_string += f"- {fault}\n"
 | |
|                 logger.info("\n".join(("", repo_name, "", fault_string)))
 | |
|                 self.gitea.issue_api.issue_create_issue(
 | |
|                     self.gitea.org_name,
 | |
|                     repo_name,
 | |
|                     body={
 | |
|                         "body": fault_string,
 | |
|                         "title": "p1 submission pre-check failed",
 | |
|                     },
 | |
|                 )
 | |
|                 fault_repos.append(repo_name)
 | |
|         logger.info(f"{len(fault_repos)} fault repo(s): {fault_repos}")
 | |
| 
 | |
|     def p1_submit(self) -> None:
 | |
|         res_dict = {}
 | |
|         assignment_name = "p1.3"
 | |
|         assignment = first(self.canvas.assignments, lambda x: x.name == assignment_name)
 | |
|         if assignment is None:
 | |
|             logger.info(f"Canvas assignment {assignment_name} not found")
 | |
|             return
 | |
|         assignment = cast(Assignment, assignment)
 | |
|         students = self.canvas.students
 | |
|         for submission in assignment.get_submissions():
 | |
|             student = first(students, lambda x: x.id == submission.user_id)
 | |
|             if student is None:
 | |
|                 continue
 | |
|             repo_name = default_repo_name_convertor(student) + "-p1"
 | |
|             repo_dir = os.path.join(self.git.repos_dir, repo_name)
 | |
|             base_score, base_url = self.joj.submit_dir(
 | |
|                 "https://joj.sjtu.edu.cn/d/ve482_fall_2021/p/61c2d0b27fe7290006b27034",
 | |
|                 repo_dir,
 | |
|                 "make",
 | |
|             )
 | |
|             bonus_score, bonus_url = self.joj.submit_dir(
 | |
|                 "https://joj.sjtu.edu.cn/d/ve482_fall_2021/p/61c2d49e7fe7290006b2703e",
 | |
|                 repo_dir,
 | |
|                 "make",
 | |
|             )
 | |
|             total_score = base_score / 520 * 100 + bonus_score / 220 * 30
 | |
|             res_dict[student.sis_login_id] = total_score
 | |
|             data = {
 | |
|                 "submission": {"posted_grade": round(total_score, 2)},
 | |
|                 "comment": {
 | |
|                     "text_comment": (
 | |
|                         f"base score: {base_score} / 520, url: {base_url}\n"
 | |
|                         f"bonus score: {bonus_score} / 220, url: {bonus_url}\n"
 | |
|                         f"total score: {base_score} / 520 * 100 + "
 | |
|                         f"{bonus_score} / 220 * 30"
 | |
|                     )
 | |
|                 },
 | |
|             }
 | |
|             submission.edit(**data)
 | |
|         float_grades = list(res_dict.values())
 | |
|         summary = [
 | |
|             min(float_grades),
 | |
|             percentile(float_grades, 0.25),
 | |
|             percentile(float_grades, 0.5),
 | |
|             percentile(float_grades, 0.75),
 | |
|             max(float_grades),
 | |
|         ]
 | |
|         average_grade = sum(float_grades) / len(float_grades)
 | |
|         logger.info(
 | |
|             f"Grades summary: "
 | |
|             f"Min: {summary[0]:.2f}, "
 | |
|             f"Q1: {summary[1]:.2f}, "
 | |
|             f"Q2: {summary[2]:.2f}, "
 | |
|             f"Q3: {summary[3]:.2f}, "
 | |
|             f"Max: {summary[4]:.2f}, "
 | |
|             f"Average: {average_grade:.2f}"
 | |
|         )
 | |
|         json.dump(
 | |
|             res_dict, open("ve482_p1_grade.json", "w"), ensure_ascii=False, indent=4
 | |
|         )
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     teapot = VE482Teapot()
 | |
|     teapot.p1_submit()
 |