Пример #1
0
 def test_problem_from_url(self):
     self.assertIsNone(
         dispatch.problem_from_url('https://atcoder.jp/contests/agc039'))
     self.assertIsNone(
         dispatch.problem_from_url("https://yukicoder.me/contests/241/"))
     self.assertIsNone(
         dispatch.problem_from_url(
             'https://atcoder.jp/contests/abc143/submissions/8059168'))
Пример #2
0
 def test_problem_from_url(self):
     problem = dispatch.problem_from_url(
         'https://codeforces.com/contest/1244/problem/C')
     self.assertTrue(
         isinstance(problem, service.codeforces.CodeforcesProblem))
     self.assertTrue(
         isinstance(problem.get_service(),
                    service.codeforces.CodeforcesService))
Пример #3
0
 def test_problem_from_url(self):
     problem = dispatch.problem_from_url('https://atcoder.jp/contests/arc001/tasks/arc001_1')
     self.assertIsInstance(problem, service.atcoder.AtCoderProblem)
     self.assertEqual(problem.get_url(), 'https://atcoder.jp/contests/arc001/tasks/arc001_1')
     self.assertEqual(problem.get_url(lang='ja'), 'https://atcoder.jp/contests/arc001/tasks/arc001_1?lang=ja')
     self.assertIsInstance(problem.get_service(), service.atcoder.AtCoderService)
     self.assertEqual(problem.download_input_format(), '\r\n<var>N</var>\r\n<var>c_1c_2c_3…c_N</var>\r\n')
     self.assertEqual(problem.get_name(), 'センター採点')
Пример #4
0
def main(args: Optional[List[str]] = None,
         *,
         debug: bool = False) -> Dict[str, Any]:
    parser = get_parser()
    parsed = parser.parse_args(args=args)

    if parsed.verbose:
        basicConfig(level=DEBUG)
    else:
        basicConfig(level=INFO)

    # do sleep to prevent impolite scraping
    logger.info('sleep %f sec', parsed.wait)
    time.sleep(parsed.wait)

    # parse the URL
    problem = dispatch.problem_from_url(getattr(parsed, 'url', ''))
    contest = dispatch.contest_from_url(getattr(parsed, 'url', ''))
    service = dispatch.service_from_url(getattr(parsed, 'url', ''))

    # prepare a session
    session = requests.Session()
    session.headers['User-Agent'] = parsed.user_agent

    # set yukicoder's token
    if parsed.yukicoder_token is not None:
        parser.error("don't use --yukicoder-token. use $YUKICODER_TOKEN")
    else:
        parsed.yukicoder_token = os.environ.get('YUKICODER_TOKEN')
        is_yukicoder = isinstance(problem, YukicoderProblem) or isinstance(
            service, YukicoderService)
        if parsed.yukicoder_token and is_yukicoder:
            session.headers['Authorization'] = 'Bearer {}'.format(
                parsed.yukicoder_token)

    # set password to login from the environment variable
    if parsed.subcommand == 'login-service':
        if parsed.password is not None:
            parser.error("don't use --password. use $PASSWORD")
        else:
            parsed.password = os.environ.get('PASSWORD')

    try:
        with utils.with_cookiejar(session, path=parsed.cookie) as session:
            result = None  # type: Optional[Dict[str, Any]]
            schema = {}  # type: Dict[str, Any]

            if parsed.subcommand == 'get-problem':
                if problem is None:
                    raise ValueError("unsupported URL: {}".format(
                        repr(parsed.url)))
                result = get_problem.main(
                    problem,
                    is_system=parsed.system,
                    is_full=parsed.full,
                    is_compatibility=parsed.compatibility,
                    session=session)
                if parsed.compatibility:
                    schema = get_problem.schema_compatibility
                else:
                    schema = get_problem.schema

            elif parsed.subcommand == 'get-contest':
                if contest is None:
                    raise ValueError("unsupported URL: {}".format(
                        repr(parsed.url)))
                result = get_contest.main(contest,
                                          is_full=parsed.full,
                                          session=session)
                schema = get_contest.schema

            elif parsed.subcommand == 'get-service':
                if service is None:
                    raise ValueError("unsupported URL: {}".format(
                        repr(parsed.url)))
                result = get_service.main(
                    service,
                    does_list_contests=parsed.list_contests,
                    session=session)
                schema = get_service.schema

            elif parsed.subcommand == 'login-service':
                if service is None:
                    raise ValueError("unsupported URL: {}".format(
                        repr(parsed.url)))
                result = login_service.main(service,
                                            username=parsed.username,
                                            password=parsed.password,
                                            check_only=parsed.check,
                                            session=session)
                schema = login_service.schema

            elif parsed.subcommand == 'submit-code':
                if problem is None:
                    raise ValueError("unsupported URL: {}".format(
                        repr(parsed.url)))
                result = submit_code.main(problem,
                                          file=parsed.file,
                                          language_id=parsed.language,
                                          session=session)
                schema = submit_code.schema

            elif parsed.subcommand is None:
                parser.print_help()
                result = None

            else:
                assert False

    except:
        etype, evalue, _ = sys.exc_info()
        logger.exception('%s', evalue)
        wrapped = {
            "status":
            "error",
            "messages": [
                *map(lambda line: line.strip(),
                     traceback.format_exception_only(etype, evalue))
            ],
            "result":
            None,
        }  # type: Dict[str, Any]
        if debug:
            return wrapped
        else:
            print(json.dumps(wrapped))
            raise SystemExit(1)

    else:
        if result is None:
            # no subcommand given
            if debug:
                return {
                    "status": "ok",
                    "messages": [],
                    "result": None,
                }
            else:
                raise SystemExit(0)

        wrapped = {
            "status": "ok",
            "messages": [],
            "result": result,
        }
        if not debug:
            print(json.dumps(wrapped))

        try:
            jsonschema.validate(result, schema)
        except jsonschema.exceptions.ValidationError as e:
            logger.debug('%s', e)

        if debug:
            return wrapped
        else:
            raise SystemExit(0)
Пример #5
0
def download(args: argparse.Namespace) -> None:
    # prepare values
    problem = dispatch.problem_from_url(args.url)
    if problem is None:
        if dispatch.contest_from_url(args.url) is not None:
            logger.warning('You specified a URL for a contest instead of a problem. If you want to download for all problems of a contest at once, please try to use `oj-prepare` command of https://github.com/online-judge-tools/template-generator')
        raise requests.exceptions.InvalidURL('The URL "%s" is not supported' % args.url)
    is_default_format = args.format is None and args.directory is None  # must be here since args.directory and args.format are overwritten
    if args.directory is None:
        args.directory = pathlib.Path('test')
    if args.format is None:
        args.format = '%b.%e'

    # get samples from the server
    with utils.new_session_with_our_user_agent(path=args.cookie) as sess:
        if args.yukicoder_token and isinstance(problem, YukicoderProblem):
            sess.headers['Authorization'] = 'Bearer {}'.format(args.yukicoder_token)
        if args.system:
            samples = problem.download_system_cases(session=sess)
        else:
            samples = problem.download_sample_cases(session=sess)

    if not samples:
        raise SampleParseError("Sample not found")

    # append the history for submit subcommand
    if not args.dry_run and is_default_format:
        history = onlinejudge_command.download_history.DownloadHistory()
        if not list(args.directory.glob('*')):
            # reset the history to help users who use only one directory for many problems
            history.remove(directory=pathlib.Path.cwd())
        history.add(problem, directory=pathlib.Path.cwd())

    # prepare files to write
    def iterate_files_to_write(sample: TestCase, *, i: int) -> Iterator[Tuple[str, pathlib.Path, bytes]]:
        for ext in ['in', 'out']:
            data = getattr(sample, ext + 'put_data')
            if data is None:
                continue
            name = sample.name
            table = {}
            table['i'] = str(i + 1)
            table['e'] = ext
            table['n'] = name
            table['b'] = os.path.basename(name)
            table['d'] = os.path.dirname(name)
            path: pathlib.Path = args.directory / format_utils.percentformat(args.format, table)
            yield ext, path, data

    for i, sample in enumerate(samples):
        for _, path, _ in iterate_files_to_write(sample, i=i):
            if path.exists():
                raise FileExistsError('Failed to download since file already exists: ' + str(path))

    # write samples to files
    for i, sample in enumerate(samples):
        logger.info('')
        logger.info('sample %d', i)
        for ext, path, data in iterate_files_to_write(sample, i=i):
            content = ''
            if not args.silent:
                content = '\n' + pretty_printers.make_pretty_large_file_content(data, limit=40, head=20, tail=10, bold=True)
            logger.info('%sput: %s%s', ext, sample.name, content)
            if not args.dry_run:
                path.parent.mkdir(parents=True, exist_ok=True)
                with path.open('wb') as fh:
                    fh.write(data)
                logger.info(utils.SUCCESS + 'saved to: %s', path)

    if args.log_file:
        with args.log_file.open(mode='w') as fhs:
            json.dump(list(map(convert_sample_to_dict, samples)), fhs)
Пример #6
0
def submit(args: 'argparse.Namespace') -> None:
    # guess url
    history = onlinejudge_command.download_history.DownloadHistory()
    if args.file.parent.resolve() == pathlib.Path.cwd():
        guessed_urls = history.get(directory=pathlib.Path.cwd())
    else:
        logger.warning(
            'cannot guess URL since the given file is not in the current directory'
        )
        guessed_urls = []
    if args.url is None:
        if len(guessed_urls) == 1:
            args.url = guessed_urls[0]
            logger.info('guessed problem: %s', args.url)
        else:
            logger.error('failed to guess the URL to submit')
            logger.info('please manually specify URL as: $ oj submit URL FILE')
            sys.exit(1)

    # parse url
    problem = dispatch.problem_from_url(args.url)
    if problem is None:
        sys.exit(1)

    # read code
    with args.file.open('rb') as fh:
        code = fh.read()  # type: bytes
    format_config = {
        'dos2unix': args.format_dos2unix or args.golf,
        'rstrip': args.format_dos2unix or args.golf,
    }
    code = format_code(code, **format_config)

    # report code
    logger.info('code (%d byte):', len(code))
    logger.info(
        utils.NO_HEADER + '%s',
        utils.make_pretty_large_file_content(code,
                                             limit=30,
                                             head=10,
                                             tail=10,
                                             bold=True))

    with utils.new_session_with_our_user_agent(path=args.cookie) as sess:
        # guess or select language ids
        language_dict = {
            language.id: language.name
            for language in problem.get_available_languages(session=sess)
        }  # type: Dict[LanguageId, str]
        matched_lang_ids = None  # type: Optional[List[str]]
        if args.language in language_dict:
            matched_lang_ids = [args.language]
        else:
            if args.guess:
                kwargs = {
                    'language_dict': language_dict,
                    'cxx_latest': args.guess_cxx_latest,
                    'cxx_compiler': args.guess_cxx_compiler,
                    'python_version': args.guess_python_version,
                    'python_interpreter': args.guess_python_interpreter,
                }
                matched_lang_ids = guess_lang_ids_of_file(
                    args.file, code, **kwargs)
                if not matched_lang_ids:
                    logger.info('failed to guess languages from the file name')
                    matched_lang_ids = list(language_dict.keys())
                if args.language is not None:
                    logger.info(
                        'you can use `--no-guess` option if you want to do an unusual submission'
                    )
                    matched_lang_ids = select_ids_of_matched_languages(
                        args.language.split(),
                        matched_lang_ids,
                        language_dict=language_dict)
            else:
                if args.language is None:
                    matched_lang_ids = None
                else:
                    matched_lang_ids = select_ids_of_matched_languages(
                        args.language.split(),
                        list(language_dict.keys()),
                        language_dict=language_dict)

        # report selected language ids
        if matched_lang_ids is not None and len(matched_lang_ids) == 1:
            args.language = matched_lang_ids[0]
            logger.info('chosen language: %s (%s)', args.language,
                        language_dict[LanguageId(args.language)])
        else:
            if matched_lang_ids is None:
                logger.error('language is unknown')
                logger.info('supported languages are:')
            elif len(matched_lang_ids) == 0:
                logger.error('no languages are matched')
                logger.info('supported languages are:')
            else:
                logger.error(
                    'Matched languages were not narrowed down to one.')
                logger.info('You have to choose:')
            for lang_id in sorted(matched_lang_ids or language_dict.keys()):
                logger.info(utils.NO_HEADER + '%s (%s)', lang_id,
                            language_dict[LanguageId(lang_id)])
            sys.exit(1)

        # confirm
        guessed_unmatch = ([problem.get_url()] != guessed_urls)
        if guessed_unmatch:
            samples_text = ('samples of "{}'.format('", "'.join(guessed_urls))
                            if guessed_urls else 'no samples')
            logger.warning(
                'the problem "%s" is specified to submit, but %s were downloaded in this directory. this may be mis-operation',
                problem.get_url(), samples_text)
        if args.wait:
            logger.info('sleep(%.2f)', args.wait)
            time.sleep(args.wait)
        if not args.yes:
            if guessed_unmatch:
                problem_id = problem.get_url().rstrip('/').split(
                    '/')[-1].split('?')[-1]  # this is too ad-hoc
                key = problem_id[:3] + (problem_id[-1]
                                        if len(problem_id) >= 4 else '')
                sys.stdout.write('Are you sure? Please type "{}" '.format(key))
                sys.stdout.flush()
                c = sys.stdin.readline().rstrip()
                if c != key:
                    logger.info('terminated.')
                    return
            else:
                sys.stdout.write('Are you sure? [y/N] ')
                sys.stdout.flush()
                c = sys.stdin.read(1)
                if c.lower() != 'y':
                    logger.info('terminated.')
                    return

        # submit
        try:
            submission = problem.submit_code(code,
                                             language_id=LanguageId(
                                                 args.language),
                                             session=sess)
        except NotLoggedInError:
            logger.info(utils.FAILURE + 'login required')
            sys.exit(1)
        except SubmissionError:
            logger.info(utils.FAILURE + 'submission failed')
            sys.exit(1)

        # show result
        if args.open:
            utils.webbrowser_register_explorer_exe()
            try:
                browser = webbrowser.get()
            except webbrowser.Error as e:
                logger.error('%s', e)
                logger.info('please set the $BROWSER envvar')
            else:
                logger.info('open the submission page with browser: %s',
                            browser)
                browser.open_new_tab(submission.get_url())
Пример #7
0
 def test_problem_from_url(self):
     self.assertIsNone(
         dispatch.problem_from_url('https://atcoder.jp/contests/agc039'))
Пример #8
0
 def test_problem_eq(self):
     self.assertEqual(problem_from_url('https://codeforces.com/contest/1244/problem/C'), problem_from_url('https://codeforces.com/contest/1244/problem/C'))
     self.assertNotEqual(problem_from_url('https://codeforces.com/contest/1244/problem/C'), problem_from_url('https://codeforces.com/contest/1244/problem/B'))
     self.assertNotEqual(problem_from_url('https://codeforces.com/contest/1244/problem/C'), problem_from_url('https://atcoder.jp/contests/abc143/tasks/abc143_c'))