Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setterを追加 #249

Merged
merged 5 commits into from
Nov 29, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion atcodertools/atcoder_tools.py
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
from atcodertools.tools.submit import main as submit_main
from atcodertools.tools.codegen import main as codegen_main
from atcodertools.tools.compiler import main as compiler_main
from atcodertools.tools.setter import main as setter_main
from atcodertools.release_management.version import __version__
from colorama import Fore, Style

@@ -39,14 +40,16 @@ def notify_if_latest_version_found():
def main():
notify_if_latest_version_found()

if len(sys.argv) < 2 or sys.argv[1] not in ("gen", "test", "submit", "codegen", "compile", "version"):
if len(sys.argv) < 2 or sys.argv[1] not in ("gen", "test", "submit", "codegen", "compile", "set", "version"):
print("Usage:")
print("{} gen -- to generate workspace".format(sys.argv[0]))
print(
"{} compile -- to compile codes in your workspace".format(sys.argv[0]))
print("{} test -- to test codes in your workspace".format(sys.argv[0]))
print(
"{} submit -- to submit a code to the contest system".format(sys.argv[0]))
print(
"{} set -- to set some additional option(error value, language)".format(sys.argv[0]))
print(
"{} version -- show atcoder-tools version".format(sys.argv[0]))
sys.exit(-1)
@@ -69,5 +72,8 @@ def main():
if sys.argv[1] == "compile":
compiler_main(prog, args)

if sys.argv[1] == "set":
setter_main(prog, args)

if sys.argv[1] == "version":
print(__version__)
2 changes: 1 addition & 1 deletion atcodertools/client/atcoder.py
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ def login(self,
"csrf_token": token
}, method='POST')

if resp.text.find("パスワードを忘れた方はこちら") != -1:
if resp.text.find("パスワードを忘れた方はこちら") != -1 or resp.text.find("Forgot your password") != -1:
raise LoginError

if use_local_session_cache and save_session_cache:
7 changes: 7 additions & 0 deletions atcodertools/common/judgetype.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,13 @@ class ErrorType(Enum):
AbsoluteOrRelative = "absolute_or_relative"


DEFAULT_EPS = 1e-9


class NoJudgeTypeException(Exception):
pass


class Judge(metaclass=ABCMeta):
@abstractmethod
def verify(self, output, expected):
2 changes: 1 addition & 1 deletion atcodertools/tools/codegen.py
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ def main(prog, args, output_file=sys.stdout):
config = get_config(args)

client = AtCoderClient()
if not config.etc_config.download_without_login:
if not args.without_login or not config.etc_config.download_without_login:
try:
client.login(
save_session_cache=not config.etc_config.save_no_session_cache)
102 changes: 102 additions & 0 deletions atcodertools/tools/setter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/python3

import argparse
import os
from atcodertools.common.judgetype import NormalJudge, DecimalJudge, ErrorType,\
JudgeType, NoJudgeTypeException, DEFAULT_EPS
from atcodertools.common.logging import logger
from atcodertools.tools.models.metadata import Metadata
from atcodertools.common.language import Language, ALL_LANGUAGES
from atcodertools.tools.codegen import main as codegen_main

USER_FACING_JUDGE_TYPE_LIST = [
"normal", "absolute", "relative", "absolute_or_relative"]


def main(prog, args) -> None:
if len(args) == 0:
print("Usage: atcoder tools set [options]")
return

parser = argparse.ArgumentParser(
prog=prog,
formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('--judge-type', '-j',
help='error type'
' must be one of [{}]'.format(
', '.join(USER_FACING_JUDGE_TYPE_LIST)),
type=str,
default=None)

parser.add_argument('--error-value', '-v',
help='error value for decimal number judge:'
' [Default] ' + str(DEFAULT_EPS),
type=float,
default=None)

parser.add_argument("--lang", '-l',
help="Programming language of your template code, {}.\n".format(
" or ".join([lang.name for lang in ALL_LANGUAGES])),
default=None)

parser.add_argument("--dir", '-d',
help="Target directory to test. [Default] Current directory",
default=".")

parser.add_argument("--without-login",
action="store_true",
help="Download data without login")

args = parser.parse_args(args)

old_metadata = Metadata.load_from(os.path.join(args.dir, "metadata.json"))

# Use the old metadata as base metadata.
output_metadata = Metadata.load_from(
os.path.join(args.dir, "metadata.json"))

old_metadata_judge_type = old_metadata.judge_method.judge_type.value

if args.judge_type in ["absolute", "relative", "absolute_or_relative"]:
new_metadata_judge_type = "decimal"
output_metadata.judge_method.error_type = ErrorType(args.judge_type)
elif args.judge_type is not None:
new_metadata_judge_type = args.judge_type
else:
new_metadata_judge_type = old_metadata_judge_type

if new_metadata_judge_type is not None and new_metadata_judge_type != old_metadata_judge_type:
if new_metadata_judge_type == JudgeType.Normal.value:
output_metadata.judge_method = NormalJudge()
elif new_metadata_judge_type == JudgeType.Decimal.value:
output_metadata.judge_method = DecimalJudge()
if args.error_value is None:
logger.warn(
"Error-value is not specified. DEFAULT_EPS is set")
output_metadata.judge_method.diff = DEFAULT_EPS
else:
raise NoJudgeTypeException()

if new_metadata_judge_type == JudgeType.Decimal.value and args.error_value is not None:
output_metadata.judge_method.diff = args.error_value

if args.lang is not None:
if args.lang != output_metadata.lang.name:
output_metadata.lang = Language.from_name(args.lang)
output_metadata.code_filename = output_metadata.lang.get_code_filename(
'main')
url = "https://atcoder.jp/contests/{}/tasks/{}".format(
output_metadata.problem.contest.contest_id, output_metadata.problem.problem_id)
main_code_filename = os.path.join(
args.dir, output_metadata.code_filename)
if not os.path.exists(main_code_filename):
a = ["--lang", output_metadata.lang.name, url]
if args.without_login:
a.append("--without-login")
codegen_main("", a, open(main_code_filename, 'w'))
else:
print("File exists: ", output_metadata.code_filename)
else:
print("Already set to {}. Skipping changing language...".format(args.lang))
output_metadata.save_to(os.path.join(args.dir, "metadata.json"))
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Kyuuridenamida
19 changes: 19 additions & 0 deletions tests/resources/test_setter/ans/main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import java.io.*;
import java.util.*;

class Main {

// Generated by 2.9.0 https://github.com/kyuridenamida/atcoder-tools (tips: You use the default template now. You can remove this line by using your custom template)
public static void main(String[] args) throws Exception {
final Scanner sc = new Scanner(System.in);
long T;
T = sc.nextLong();
long X;
X = sc.nextLong();
solve(T, X);
}

static void solve(long T, long X){

}
}
18 changes: 18 additions & 0 deletions tests/resources/test_setter/ans/metadata_change_error_value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"code_filename": "main.java",
"judge": {
"diff": 1e-07,
"error_type": "relative",
"judge_type": "decimal"
},
"lang": "java",
"problem": {
"alphabet": "A",
"contest": {
"contest_id": "abc117"
},
"problem_id": "abc117_a"
},
"sample_in_pattern": "in_*.txt",
"sample_out_pattern": "out_*.txt"
}
18 changes: 18 additions & 0 deletions tests/resources/test_setter/ans/metadata_change_to_relative.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"code_filename": "main.java",
"judge": {
"diff": 0.001,
"error_type": "relative",
"judge_type": "decimal"
},
"lang": "java",
"problem": {
"alphabet": "A",
"contest": {
"contest_id": "abc117"
},
"problem_id": "abc117_a"
},
"sample_in_pattern": "in_*.txt",
"sample_out_pattern": "out_*.txt"
}
18 changes: 18 additions & 0 deletions tests/resources/test_setter/ans/metadata_java.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"code_filename": "main.java",
"judge": {
"diff": 0.001,
"error_type": "absolute_or_relative",
"judge_type": "decimal"
},
"lang": "java",
"problem": {
"alphabet": "A",
"contest": {
"contest_id": "abc117"
},
"problem_id": "abc117_a"
},
"sample_in_pattern": "in_*.txt",
"sample_out_pattern": "out_*.txt"
}
35 changes: 35 additions & 0 deletions tests/resources/test_setter/test/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <cassert>
using namespace std;


void solve(long long T, long long X){

}

// Generated by 2.9.0 https://github.com/kyuridenamida/atcoder-tools (tips: You use the default template now. You can remove this line by using your custom template)
int main(){
long long T;
std::scanf("%lld", &T);
long long X;
std::scanf("%lld", &X);
solve(T, X);
return 0;
}
18 changes: 18 additions & 0 deletions tests/resources/test_setter/test/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"code_filename": "main.cpp",
"judge": {
"diff": 0.001,
"error_type": "absolute_or_relative",
"judge_type": "decimal"
},
"lang": "cpp",
"problem": {
"alphabet": "A",
"contest": {
"contest_id": "abc117"
},
"problem_id": "abc117_a"
},
"sample_in_pattern": "in_*.txt",
"sample_out_pattern": "out_*.txt"
}
72 changes: 72 additions & 0 deletions tests/test_setter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
import shutil
import tempfile
import unittest
from os.path import relpath
from logging import getLogger

from atcodertools.tools.setter import main

logger = getLogger(__name__)

RESOURCE_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"./resources/test_setter/")
TEMPLATE_PATH = os.path.join(RESOURCE_DIR, "template.cpp")
REPLACEMENT_PATH = os.path.join(RESOURCE_DIR, "replacement.cpp")


def get_all_rel_file_paths(dir_path: str):
res = []
for root, _, filenames in os.walk(dir_path):
for filename in filenames:
res.append(relpath(os.path.join(root, filename), dir_path))
return sorted(res)


class TestSetter(unittest.TestCase):

def setUp(self):
self.temp_dir = tempfile.mkdtemp()

def tearDown(self):
shutil.rmtree(self.temp_dir)
logger.info(self.temp_dir)

def test_setter_change_lang(self):
test_dir = os.path.join(self.temp_dir, "test_setter")
shutil.copytree(os.path.join(RESOURCE_DIR, "test"), test_dir)
# abc117A

main(
"",
["--lang", "java",
"--dir", test_dir,
"--without-login"]
)
self.assertEqual(open(os.path.join(test_dir, "main.java")).read(),
open(os.path.join(RESOURCE_DIR, "ans", "main.java")).read())
self.assertEqual(open(os.path.join(test_dir, "metadata.json")).read(),
open(os.path.join(RESOURCE_DIR, "ans", "metadata_java.json")).read())

main(
"",
["--judge-type", "relative",
"--dir", test_dir]
)

self.assertEqual(open(os.path.join(test_dir, "metadata.json")).read(),
open(os.path.join(RESOURCE_DIR, "ans", "metadata_change_to_relative.json")).read())

main(
"",
["--error-value", "1e-7",
"--dir", test_dir]
)

self.assertEqual(open(os.path.join(test_dir, "metadata.json")).read(),
open(os.path.join(RESOURCE_DIR, "ans", "metadata_change_error_value.json")).read())


if __name__ == '__main__':
unittest.main()