From 267ef2e7c24786705f7326b44f551349c67fabea Mon Sep 17 00:00:00 2001 From: takeaship Date: Sun, 17 Apr 2022 21:11:28 +0900 Subject: [PATCH] add algo-method support (get-problem only) --- README.md | 1 + onlinejudge/service/__init__.py | 1 + onlinejudge/service/algo_method.py | 81 ++++++++++++++++++++++++++++++ onlinejudge_api/main.py | 1 + tests/get_problem_algo_method.py | 65 ++++++++++++++++++++++++ 5 files changed, 149 insertions(+) create mode 100644 onlinejudge/service/algo_method.py create mode 100644 tests/get_problem_algo_method.py diff --git a/README.md b/README.md index 823ee65..a7758e1 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ $ pip3 install online-judge-api-client | website | get sample cases | get system cases | get metadata | get contest data | login service | submit code | |--------------------------------------------------------------------------------|--------------------|--------------------|--------------------|--------------------|--------------------|--------------------| +| [Algo-Method](https://algo-method.com) | :heavy_check_mark: | | | | | | | [Aizu Online Judge](https://onlinejudge.u-aizu.ac.jp/home) | :heavy_check_mark: | :heavy_check_mark: | | | | | | [Anarchy Golf](http://golf.shinh.org/) | :heavy_check_mark: | :grey_question: (same to samples) | | | | | | [AtCoder](https://atcoder.jp/) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | diff --git a/onlinejudge/service/__init__.py b/onlinejudge/service/__init__.py index a23ff82..b5e88cd 100644 --- a/onlinejudge/service/__init__.py +++ b/onlinejudge/service/__init__.py @@ -1,4 +1,5 @@ # Python Version: 3.x +import onlinejudge.service.algo_method import onlinejudge.service.anarchygolf import onlinejudge.service.aoj import onlinejudge.service.atcoder diff --git a/onlinejudge/service/algo_method.py b/onlinejudge/service/algo_method.py new file mode 100644 index 0000000..a0e19f5 --- /dev/null +++ b/onlinejudge/service/algo_method.py @@ -0,0 +1,81 @@ +# Python Version: 3.x +# -*- coding: utf-8 -*- +""" +the module for Algo-Method (https://algo-method.com/) +""" + +import json +import posixpath +import re +import urllib.parse +from typing import * + +import bs4 +import requests + +import onlinejudge._implementation.testcase_zipper +import onlinejudge._implementation.utils as utils +import onlinejudge.dispatch +import onlinejudge.type + + +class AlgoMethodService(onlinejudge.type.Service): + def get_url(self) -> str: + return 'https://algo-method.com/' + + def get_name(self) -> str: + return 'algo-method' + + @classmethod + def from_url(cls, url: str) -> Optional['AlgoMethodService']: + # example: https://algo-method.com/ + result = urllib.parse.urlparse(url) + if result.scheme in ('', 'http', 'https') \ + and result.netloc == 'algo-method.com': + return cls() + return None + + +class AlgoMethodProblem(onlinejudge.type.Problem): + def __init__(self, *, problem_id: str): + self.problem_id = problem_id + + def download_sample_cases(self, *, session: Optional[requests.Session] = None) -> List[onlinejudge.type.TestCase]: + session = session or utils.get_default_session() + # get + resp = utils.request('GET', self.get_url(), session=session) + # parse + soup = bs4.BeautifulSoup(resp.text, utils.HTML_PARSER) + samples = onlinejudge._implementation.testcase_zipper.SampleZipper() + for case, name in self._parse_sample_cases(soup): + samples.add(case.encode(), name) + return samples.get() + + def _parse_sample_cases(self, soup: bs4.BeautifulSoup) -> Generator[Tuple[str, str], None, None]: + body_md = json.loads(soup.find(id='__NEXT_DATA__').get_text())['props']['pageProps']['tasks']['body'] + pattern = r'#### ([入出]力例 \d ?)\r\n```IOExample\r\n([\s\S]+?)```' + cases = re.findall(pattern, body_md) + for name, case in cases: + yield (utils.dos2unix(case), name) + + def get_url(self) -> str: + return 'https://algo-method.com/tasks/{}'.format(self.problem_id) + + def get_service(self) -> AlgoMethodService: + return AlgoMethodService() + + @classmethod + def from_url(cls, url: str) -> Optional['AlgoMethodProblem']: + # example: https://algo-method.com/tasks/15 + result = urllib.parse.urlparse(url) + dirname, basename = posixpath.split(utils.normpath(result.path)) + if result.scheme in ('', 'http', 'https') \ + and result.netloc == 'algo-method.com' \ + and dirname == '/tasks' \ + and basename: + return cls(problem_id=basename) + return None + + +onlinejudge.dispatch.services += [AlgoMethodService] +onlinejudge.dispatch.problems += [AlgoMethodProblem] diff --git a/onlinejudge_api/main.py b/onlinejudge_api/main.py index 30a0685..ba50f93 100644 --- a/onlinejudge_api/main.py +++ b/onlinejudge_api/main.py @@ -58,6 +58,7 @@ def get_parser() -> argparse.ArgumentParser: # get-problem epilog = textwrap.dedent("""\ supported services: + Algo-Method Aizu Online Judge Anarchy Golf AtCoder diff --git a/tests/get_problem_algo_method.py b/tests/get_problem_algo_method.py new file mode 100644 index 0000000..2b43a82 --- /dev/null +++ b/tests/get_problem_algo_method.py @@ -0,0 +1,65 @@ +import unittest + +from onlinejudge_api.main import main + + +class GetProblemAlgoMethodTest(unittest.TestCase): + def test_tasks_22(self): + url = 'https://algo-method.com/tasks/22' + expected = { + "status": "ok", + "messages": [], + "result": { + "url": "https://algo-method.com/tasks/22", + "tests": [ + { + "input": "power\n", + "output": "w\n" + }, + { + "input": "otter\n", + "output": "t\n" + }, + ], + "context": {} + }, + } + actual = main(['get-problem', url], debug=True) + self.assertEqual(expected, actual) + + def test_tasks_24(self): + url = 'https://algo-method.com/tasks/24' + expected = { + "status": "ok", + "messages": [], + "result": { + "url": "https://algo-method.com/tasks/24", + "tests": [{ + "input": "1 2\n", + "output": "3\n" + }], + "context": {} + }, + } + actual = main(['get-problem', url], debug=True) + self.assertEqual(expected, actual) + + def test_tasks_529(self): + url = 'https://algo-method.com/tasks/529' + expected = { + "status": "ok", + "messages": [], + "result": { + "url": "https://algo-method.com/tasks/529", + "tests": [{ + "input": "7\n0 1 0 0 1 5\n", + "output": "0\n1\n2\n1\n1\n2\n3\n" + }, { + "input": "7\n0 0 0 0 0 0\n", + "output": "0\n1\n1\n1\n1\n1\n1\n" + }], + "context": {} + }, + } + actual = main(['get-problem', url], debug=True) + self.assertEqual(expected, actual)