Beispiel #1
0
    def getTestcaseStatus(self, id):
        req = self.getAuthRequest(self.BASE_URL +
                                  '/widgets/single_submission?id=' + str(id))
        if req.status_code == 401:
            raise InvalidSessionException(req.status_code)
        soup = bs.BeautifulSoup(req.text, 'lxml')
        status = soup.find_all('span', attrs={'class':
                                              'status'})[0].contents[0]
        time = soup.find_all('div', attrs={'class':
                                           'time'})[-1].contents[0].strip()
        memory = soup.find_all('div', attrs={'class': 'memory'})[0].contents[0]
        done = status not in self.gradingStatuses

        if memory == '---':
            memory = None
        if time == '---':
            time = None

        problemName = soup.find_all('div',
                                    attrs={'class':
                                           'name'})[0].find('a').contents[0]

        req = self.getAuthRequest(self.BASE_URL +
                                  '/widgets/submission_testcases?id=' +
                                  str(id))
        if req.status_code == 401:
            raise InvalidSessionException(req.status_code)
        soup = bs.BeautifulSoup(req.text, 'lxml')
        raw_result = soup.find('body').contents[0]

        cases = []

        try:
            caseTable = soup.find_all(
                'table', attrs={'class': 'submissions-status-table'})[0]
        except IndexError:
            return Result(cases, raw_result, status, problemName, time, memory,
                          done)

        for row in caseTable.find_all('tr'):
            testcase = Testcase()
            try:
                testcase.id = int(row.get('id'))
            except ValueError:
                continue
            children = row.find_all('td')
            testcase.descriptor = children[0].find('b').contents[0]
            testcase.status = children[1].find('span').contents[0]
            testcase.details = {
                'time':
                children[2].find('span').contents[0].replace(',', ''),
                'memory':
                children[3].contents[0].replace('\xa0', ' ').replace(']', ''),
                'points':
                children[4].contents[0]
            }
            cases.append(testcase)

        return Result(cases, raw_result, status, problemName, time, memory,
                      done)
Beispiel #2
0
    def grade(self, case):
        result = Result(case)

        input = case.input_data()  # cache generator data

        self._current_proc = self.binary.launch(time=self.problem.time_limit, memory=self.problem.memory_limit,
                                                pipe_stderr=True, unbuffered=case.config.unbuffered,
                                                io_redirects=case.io_redirects())

        error = self._interact_with_process(case, result, input)

        process = self._current_proc

        result.max_memory = process.max_memory or 0.0
        result.execution_time = process.execution_time or 0.0
        result.r_execution_time = process.r_execution_time or 0.0

        # Translate status codes/process results into Result object for status codes
        self.set_result_flag(process, result)

        check = self.check_result(case, result)

        # checkers must either return a boolean (True: full points, False: 0 points)
        # or a CheckerResult, so convert to CheckerResult if it returned bool
        if not isinstance(check, CheckerResult):
            check = CheckerResult(check, case.points if check else 0.0)

        result.result_flag |= [Result.WA, Result.AC][check.passed]
        result.points = check.points

        self.update_feedback(check, error, process, result)

        return result
Beispiel #3
0
    def grade_cases(self, grader, cases, short_circuit=False, is_short_circuiting=False):

        for case in cases:
            # Yield notifying objects for batch begin/end, and unwrap all cases inside the batches
            if isinstance(case, BatchedTestCase):
                yield BatchBegin()
                for _ in self.grade_cases(grader, case.batched_cases, short_circuit=True,
                                          is_short_circuiting=is_short_circuiting):
                    yield _
                yield BatchEnd()
                continue

            # Stop grading if we're short circuiting
            if is_short_circuiting:
                result = Result(case)
                result.result_flag = Result.SC
                yield result
                continue

            # Must check here because we might be interrupted mid-execution
            # If we don't bail out, we get an IR.
            # In Java's case, all the code after this will crash.
            if self._terminate_grading:
                raise TerminateGrading()

            result = grader.grade(case)

            # If the WA bit of result_flag is set and we are set to short-circuit (e.g., in a batch),
            # short circuit the rest of the cases.
            # Do the same if the case is a pretest (i.e. has 0 points)
            if (result.result_flag & Result.WA) > 0 and (short_circuit or case.points == 0):
                is_short_circuiting = True

            yield result
Beispiel #4
0
    def grade(self, case):
        result = Result(case)

        case.input_data()  # cache generator data

        self._current_proc = self.binary.launch(time=self.problem.time_limit, memory=self.problem.memory_limit,
                                                pipe_stderr=True,
                                                unbuffered=case.config.unbuffered)

        error = self._interact_with_process(case, result)

        process = self._current_proc

        result.max_memory = process.max_memory or 0.0
        result.execution_time = process.execution_time or 0.0
        result.r_execution_time = process.r_execution_time or 0.0

        # checkers might crash if any data is None, so force at least empty string
        check = case.checker()(result.proc_output or '',
                               case.output_data() or '',
                               submission_source=self.source,
                               judge_input=case.input_data() or '',
                               point_value=case.points)

        # checkers must either return a boolean (True: full points, False: 0 points)
        # or a CheckerResult, so convert to CheckerResult if it returned bool
        if not isinstance(check, CheckerResult):
            check = CheckerResult(check, case.points if check else 0.0)

        result.result_flag |= [Result.WA, Result.AC][check.passed]

        # Translate status codes/process results into Result object for status codes

        if process.returncode > 0:
            # print>> sys.stderr, 'Exited with error: %d' % process.returncode
            result.result_flag |= Result.IR
        if process.returncode < 0:
            # None < 0 == True
            # if process.returncode is not None:
               # print>> sys.stderr, 'Killed by signal %d' % -process.returncode
            result.result_flag |= Result.RTE  # Killed by signal
        if process.tle:
            result.result_flag |= Result.TLE
        if process.mle:
            result.result_flag |= Result.MLE

        if result.result_flag & ~Result.WA:
            check.points = 0

        result.points = check.points
        result.feedback = (check.feedback or
                           (process.feedback if hasattr(process, 'feedback') else
                            getattr(self.binary, 'get_feedback', lambda x, y: '')(error, result)))

        if not result.feedback and hasattr(process, 'signal') and process.signal and result.get_main_code() in [Result.IR, Result.RTE]:
            result.feedback = strsignal(process.signal)

        return result
Beispiel #5
0
    def _ipc_result(self, report, batch_number: Optional[int],
                    case_number: int, result: Result) -> None:
        codes = result.readable_codes()

        is_sc = result.result_flag & Result.SC
        colored_codes = [
            '#ansi[%s](%s|bold)' %
            ('--' if x == 'SC' else x, Result.COLORS_BYID[x]) for x in codes
        ]
        colored_aux_codes = '{%s}' % ', '.join(
            colored_codes[1:]) if len(codes) > 1 else ''
        colored_feedback = '(#ansi[%s](|underline)) ' % utf8text(
            result.feedback) if result.feedback else ''
        if is_sc:
            case_info = ''
        else:
            case_info = '[%.3fs (%.3fs) | %dkb] %s%s' % (
                result.execution_time,
                result.wall_clock_time,
                result.max_memory,
                colored_feedback,
                colored_aux_codes,
            )
        case_padding = '  ' if batch_number is not None else ''
        report(
            ansi_style(
                '%sTest case %2d %-3s %s' %
                (case_padding, case_number, colored_codes[0], case_info)))
        self.packet_manager.test_case_status_packet(case_number, result)
Beispiel #6
0
 def test_case_status_packet(self, position: int, result: Result):
     log.info('Test case on %d: #%d, %s [%.3fs | %.2f MB], %.1f/%.0f',
              self.judge.current_submission_id, position,
              ', '.join(result.readable_codes()), result.execution_time,
              result.max_memory / 1024.0, result.points,
              result.total_points)
     with self._testcase_queue_lock:
         self._testcase_queue.append((position, result))
Beispiel #7
0
    def populate_result(self, stderr: bytes, result: Result,
                        process: TracedPopen) -> None:
        # Translate status codes/process results into Result object for status codes
        result.max_memory = process.max_memory or 0.0
        result.execution_time = process.execution_time or 0.0
        result.wall_clock_time = process.wall_clock_time or 0.0

        if process.is_ir:
            result.result_flag |= Result.IR
        if process.is_rte:
            result.result_flag |= Result.RTE
        if process.is_ole:
            result.result_flag |= Result.OLE
        if process.is_tle:
            result.result_flag |= Result.TLE
        if process.is_mle:
            result.result_flag |= Result.MLE

        result.update_feedback(stderr, process, self)
Beispiel #8
0
    def grade_cases(self, grader, cases, short_circuit=False, is_short_circuiting=False):
        for case in cases:
            # Yield notifying objects for batch begin/end, and unwrap all cases inside the batches
            if isinstance(case, BatchedTestCase):
                yield BatchBegin()

                for batched_case in self.grade_cases(grader, case.batched_cases,
                                                     short_circuit=case.config['short_circuit'],
                                                     is_short_circuiting=is_short_circuiting):
                    # A batched case just failed.
                    # There are two cases where this means that we should completely short-circuit:
                    # 1. If the batch was worth 0 points, to emulate the property of 0-point cases.
                    # 2. If the short_circuit flag is true, see <https://github.com/DMOJ/judge/issues/341>.
                    if (batched_case.result_flag & Result.WA) and (not case.points or short_circuit):
                        is_short_circuiting = True
                    yield batched_case
                yield BatchEnd()
                continue

            # Stop grading if we're short circuiting
            if is_short_circuiting:
                result = Result(case)
                result.result_flag = Result.SC
                yield result
                continue

            # Must check here because we might be interrupted mid-execution
            # If we don't bail out, we get an IR.
            # In Java's case, all the code after this will crash.
            if self._terminate_grading:
                raise TerminateGrading()

            result = grader.grade(case)

            # If the WA bit of result_flag is set and we are set to short-circuit (e.g., in a batch),
            # short circuit the rest of the cases.
            # Do the same if the case is a pretest (i.e. has 0 points)
            if (result.result_flag & Result.WA) > 0 and (short_circuit or not case.points):
                is_short_circuiting = True

            yield result
def parse_helper_file_error(proc, executor, name, stderr, time_limit, memory_limit):
    if proc.is_tle:
        error = '%s timed out (> %d seconds)' % (name, time_limit)
    elif proc.is_mle:
        error = '%s ran out of memory (> %s Kb)' % (name, memory_limit)
    elif proc.protection_fault:
        syscall, callname, args = proc.protection_fault
        error = '%s invoked disallowed syscall %s (%s)' % (name, syscall, callname)
    elif proc.returncode:
        if proc.returncode > 0:
            error = '%s exited with nonzero code %d' % (name, proc.returncode)
        else:
            error = '%s exited with %s' % (name, strsignal(proc.signal))
        feedback = Result.get_feedback_str(stderr, proc, executor)
        if feedback:
            error += ' with feedback %s' % feedback
    else:
        return

    raise InternalError(error)
Beispiel #10
0
    def grade(self, case):
        result = Result(case)

        input = case.input_data()  # cache generator data

        self._current_proc = self.binary.launch(time=self.problem.time_limit,
                                                memory=self.problem.memory_limit,
                                                symlinks=case.config.symlinks,
                                                pipe_stderr=True,
                                                wall_time=case.config.wall_time_factor * self.problem.time_limit)

        error = self._interact_with_process(case, result, input)

        process = self._current_proc

        result.max_memory = process.max_memory or 0.0
        result.execution_time = process.execution_time or 0.0
        result.r_execution_time = process.r_execution_time or 0.0

        # Translate status codes/process results into Result object for status codes
        self.set_result_flag(process, result)

        check = self.check_result(case, result)

        # checkers must either return a boolean (True: full points, False: 0 points)
        # or a CheckerResult, so convert to CheckerResult if it returned bool
        if not isinstance(check, CheckerResult):
            check = CheckerResult(check, case.points if check else 0.0)

        result.result_flag |= [Result.WA, Result.AC][check.passed]
        result.points = check.points
        result.extended_feedback = check.extended_feedback

        self.update_feedback(check, error, process, result)
        case.free_data()

        # Where CPython has reference counting and a GC, PyPy only has a GC. This means that while CPython
        # will have freed any (usually massive) generated data from the line above by reference counting, it might
        # - and probably still is - in memory by now. We need to be able to fork() immediately, which has a good chance
        # of failing if there's not a lot of swap space available.
        #
        # We don't really have a way to force the generated data to disappear, so calling a gc here is the best
        # chance we have.
        if platform.python_implementation() == 'PyPy':
            gc.collect()

        return result
Beispiel #11
0
def parse_helper_file_error(proc: 'TracedPopen', executor: 'BaseExecutor',
                            name: str, stderr: bytes, time_limit: int,
                            memory_limit: int) -> None:
    if proc.is_tle:
        error = f'{name} timed out (> {time_limit} seconds)'
    elif proc.is_mle:
        error = f'{name} ran out of memory (> {memory_limit} KB)'
    elif proc.protection_fault:
        syscall, callname, args, update_errno = proc.protection_fault
        error = f'{name} invoked disallowed syscall {syscall} ({callname})'
    elif proc.returncode:
        if proc.returncode > 0:
            error = f'{name} exited with nonzero code {proc.returncode}'
        else:
            assert proc.signal is not None
            error = f'{name} exited with {strsignal(proc.signal)}'
        feedback = Result.get_feedback_str(stderr, proc, executor)
        if feedback:
            error += f' with feedback {feedback}'
    else:
        return

    raise InternalError(error)
Beispiel #12
0
    def populate_result(self, stderr: bytes, result: Result,
                        process: TracedPopen) -> None:
        # Translate status codes/process results into Result object for status codes
        result.max_memory = process.max_memory or 0.0
        result.execution_time = process.execution_time or 0.0
        result.wall_clock_time = process.wall_clock_time or 0.0
        result.context_switches = process.context_switches or (0, 0)
        result.runtime_version = ', '.join(
            f'{runtime} {".".join(map(str, version))}'
            for runtime, version in self.get_runtime_versions())

        if process.is_ir:
            result.result_flag |= Result.IR
        if process.is_rte:
            result.result_flag |= Result.RTE
        if process.is_ole:
            result.result_flag |= Result.OLE
        if process.is_tle:
            result.result_flag |= Result.TLE
        if process.is_mle:
            result.result_flag |= Result.MLE

        result.update_feedback(stderr, process, self)
Beispiel #13
0
    def _run_generator(self, gen, args=None):
        flags = []
        args = args or []

        # resource limits on how to run the generator
        time_limit = env.generator_time_limit
        memory_limit = env.generator_memory_limit
        compiler_time_limit = env.generator_compiler_time_limit
        lang = None  # Default to C/C++

        base = get_problem_root(self.problem.id)
        if isinstance(gen, str):
            filenames = gen
        elif isinstance(gen.unwrap(), list):
            filenames = list(gen.unwrap())
        else:
            if isinstance(gen.source, str):
                filenames = gen.source
            elif isinstance(gen.source.unwrap(), list):
                filenames = list(gen.source.unwrap())
            else:
                raise InvalidInitException("invalid generator declaration")

            if gen.flags:
                flags += gen.flags
            if not args and gen.args:
                args += gen.args

            time_limit = gen.time_limit or time_limit
            memory_limit = gen.memory_limit or memory_limit
            compiler_time_limit = gen.compiler_time_limit or compiler_time_limit
            lang = gen.language

        if not isinstance(filenames, list):
            filenames = [filenames]

        filenames = [os.path.join(base, name) for name in filenames]
        executor = self.problem.generator_manager.get_generator(
            filenames,
            flags,
            lang=lang,
            compiler_time_limit=compiler_time_limit)

        # convert all args to str before launching; allows for smoother int passing
        args = map(str, args)

        # setting large buffers is really important, because otherwise stderr is unbuffered
        # and the generator begins calling into cptbox Python code really frequently
        proc = executor.launch(*args,
                               time=time_limit,
                               memory=memory_limit,
                               stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE,
                               stderr_buffer_size=65536,
                               stdout_buffer_size=65536)

        try:
            input = self.problem.problem_data[
                self.config['in']] if self.config['in'] else None
        except KeyError:
            input = None

        stdout, stderr = proc.unsafe_communicate(input)
        self._generated = list(map(self._normalize, (stdout, stderr)))

        if proc.tle:
            raise InternalError('generator timed out (> %s seconds)' %
                                time_limit)
        if proc.mle:
            raise InternalError('generator ran out of memory (> %s Kb)' %
                                memory_limit)
        if proc.protection_fault:
            syscall, callname, args = proc.protection_fault
            raise InternalError(
                'generator invoked disallowed syscall %s (%s)' %
                (syscall, callname))
        if proc.returncode:
            error = 'generator exited with nonzero code %s' % proc.returncode
            # To get the feedback, we need a Result object, but we lack a Case object
            # So we set it to None because we don't need to access it
            result = Result(None)
            result.set_result_flag(proc)
            feedback = (proc.feedback
                        if hasattr(executor, 'feedback') and proc.feedback else
                        (getattr(executor, 'get_feedback', lambda x, y, z: '')(
                            stderr, result, proc)))
            if feedback:
                error += ' with feedback: %s' % feedback
            raise InternalError(error)