예제 #1
0
 def _load_test_case_info(self):
     try:
         with open(os.path.join(self._test_case_dir, "info")) as f:
             return json.load(f)
     except IOError:
         raise JudgeClientError("Test case not found" + self._test_case_dir)
     except ValueError:
         raise JudgeClientError("Bad test case config")
예제 #2
0
 def load_judge_info(self, problem_id):
     try:
         with open(os.path.join(self.task_path, 'info.json')) as f:
             return json.load(f)
     except IOError:
         raise JudgeClientError("Test case not found: " + problem_id)
     except ValueError:
         raise JudgeClientError("Bad test case config")
예제 #3
0
    def __init__(self,
                 run_config,
                 exe_path,
                 max_cpu_time,
                 max_memory,
                 test_case_id,
                 submission_dir,
                 spj_version,
                 spj_config,
                 output=False):
        self._run_config = run_config
        self._exe_path = exe_path
        self._max_cpu_time = max_cpu_time
        self._max_memory = max_memory
        self._max_real_time = self._max_cpu_time * 3
        self._test_case_id = test_case_id
        self._test_case_dir = os.path.join(TEST_CASE_DIR, test_case_id)
        self._submission_dir = submission_dir

        self._pool = Pool(processes=psutil.cpu_count())
        self._test_case_info = self._load_test_case_info()

        self._spj_version = spj_version
        self._spj_config = spj_config
        self._output = output
        if self._spj_version and self._spj_config:
            self._spj_exe = os.path.join(
                SPJ_EXE_DIR, self._spj_config["exe_name"].format(
                    spj_version=self._spj_version))
            if not os.path.exists(self._spj_exe):
                raise JudgeClientError("spj exe not found")
예제 #4
0
 def __exit__(self, exc_type, exc_val, exc_tb):
     if not DEBUG:
         try:
             shutil.rmtree(self.path)
         except Exception as e:
             logger.exception(e)
             raise JudgeClientError("failed to clean runtime dir")
예제 #5
0
    def _judge_one(self, test_case_file_id):
        test_case_info = self._get_test_case_file_info(test_case_file_id)
        in_file = os.path.join(self._test_case_dir, test_case_info["input_name"])
        user_output_file = os.path.join(self._submission_dir, test_case_file_id + ".out")

        command = self._run_config["command"].format(exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path),
                                                     max_memory=int(self._max_memory / 1024)).split(" ")
        env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get("env", [])

        run_result = _judger.run(max_cpu_time=self._max_cpu_time,
                                 max_real_time=self._max_real_time,
                                 max_memory=self._max_memory,
                                 max_stack=128 * 1024 * 1024,
                                 max_output_size=max(test_case_info.get("output_size", 0) * 2, 1024 * 1024 * 16),
                                 max_process_number=_judger.UNLIMITED,
                                 exe_path=command[0],
                                 input_path=in_file,
                                 output_path=user_output_file,
                                 error_path=user_output_file,
                                 args=command[1::],
                                 env=env,
                                 log_path=JUDGER_RUN_LOG_PATH,
                                 seccomp_rule_name=self._run_config["seccomp_rule"],
                                 uid=RUN_USER_UID,
                                 gid=RUN_GROUP_GID,
                                 memory_limit_check_only=self._run_config.get("memory_limit_check_only", 0))
        run_result["test_case"] = test_case_file_id

        # if progress exited normally, then we should check output result
        run_result["output_md5"] = None
        run_result["output"] = None
        if run_result["result"] == _judger.RESULT_SUCCESS:
            if self._test_case_info.get("spj"):
                if not self._spj_config or not self._spj_version:
                    raise JudgeClientError("spj_config or spj_version not set")

                spj_result = self._spj(in_file_path=in_file, user_out_file_path=user_output_file)

                if spj_result == SPJ_WA:
                    run_result["result"] = _judger.RESULT_WRONG_ANSWER
                elif spj_result == SPJ_ERROR:
                    run_result["result"] = _judger.RESULT_SYSTEM_ERROR
                    run_result["error"] = _judger.ERROR_SPJ_ERROR
            else:
                run_result["output_md5"], is_ac, is_pe = self._compare_output(test_case_file_id)
                # -1 == Wrong Answer
                if not is_ac:
                    run_result["result"] = _judger.RESULT_WRONG_ANSWER
                if not is_ac and is_pe:
                    run_result["result"] = _judger.RESULT_PRESENTATION_ERROR

        if self._output:
            try:
                with open(user_output_file, "r", encoding="utf-8") as f:
                    run_result["output"] = f.read()
            except Exception:
                pass

        return run_result
예제 #6
0
파일: server.py 프로젝트: lvku/JudgeServer
 def __enter__(self):
     try:
         os.mkdir(self.path)
         os.chmod(self.path, 0o777)
     except Exception as e:
         logger.exception(e)
         raise JudgeClientError("failed to create runtime dir")
     return self.path
예제 #7
0
 def __exit__(self, exc_type, exc_val, exc_tb):
     if not DEBUG:
         try:
             shutil.rmtree(self.work_dir)  #remove temp files
             pass
         except Exception as e:
             logger.exception(e)
             raise JudgeClientError("failed to clean runtime dir")
예제 #8
0
 def __enter__(self):
     try:
         os.mkdir(self.path)
         os.chown(self.path, COMPILER_USER_UID, RUN_GROUP_GID)
         os.chmod(self.path, 0o711)
     except Exception as e:
         logger.exception(e)
         raise JudgeClientError("failed to create runtime dir")
     return self.path
예제 #9
0
 def __enter__(self):
     try:
         os.mkdir(self.work_dir)
         if self.init_test_case_dir:
             os.mkdir(self.test_case_dir)
         os.chown(self.work_dir, COMPILER_USER_UID, RUN_GROUP_GID)
         os.chmod(self.work_dir, 0o711)
     except Exception as e:
         logger.exception(e)
         raise JudgeClientError("failed to create runtime dir")
     return self.work_dir, self.test_case_dir
예제 #10
0
    def __init__(self,
                 run_config,
                 exe_path,
                 max_cpu_time,
                 max_memory,
                 test_case_dir,
                 submission_dir,
                 spj_version,
                 spj_config,
                 io_mode,
                 submission_id,
                 input_str,
                 output=False,
                 output_description=None):
        self._run_config = run_config
        self._exe_path = exe_path
        self._max_cpu_time = max_cpu_time
        self._max_memory = max_memory
        self._max_real_time = self._max_cpu_time * 3
        self._test_case_dir = test_case_dir
        self._submission_dir = submission_dir
        self._submission_id = submission_id

        self._pool = Pool(processes=psutil.cpu_count())
        self._test_case_info = self._load_test_case_info()

        self._spj_version = spj_version
        self._spj_config = spj_config
        self._output = output
        self._io_mode = io_mode
        self._input_str = input_str

        pattern = re.compile(r'<[^>]+>', re.S)
        self._output_description = pattern.sub('', output_description)

        if self._spj_version and self._spj_config:
            self._spj_exe = os.path.join(
                SPJ_EXE_DIR, self._spj_config["exe_name"].format(
                    spj_version=self._spj_version))
            if not os.path.exists(self._spj_exe):
                raise JudgeClientError("spj exe not found")
예제 #11
0
    def __init__(self,
                 run_config,
                 exe_path,
                 max_cpu_time,
                 max_memory,
                 test_case_id,
                 submission_dir,
                 spj_version,
                 spj_config,
                 output=False):
        #_run_config是一个json的数据
        self._run_config = run_config
        self._exe_path = exe_path
        self._max_cpu_time = max_cpu_time
        self._max_memory = max_memory
        #最大真实时间限定为最大CPU时间的3倍
        self._max_real_time = self._max_cpu_time * 3
        self._test_case_id = test_case_id
        #因为每个测试用例不同的,这个test_case_id也应该有用户传进,然后拼接在一起形成一个新的文件路径
        self._test_case_dir = os.path.join(TEST_CASE_DIR, test_case_id)
        #_submission_dir=submission_dir=/judger/run/submission_id/
        self._submission_dir = submission_dir
        #实例化一个多进程池,里面的进程数根据系统CPU逻辑个数开启
        self._pool = Pool(processes=psutil.cpu_count())
        #加载测试用例信息
        self._test_case_info = self._load_test_case_info()

        self._spj_version = spj_version
        self._spj_config = spj_config
        self._output = output

        #如果特殊评判版本和配置不为空,则执行特殊评判
        #拼接配置特殊评判的执行文件的路径,注意这里是config的,非compile
        if self._spj_version and self._spj_config:
            self._spj_exe = os.path.join(
                SPJ_EXE_DIR, self._spj_config["exe_name"].format(
                    spj_version=self._spj_version))
            #到SPJ_EXE_DIR去找,如果特殊评判执行文件不存在,则抛出异常
            if not os.path.exists(self._spj_exe):
                raise JudgeClientError("spj exe not found")
예제 #12
0
파일: utils.py 프로젝트: xaccc/JudgeServer
def get_token():
    token = os.environ.get("TOKEN")
    if token:
        return token
    else:
        raise JudgeClientError("env 'token' not found")
예제 #13
0
    def judge(cls,
              language_config,
              src,
              max_cpu_time,
              max_memory,
              test_case_id=None,
              test_case=None,
              spj_version=None,
              spj_config=None,
              spj_compile_config=None,
              spj_src=None,
              output=False,
              io_mode=None,
              output_description=None,
              input_str=None):
        if not io_mode:
            io_mode = {"io_mode": ProblemIOMode.standard}

        if not (test_case or test_case_id) or (test_case and test_case_id):
            raise JudgeClientError("invalid parameter")
        # init
        compile_config = language_config.get("compile")
        run_config = language_config["run"]
        submission_id = uuid.uuid4().hex

        is_spj = spj_version and spj_config

        if is_spj:
            spj_exe_path = os.path.join(
                SPJ_EXE_DIR,
                spj_config["exe_name"].format(spj_version=spj_version))
            # spj src has not been compiled
            if not os.path.isfile(spj_exe_path):
                logger.warning(
                    "%s does not exists, spj src will be recompiled")
                cls.compile_spj(spj_version=spj_version,
                                src=spj_src,
                                spj_compile_config=spj_compile_config)

        init_test_case_dir = bool(test_case)
        with InitSubmissionEnv(JUDGER_WORKSPACE_BASE,
                               submission_id=str(submission_id),
                               init_test_case_dir=init_test_case_dir) as dirs:
            submission_dir, test_case_dir = dirs
            test_case_dir = test_case_dir or os.path.join(
                TEST_CASE_DIR, test_case_id)

            if compile_config:
                src_path = os.path.join(submission_dir,
                                        compile_config["src_name"])

                # write source code into file
                with open(src_path, "w", encoding="utf-8") as f:
                    src = "import sys \nimport codecs \nsys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach()) \n" + src
                    f.write(src)
                os.chown(src_path, COMPILER_USER_UID, 0)
                os.chmod(src_path, 0o400)

                # compile source code, return exe file path
                exe_path = Compiler().compile(compile_config=compile_config,
                                              src_path=src_path,
                                              output_dir=submission_dir)
                try:
                    # Java exe_path is SOME_PATH/Main, but the real path is SOME_PATH/Main.class
                    # We ignore it temporarily
                    os.chown(exe_path, RUN_USER_UID, 0)
                    os.chmod(exe_path, 0o500)
                except Exception:
                    pass
            else:
                exe_path = os.path.join(submission_dir, run_config["exe_name"])
                with open(exe_path, "w", encoding="utf-8") as f:
                    f.write(src)

            if init_test_case_dir:
                info = {
                    "test_case_number": len(test_case),
                    "spj": is_spj,
                    "test_cases": {}
                }
                # write test case
                for index, item in enumerate(test_case):
                    index += 1
                    item_info = {}

                    input_name = str(index) + ".in"
                    item_info["input_name"] = input_name
                    input_data = item["input"].encode("utf-8")
                    item_info["input_size"] = len(input_data)

                    with open(os.path.join(test_case_dir, input_name),
                              "wb") as f:
                        f.write(input_data)
                    if not is_spj:
                        output_name = str(index) + ".out"
                        item_info["output_name"] = output_name
                        output_data = item["output"].encode("utf-8")
                        item_info["output_md5"] = hashlib.md5(
                            output_data).hexdigest()
                        item_info["output_size"] = len(output_data)
                        item_info["stripped_output_md5"] = hashlib.md5(
                            output_data.rstrip()).hexdigest()

                        with open(os.path.join(test_case_dir, output_name),
                                  "wb") as f:
                            f.write(output_data)
                    info["test_cases"][index] = item_info
                with open(os.path.join(test_case_dir, "info"), "w") as f:
                    json.dump(info, f)

            judge_client = JudgeClient(run_config=language_config["run"],
                                       exe_path=exe_path,
                                       max_cpu_time=max_cpu_time,
                                       max_memory=max_memory,
                                       test_case_dir=test_case_dir,
                                       submission_dir=submission_dir,
                                       submission_id=submission_id,
                                       spj_version=spj_version,
                                       spj_config=spj_config,
                                       output=output,
                                       io_mode=io_mode,
                                       output_description=output_description,
                                       input_str=input_str)
            run_result = judge_client.run()

            return run_result
예제 #14
0
    def _judge_one(self, test_case_file_id):
        test_case_info = self._get_test_case_file_info(test_case_file_id)
        in_file = os.path.join(self._test_case_dir,
                               test_case_info["input_name"])

        if self._io_mode["io_mode"] == ProblemIOMode.file:
            user_output_dir = os.path.join(self._submission_dir,
                                           str(test_case_file_id))
            os.mkdir(user_output_dir)
            os.chown(user_output_dir, RUN_USER_UID, RUN_GROUP_GID)
            os.chmod(user_output_dir, 0o711)
            os.chdir(user_output_dir)
            # todo check permission
            user_output_file = os.path.join(user_output_dir,
                                            self._io_mode["output"])
            real_user_output_file = os.path.join(user_output_dir, "stdio.txt")
            shutil.copyfile(
                in_file, os.path.join(user_output_dir, self._io_mode["input"]))
            kwargs = {
                "input_path": in_file,
                "output_path": real_user_output_file,
                "error_path": real_user_output_file
            }
        else:
            real_user_output_file = user_output_file = os.path.join(
                self._submission_dir, test_case_file_id + ".out")
            kwargs = {
                "input_path": in_file,
                "output_path": real_user_output_file,
                "error_path": real_user_output_file
            }

        command = self._run_config["command"].format(
            exe_path=self._exe_path,
            exe_dir=os.path.dirname(self._exe_path),
            max_memory=int(self._max_memory / 1024)).split(" ")
        env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get(
            "env", [])

        seccomp_rule = self._run_config["seccomp_rule"]
        if isinstance(seccomp_rule, dict):
            seccomp_rule = seccomp_rule[self._io_mode["io_mode"]]

        run_result = _judger.run(max_cpu_time=self._max_cpu_time,
                                 max_real_time=self._max_real_time,
                                 max_memory=self._max_memory,
                                 max_stack=128 * 1024 * 1024,
                                 max_output_size=max(
                                     test_case_info.get("output_size", 0) * 2,
                                     1024 * 1024 * 16),
                                 max_process_number=_judger.UNLIMITED,
                                 exe_path=command[0],
                                 args=command[1::],
                                 env=env,
                                 log_path=JUDGER_RUN_LOG_PATH,
                                 seccomp_rule_name=seccomp_rule,
                                 uid=RUN_USER_UID,
                                 gid=RUN_GROUP_GID,
                                 memory_limit_check_only=self._run_config.get(
                                     "memory_limit_check_only", 0),
                                 **kwargs)
        run_result["test_case"] = test_case_file_id

        # if progress exited normally, then we should check output result
        run_result["output_md5"] = None
        run_result["output"] = None
        if run_result["result"] == _judger.RESULT_SUCCESS:
            if not os.path.exists(user_output_file):
                run_result["result"] = _judger.RESULT_WRONG_ANSWER
            else:
                if self._test_case_info.get("spj"):
                    if not self._spj_config or not self._spj_version:
                        raise JudgeClientError(
                            "spj_config or spj_version not set")

                    spj_result = self._spj(in_file_path=in_file,
                                           user_out_file_path=user_output_file)

                    if spj_result == SPJ_WA:
                        run_result["result"] = _judger.RESULT_WRONG_ANSWER
                    elif spj_result == SPJ_ERROR:
                        run_result["result"] = _judger.RESULT_SYSTEM_ERROR
                        run_result["error"] = _judger.ERROR_SPJ_ERROR
                else:
                    run_result["output_md5"], is_ac = self._compare_output(
                        test_case_file_id, user_output_file)
                    # -1 == Wrong Answer
                    if not is_ac:
                        run_result["result"] = _judger.RESULT_WRONG_ANSWER

        if self._output:
            try:
                with open(user_output_file, "rb") as f:
                    run_result["output"] = f.read().decode(
                        "utf-8", errors="backslashreplace")
            except Exception:
                pass

        return run_result
예제 #15
0
    def judge(cls,
              language_config,
              src,
              max_cpu_time,
              max_memory,
              test_case_id=None,
              test_case=None,
              spj_version=None,
              spj_config=None,
              spj_compile_config=None,
              spj_src=None,
              output=False,
              io_mode=None):
        if not io_mode:
            io_mode = {"io_mode": ProblemIOMode.standard}

        if not (test_case or test_case_id) or (test_case and test_case_id):
            raise JudgeClientError("invalid parameter")
        # init
        compile_config = language_config.get("compile")
        run_config = language_config["run"]
        submission_id = uuid.uuid4().hex
        # 是否是特殊题
        is_spj = spj_version and spj_config

        if is_spj:
            spj_exe_path = os.path.join(
                SPJ_EXE_DIR,
                spj_config["exe_name"].format(spj_version=spj_version))
            # spj src has not been compiled
            if not os.path.isfile(spj_exe_path):
                logger.warning(
                    "%s does not exists, spj src will be recompiled")
                cls.compile_spj(spj_version=spj_version,
                                src=spj_src,
                                spj_compile_config=spj_compile_config)
        # 初始化判题目录
        init_test_case_dir = bool(test_case)
        with InitSubmissionEnv(JUDGER_WORKSPACE_BASE,
                               submission_id=str(submission_id),
                               init_test_case_dir=init_test_case_dir) as dirs:
            submission_dir, test_case_dir = dirs
            test_case_dir = test_case_dir or os.path.join(
                TEST_CASE_DIR, test_case_id)

            #若compile_config 不为空创建获得源码路径
            if compile_config:
                src_path = os.path.join(submission_dir,
                                        compile_config["src_name"])

                # 将源码写入源码地址
                with open(src_path, "w", encoding="utf-8") as f:
                    f.write(src)
                os.chown(src_path, COMPILER_USER_UID, 0)
                os.chmod(src_path, 0o400)

                # compile source code, return exe file path
                exe_path = Compiler().compile(compile_config=compile_config,
                                              src_path=src_path,
                                              output_dir=submission_dir)
                try:
                    # Java exe_path is SOME_PATH/Main, but the real path is SOME_PATH/Main.class
                    # We ignore it temporarily
                    os.chown(exe_path, RUN_USER_UID, 0)
                    os.chmod(exe_path, 0o500)
                except Exception:
                    pass
            #若compile_config为空 直接获得EXE路径
            else:
                exe_path = os.path.join(submission_dir, run_config["exe_name"])
                with open(exe_path, "w", encoding="utf-8") as f:
                    f.write(src)

            # 初始化判题目录
            # info
            # |-test_case_numeber int
            # |-spj bool
            # |-test_cases
            # ||-item_info[0]
            # ||-item_info[1]
            # ||- ...
            if init_test_case_dir:
                info = {
                    "test_case_number": len(test_case),
                    "spj": is_spj,
                    "test_cases": {}
                }
                # write test case
                for index, item in enumerate(test_case):
                    index += 1
                    item_info = {}
                    # item_info
                    # |-input_name
                    # |-input_size
                    # |-output_name
                    # |-output_md5
                    # |-output_size
                    # |-stripped_output_md5
                    input_name = str(index) + ".in"
                    item_info["input_name"] = input_name
                    input_data = item["input"].encode("utf-8")
                    item_info["input_size"] = len(input_data)

                    with open(os.path.join(test_case_dir, input_name),
                              "wb") as f:
                        f.write(input_data)
                    if not is_spj:
                        output_name = str(index) + ".out"
                        item_info["output_name"] = output_name
                        output_data = item["output"].encode("utf-8")
                        item_info["output_md5"] = hashlib.md5(
                            output_data).hexdigest()
                        item_info["output_size"] = len(output_data)
                        # strip()
                        # 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
                        # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
                        item_info["stripped_output_md5"] = hashlib.md5(
                            output_data.rstrip()).hexdigest()

                        with open(os.path.join(test_case_dir, output_name),
                                  "wb") as f:
                            f.write(output_data)
                    info["test_cases"][index] = item_info
                with open(os.path.join(test_case_dir, "info"), "w") as f:
                    json.dump(info, f)
                # json.dumps()函数是将一个Python数据类型列表进行json格式的编码

            # 开始初始化评测机
            judge_client = JudgeClient(run_config=language_config["run"],
                                       exe_path=exe_path,
                                       max_cpu_time=max_cpu_time,
                                       max_memory=max_memory,
                                       test_case_dir=test_case_dir,
                                       submission_dir=submission_dir,
                                       spj_version=spj_version,
                                       spj_config=spj_config,
                                       output=output,
                                       io_mode=io_mode)
            run_result = judge_client.run()

            return run_result
예제 #16
0
    def _judge_one(self, test_case_file_id):
        # 找到测试用例信息
        test_case_info = self._get_test_case_file_info(test_case_file_id)
        # 输入文件路径,input_name:1.in,那么路径就是/test_case/1.in
        in_file = os.path.join(self._test_case_dir,
                               test_case_info["input_name"])
        # 输出文件路径:user_output_file=_submission_dir+test_case_file_id.out=/judger/run/submission_id/test_case_file_id.out
        user_output_file = os.path.join(self._submission_dir,
                                        test_case_file_id + ".out")

        #先格式化执行文件命令并按照空格分割成块,exe_path对应c和c++,exe_dir和max_memory对应java
        command = self._run_config["command"].format(
            exe_path=self._exe_path,
            exe_dir=os.path.dirname(self._exe_path),
            max_memory=int(self._max_memory / 1024)).split(" ")

        #设置运行环境:系统的路径拼接上运行配置的路径
        env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get(
            "env", [])

        run_result = _judger.run(
            max_cpu_time=self._max_cpu_time,
            max_real_time=self._max_real_time,
            max_memory=self._max_memory,
            max_stack=128 * 1024 * 1024,
            # 根据配置文件要求,比较选取最大的那个
            max_output_size=max(
                test_case_info.get("output_size", 0) * 2, 1024 * 1024 * 16),
            max_process_number=_judger.UNLIMITED,
            #这里执行的是用户的编译好的代码
            exe_path=command[0],
            input_path=in_file,
            output_path=user_output_file,
            error_path=user_output_file,
            #从第1个参数开始,直至最后
            args=command[1::],
            env=env,
            log_path=JUDGER_RUN_LOG_PATH,
            #这里需要设置黑名单安全计算规则
            seccomp_rule_name=self._run_config["seccomp_rule"],
            uid=RUN_USER_UID,
            gid=RUN_GROUP_GID,
            #由于java比较特殊,所以只设置其运行内存为检查,查出了就报错
            memory_limit_check_only=self._run_config.get(
                "memory_limit_check_only", 0))

        #这个是judge.run():返回的数据:例如{'cpu_time': 0, 'signal': 0, 'memory': 4554752, 'exit_code': 0, 'result': 0, 'error': 0, 'real_time': 2}
        #因为run_result里面的json数据是没有对应的test_cast这么一条数据的,但是可以添加进去,那么运行的结果就有对应的数据了
        #因为是for循环进行的调用的,所以可以每次评判完成时候添加这几个数据,例如下面的outp_md5和output因为还没有生成,需要
        #进行测试结果比较会后才会返回,所以这里就先将它们赋值为None,等返回对应的之后再进行相应的覆盖即可。
        #run_result是一个json的数据,里面的参数就是运行的结果
        run_result["test_case"] = test_case_file_id

        # if progress exited normally, then we should check output result
        # 如果进程正常退出,那么然后我们就应该检查输出结果
        run_result["output_md5"] = None
        run_result["output"] = None

        # 如果评测结果通过,仅仅运行没有错误,还要将结果进行比较
        if run_result["result"] == _judger.RESULT_SUCCESS:
            #调用_load_test_case_info加载测试用例信息,当spj为真,就进行spj评判,否者比较结果
            if self._test_case_info.get("spj"):
                #如果特殊测试配值为0或者版本号没设置,抛出相应的异常
                if not self._spj_config or not self._spj_version:
                    raise JudgeClientError("spj_config or spj_version not set")

                #意思就是通过正常的测试之后,如果需要进行特殊评判的话,就进入特殊评判,所以输入文
                # 件路径还是从本目录传进去,等到调用_spj()函数之后,在做相应的用户和用户组和权限的更改。
                spj_result = self._spj(in_file_path=in_file,
                                       user_out_file_path=user_output_file)

                #特殊评判答案错误-1
                if spj_result == SPJ_WA:
                    run_result["result"] = _judger.RESULT_WRONG_ANSWER
                #返回1(这里不设RESULT_CPU_TIME_LIMIT_EXCEEDED),因为不用,只是然后用户知道是系统错误就行
                elif spj_result == SPJ_ERROR:
                    run_result["result"] = _judger.RESULT_SYSTEM_ERROR
                    run_result["error"] = _judger.ERROR_SPJ_ERROR
            else:
                #否则就不用进行特殊测试,直接比较结果的md5值,判断评测结果,返回之后覆盖None
                run_result["output_md5"], is_ac = self._compare_output(
                    test_case_file_id)
                # -1 为错误答案
                # is_ac为假,WA并不便是运算不通过,是得出的结果和测试数据的不同
                if not is_ac:
                    run_result["result"] = _judger.RESULT_WRONG_ANSWER

        #输出文件不为空,就设置运行的结果为文件的内容
        if self._output:
            try:
                with open(user_output_file, "r", encoding="utf-8") as f:
                    #覆盖之前的None
                    run_result["output"] = f.read()
            except Exception:
                pass

        return run_result