Beispiel #1
0
def get_problem_from_url(problem_url: str) -> Problem:
    dummy_alphabet = 'Z'  # it's impossible to reconstruct the alphabet from URL
    result = urllib.parse.urlparse(problem_url)

    normpath = os.path.normpath(result.path)
    normpath = normpath.replace("\\", "/")  # for windows

    # old-style (e.g. http://agc012.contest.atcoder.jp/tasks/agc012_d)
    dirname, basename = posixpath.split(normpath)
    if result.scheme in ('', 'http', 'https') \
            and result.netloc.count('.') == 3 \
            and result.netloc.endswith('.contest.atcoder.jp') \
            and result.netloc.split('.')[0] \
            and dirname == '/tasks' \
            and basename:
        contest_id = result.netloc.split('.')[0]
        problem_id = basename
        return Problem(Contest(contest_id), dummy_alphabet, problem_id)

    # new-style (e.g. https://beta.atcoder.jp/contests/abc073/tasks/abc073_a)
    m = re.match(r'^/contests/([\w\-_]+)/tasks/([\w\-_]+)$', normpath)
    if result.scheme in ('', 'http', 'https') \
            and result.netloc in ('atcoder.jp', 'beta.atcoder.jp') \
            and m:
        contest_id = m.group(1)
        problem_id = m.group(2)
        return Problem(Contest(contest_id), dummy_alphabet, problem_id)

    raise UnknownProblemURLError
Beispiel #2
0
    def submit_source_code(self, contest: Contest, problem: Problem, lang: str,
                           source: str) -> Submission:
        resp = self._request(contest.get_submit_url())

        soup = BeautifulSoup(resp.text, "html.parser")
        session_id = soup.find("input", attrs={"type": "hidden"}).get("value")
        task_select_area = soup.find('select',
                                     attrs={"id": "submit-task-selector"})
        task_field_name = task_select_area.get("name")
        task_number = task_select_area.find(
            "option", text=re.compile('{} -'.format(
                problem.get_alphabet()))).get("value")
        language_select_area = soup.find(
            'select',
            attrs={"id": "submit-language-selector-{}".format(task_number)})
        language_field_name = language_select_area.get("name")
        language_number = language_select_area.find("option",
                                                    text=lang).get("value")
        postdata = {
            "__session": session_id,
            task_field_name: task_number,
            language_field_name: language_number,
            "source_code": source
        }
        resp = self._request(contest.get_submit_url(),
                             data=postdata,
                             method='POST')
        return Submission.make_submissions_from(resp.text)[0]
Beispiel #3
0
    def test_url_parser(self):
        problem = Problem(Contest("utpc2014"), "Z", "utpc2014_k")
        urls = [
            "http://utpc2014.contest.atcoder.jp/tasks/utpc2014_k",
            "http://beta.atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "http://atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://utpc2014.contest.atcoder.jp/tasks/utpc2014_k",
            "https://beta.atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k?lang=en",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k/?lang=en",
        ]

        for url in urls:
            self.assertEqual(
                get_problem_from_url(url).to_dict(), problem.to_dict())
    def download_problem_content(self, problem: Problem) -> ProblemContent:
        resp = self._request(problem.get_url())

        try:
            return ProblemContent.from_html(resp.text)
        except (InputFormatDetectionError, SampleDetectionError) as e:
            raise e
Beispiel #5
0
    def download_problem_content(self, problem: Problem) -> ProblemContent:
        resp = self._request(problem.get_url())

        try:
            return ProblemContent.from_html(resp.text)
        except (InputFormatDetectionError, SampleDetectionError) as e:
            raise e
Beispiel #6
0
    def submit_source_code(self, contest: Contest, problem: Problem, lang: Union[str, Language], source: str) -> Submission:
        if isinstance(lang, str):
            warnings.warn(
                "Parameter lang as a str object is deprecated. "
                "Please use 'atcodertools.common.language.Language' object instead",
                UserWarning)
            lang_option_pattern = lang
        else:
            lang_option_pattern = lang.submission_lang_pattern

        resp = self._request(contest.get_submit_url())

        soup = BeautifulSoup(resp.text, "html.parser")
        session_id = soup.find("input", attrs={"type": "hidden"}).get("value")
        task_select_area = soup.find(
            'select', attrs={"id": "submit-task-selector"})
        task_field_name = task_select_area.get("name")
        task_number = task_select_area.find(
            "option", text=re.compile('{} -'.format(problem.get_alphabet()))).get("value")
        language_select_area = soup.find(
            'select', attrs={"id": "submit-language-selector-{}".format(task_number)})
        language_field_name = language_select_area.get("name")
        language_number = language_select_area.find(
            "option", text=lang_option_pattern).get("value")
        postdata = {
            "__session": session_id,
            task_field_name: task_number,
            language_field_name: language_number,
            "source_code": source
        }
        resp = self._request(
            contest.get_submit_url(),
            data=postdata,
            method='POST')
        return Submission.make_submissions_from(resp.text)[0]
    def submit_source_code(self, contest: Contest, problem: Problem, lang: Union[str, Language], source: str) -> Submission:
        if isinstance(lang, str):
            warnings.warn(
                "Parameter lang as a str object is deprecated. "
                "Please use 'atcodertools.common.language.Language' object instead",
                UserWarning)
            lang_option_pattern = lang
        else:
            lang_option_pattern = lang.submission_lang_pattern

        resp = self._request(contest.get_submit_url())

        soup = BeautifulSoup(resp.text, "html.parser")
        session_id = soup.find("input", attrs={"type": "hidden"}).get("value")
        task_select_area = soup.find(
            'select', attrs={"id": "submit-task-selector"})
        task_field_name = task_select_area.get("name")
        task_number = task_select_area.find(
            "option", text=re.compile('{} -'.format(problem.get_alphabet()))).get("value")
        language_select_area = soup.find(
            'select', attrs={"id": "submit-language-selector-{}".format(task_number)})
        language_field_name = language_select_area.get("name")
        language_number = language_select_area.find(
            "option", text=lang_option_pattern).get("value")
        postdata = {
            "__session": session_id,
            task_field_name: task_number,
            language_field_name: language_number,
            "source_code": source
        }
        resp = self._request(
            contest.get_submit_url(),
            data=postdata,
            method='POST')
        return Submission.make_submissions_from(resp.text)[0]
Beispiel #8
0
 def from_dict(cls, dic):
     return Metadata(
         problem=Problem.from_dict(dic["problem"]),
         code_filename=dic["code_filename"],
         sample_in_pattern=dic["sample_in_pattern"],
         sample_out_pattern=dic["sample_out_pattern"],
         lang=Language.from_name(dic["lang"]),
     )
 def from_dict(cls, dic):
     return Metadata(
         problem=Problem.from_dict(dic["problem"]),
         code_filename=dic["code_filename"],
         sample_in_pattern=dic["sample_in_pattern"],
         sample_out_pattern=dic["sample_out_pattern"],
         lang=Language.from_name(dic["lang"]),
     )
    def test_url_parser(self):
        dummy_alphabet = "Z"
        problem = Problem(Contest("utpc2014"), "Z", "utpc2014_k")
        urls = [
            "http://utpc2014.contest.atcoder.jp/tasks/utpc2014_k",
            "http://beta.atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "http://atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://utpc2014.contest.atcoder.jp/tasks/utpc2014_k",
            "https://beta.atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k?lang=en",
            "https://atcoder.jp/contests/utpc2014/tasks/utpc2014_k/?lang=en",
        ]

        for url in urls:
            self.assertEqual(
                get_problem_from_url(url).to_dict(), problem.to_dict())
Beispiel #11
0
 def download_problem_list(self, contest: Contest) -> List[Problem]:
     resp = self._request(contest.get_problem_list_url())
     soup = BeautifulSoup(resp.text, "html.parser")
     res = []
     for tag in soup.select('.linkwrapper')[0::2]:
         alphabet = tag.text
         problem_id = tag.get("href").split("/")[-1]
         res.append(Problem(contest, alphabet, problem_id))
     return res
    def test_submit_source_code(self):
        contest = Contest("arc001")
        problem = Problem(contest, "A", "arc001_1")

        self.client._request = create_fake_request_func(
            {contest.get_submit_url(): fake_resp("submit/after_get.html")},
            {contest.get_submit_url(): fake_resp("submit/after_post.html")})

        submission = self.client.submit_source_code(contest, problem,
                                                    "C++14 (GCC 5.4.1)", "x")
        self.assertEqual(3905485, submission.submission_id)
        self.assertEqual("arc001_1", submission.problem_id)
Beispiel #13
0
    def test_submit_source_code(self):
        contest = Contest("arc001")
        problem = Problem(contest, "A", "arc001_1")

        self.client._request = create_fake_request_func(
            {contest.get_submit_url(): fake_resp("submit/after_get.html")},
            {contest.get_submit_url(): fake_resp("submit/after_post.html")})

        # test two patterns (str, Language object) for parameter lang
        for lang in [CPP, "C++14 (GCC 5.4.1)"]:
            submission = self.client.submit_source_code(
                contest, problem, lang, "x")
            self.assertEqual(3905485, submission.submission_id)
            self.assertEqual("arc001_1", submission.problem_id)
Beispiel #14
0
    def from_dict(cls, dic):
        if "judge" in dic:
            judge_type = dic["judge"]["judge_type"]
            if judge_type == "normal":
                judge_method = NormalJudge.from_dict(dic["judge"])
            elif judge_type == "decimal":
                judge_method = DecimalJudge.from_dict(dic["judge"])
            else:
                raise Exception("invalid judge type")
        else:
            judge_method = NormalJudge()

        return Metadata(problem=Problem.from_dict(dic["problem"]),
                        code_filename=dic["code_filename"],
                        sample_in_pattern=dic["sample_in_pattern"],
                        sample_out_pattern=dic["sample_out_pattern"],
                        lang=Language.from_name(dic["lang"]),
                        judge_method=judge_method)
Beispiel #15
0
    def from_dict(cls, dic):
        if "judge" in dic:
            judge_type = dic["judge"]["judge_type"]
            if judge_type == "normal":
                judge_method = NormalJudge.from_dict(dic["judge"])
            elif judge_type == "decimal":
                judge_method = DecimalJudge.from_dict(dic["judge"])
            elif judge_type == "multisolution":
                judge_method = MultiSolutionJudge()
            elif judge_type == "interactive":
                judge_method = InteractiveJudge()
            else:
                raise NoJudgeTypeException()
        else:
            judge_method = NormalJudge()

        return Metadata(problem=Problem.from_dict(dic["problem"]),
                        code_filename=dic["code_filename"],
                        sample_in_pattern=dic["sample_in_pattern"],
                        sample_out_pattern=dic["sample_out_pattern"],
                        lang=Language.from_name(dic["lang"]),
                        judge_method=judge_method)
Beispiel #16
0
def prepare_procedure(atcoder_client: AtCoderClient, problem: Problem,
                      config: Config):
    workspace_root_path = config.code_style_config.workspace_dir
    template_code_path = config.code_style_config.template_file
    lang = config.code_style_config.lang

    pid = problem.get_alphabet()
    problem_dir_path = os.path.join(workspace_root_path,
                                    problem.get_contest().get_id(), pid)

    def emit_error(text):
        logger.error(with_color("Problem {}: {}".format(pid, text), Fore.RED))

    def emit_warning(text):
        logger.warning("Problem {}: {}".format(pid, text))

    def emit_info(text):
        logger.info("Problem {}: {}".format(pid, text))

    emit_info('{} is used for template'.format(template_code_path))

    original_html = atcoder_client.download_problem_content_raw_html(problem)
    constants = predict_constants(original_html)

    if constants.judge_method.judge_type != JudgeType.Interactive:
        # Fetch problem data from the statement
        try:
            content = get_problem_content(original_html)
        except InputFormatDetectionError as e:
            emit_error("Failed to download input format.")
            raise e
        except SampleDetectionError as e:
            emit_error("Failed to download samples.")
            raise e

        # Store examples to the directory path
        if len(content.get_samples()) == 0:
            emit_info("No samples.")
        else:
            os.makedirs(problem_dir_path, exist_ok=True)
            create_examples(content.get_samples(), problem_dir_path,
                            config.etc_config.in_example_format,
                            config.etc_config.out_example_format)
            emit_info("Created examples.")

    code_file_path = os.path.join(problem_dir_path,
                                  "main.{}".format(lang.extension))

    # If there is an existing code, just create backup
    if os.path.exists(code_file_path):
        backup_id = 1
        while True:
            backup_name = "{}.{}".format(code_file_path, backup_id)
            if not os.path.exists(backup_name):
                new_path = backup_name
                shutil.copy(code_file_path, backup_name)
                break
            backup_id += 1
        emit_info("Backup for existing code '{}' -> '{}'".format(
            code_file_path, new_path))

    if constants.judge_method.judge_type != JudgeType.Interactive:
        try:
            prediction_result = predict_format(content)
            emit_info(
                with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
        except (NoPredictionResultError, MultiplePredictionResultsError) as e:
            prediction_result = FormatPredictionResult.empty_result()
            if isinstance(e, NoPredictionResultError):
                msg = "No prediction -- Failed to understand the input format"
            else:
                msg = "Too many prediction -- Failed to understand the input format"
            emit_warning(with_color(msg, Fore.LIGHTRED_EX))
    else:
        prediction_result = FormatPredictionResult.empty_result()

    code_generator = config.code_style_config.code_generator
    with open(template_code_path, "r") as f:
        template = f.read()

    create_code(
        code_generator(
            CodeGenArgs(template, prediction_result.format, constants,
                        config.code_style_config)), code_file_path)
    emit_info("Saved code to {}".format(code_file_path))

    # Save metadata
    metadata_path = os.path.join(problem_dir_path, "metadata.json")
    Metadata(
        problem,
        os.path.basename(code_file_path),
        config.etc_config.in_example_format.replace("{}", "*"),
        config.etc_config.out_example_format.replace("{}", "*"),
        lang,
        constants.judge_method,
    ).save_to(metadata_path)
    emit_info("Saved metadata to {}".format(metadata_path))

    if config.postprocess_config.exec_cmd_on_problem_dir is not None:
        emit_info(
            _message_on_execution(
                problem_dir_path,
                config.postprocess_config.exec_cmd_on_problem_dir))
        config.postprocess_config.execute_on_problem_dir(problem_dir_path)

    output_splitter()
Beispiel #17
0
 def download_problem_content_raw_html(self, problem: Problem) -> str:
     resp = self._request(problem.get_url())
     return resp.text
Beispiel #18
0
 def test_download_problem_content(self):
     content = self.client.download_problem_content(
         Problem(Contest("arc002"), "C", "arc002_3"))
     self.assertEqual("N\nc_{1}c_{2}...c_{N}\n", content.input_format_text)
     self.assertEqual(3, len(content.samples))
Beispiel #19
0
def prepare_procedure(atcoder_client: AtCoderClient,
                      problem: Problem,
                      config: Config):
    workspace_root_path = config.code_style_config.workspace_dir
    template_code_path = config.code_style_config.template_file
    lang = config.code_style_config.lang

    pid = problem.get_alphabet()
    problem_dir_path = os.path.join(
        workspace_root_path,
        problem.get_contest().get_id(),
        pid)

    def emit_error(text):
        logging.error(with_color("Problem {}: {}".format(pid, text), Fore.RED))

    def emit_warning(text):
        logging.warning("Problem {}: {}".format(pid, text))

    def emit_info(text):
        logging.info("Problem {}: {}".format(pid, text))

    emit_info('{} is used for template'.format(template_code_path))

    # Fetch problem data from the statement
    try:
        content = atcoder_client.download_problem_content(problem)
    except InputFormatDetectionError as e:
        emit_error("Failed to download input format.")
        raise e
    except SampleDetectionError as e:
        emit_error("Failed to download samples.")
        raise e

    # Store examples to the directory path
    if len(content.get_samples()) == 0:
        emit_info("No samples.")
    else:
        os.makedirs(problem_dir_path, exist_ok=True)
        create_examples(content.get_samples(), problem_dir_path,
                        IN_EXAMPLE_FORMAT, OUT_EXAMPLE_FORMAT)
        emit_info("Created examples.")

    code_file_path = os.path.join(
        problem_dir_path,
        "main.{}".format(lang.extension))

    # If there is an existing code, just create backup
    if os.path.exists(code_file_path):
        backup_id = 1
        while True:
            backup_name = "{}.{}".format(code_file_path, backup_id)
            if not os.path.exists(backup_name):
                new_path = backup_name
                shutil.copy(code_file_path, backup_name)
                break
            backup_id += 1
        emit_info(
            "Backup for existing code '{}' -> '{}'".format(
                code_file_path,
                new_path))

    try:
        prediction_result = predict_format(content)
        emit_info(
            with_color("Format prediction succeeded", Fore.LIGHTGREEN_EX))
    except (NoPredictionResultError, MultiplePredictionResultsError) as e:
        prediction_result = FormatPredictionResult.empty_result()
        if isinstance(e, NoPredictionResultError):
            msg = "No prediction -- Failed to understand the input format"
        else:
            msg = "Too many prediction -- Failed to understand the input format"
        emit_warning(with_color(msg, Fore.LIGHTRED_EX))

    constants = predict_constants(content.original_html)
    code_generator = config.code_style_config.code_generator
    with open(template_code_path, "r") as f:
        template = f.read()

    create_code(code_generator(
        CodeGenArgs(
            template,
            prediction_result.format,
            constants,
            config.code_style_config
        )),
        code_file_path)
    emit_info("Saved code to {}".format(code_file_path))

    # Save metadata
    metadata_path = os.path.join(problem_dir_path, "metadata.json")
    Metadata(problem,
             os.path.basename(code_file_path),
             IN_EXAMPLE_FORMAT.replace("{}", "*"),
             OUT_EXAMPLE_FORMAT.replace("{}", "*"),
             lang,
             ).save_to(metadata_path)
    emit_info("Saved metadata to {}".format(metadata_path))

    if config.postprocess_config.exec_cmd_on_problem_dir is not None:
        emit_info(_message_on_execution(problem_dir_path,
                                        config.postprocess_config.exec_cmd_on_problem_dir))
        config.postprocess_config.execute_on_problem_dir(
            problem_dir_path)

    output_splitter()