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'))
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))
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(), 'センター採点')
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)
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)
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())
def test_problem_from_url(self): self.assertIsNone( dispatch.problem_from_url('https://atcoder.jp/contests/agc039'))
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'))