Skip to content

Commit

Permalink
#464: make breaking changes on onlinejudge.type
Browse files Browse the repository at this point in the history
  • Loading branch information
kmyk committed Aug 21, 2019
1 parent 67e5cc1 commit 4128bee
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
15 changes: 14 additions & 1 deletion onlinejudge/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from typing import List, Optional, Type

import onlinejudge._implementation.logging as log
from onlinejudge.type import Problem, Service, Submission
from onlinejudge.type import Contest, Problem, Service, Submission

submissions = [] # type: List[Type['Submission']]

Expand Down Expand Up @@ -61,6 +61,19 @@ def problem_from_url(url: str) -> Optional[Problem]:
return None


contests = [] # type: List[Type['Contest']]


def contest_from_url(url: str) -> Optional[Contest]:
for cls in contests:
contest = cls.from_url(url)
if contest is not None:
log.status('contest recognized: %s: %s', str(contest), url)
return contest
log.failure('unknown contest: %s', url)
return None


services = [] # type: List[Type['Service']]


Expand Down
76 changes: 60 additions & 16 deletions onlinejudge/type.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Python Version: 3.x
from abc import ABC, abstractmethod
from typing import Callable, List, NamedTuple, NewType, Optional, Tuple
from typing import Any, Callable, Iterator, List, NamedTuple, NewType, Optional, Tuple

import requests

Expand All @@ -12,14 +12,14 @@ class LoginError(RuntimeError):


class Service(ABC):
def login(self, get_credentials: CredentialsProvider, session: Optional[requests.Session] = None) -> None:
def login(self, *, get_credentials: CredentialsProvider, session: Optional[requests.Session] = None) -> None:
"""
:param get_credentials: returns a tuple of (username, password)
:raises LoginError:
"""
raise NotImplementedError

def is_logged_in(self, session: Optional[requests.Session] = None) -> bool:
def is_logged_in(self, *, session: Optional[requests.Session] = None) -> bool:
raise NotImplementedError

@abstractmethod
Expand Down Expand Up @@ -50,13 +50,16 @@ def __eq__(self, other) -> bool:
def from_url(self, s: str) -> Optional['Service']:
pass

def iterate_contests(self, *, session: Optional[requests.Session] = None) -> Iterator['Contest']:
raise NotImplementedError


TestCase = NamedTuple('TestCase', [
('name', str),
('input_name', str),
('input_data', bytes),
('output_name', Optional[str]),
('output_data', Optional[bytes]),
('output_name', str),
('output_data', bytes),
])

LanguageId = NewType('LanguageId', str)
Expand All @@ -78,25 +81,60 @@ class NotLoggedInError(RuntimeError):
pass


class SampleParsingError(RuntimeError):
pass


class SubmissionError(RuntimeError):
pass


class Contest(ABC):
"""
:note: :py:class:`Contest` represents just a URL of a contest, without the data of the contest.
"""
def download_name(self, *, session: Optional[requests.Session] = None) -> str:
content = self.download_content(session=session) # type: Any
return content.name

def list_problems(self, *, session: Optional[requests.Session] = None) -> List['Problem']:
content = self.download_content(session=session) # type: Any
return content.problems

def download_content(self, *, session: Optional[requests.Session] = None) -> tuple:
"""
:note: The returned values vary depending on the implementation.
"""
raise NotImplementedError

def iterate_submissions(self, *, session: Optional[requests.Session] = None) -> Iterator['Submission']:
raise NotImplementedError

@classmethod
@abstractmethod
def from_url(self, s: str) -> Optional['Contest']:
pass


class Problem(ABC):
"""
:note: :py:class:`Problem` represents just a URL of a problem, without the data of the problem.
:py:class:`Problem` はちょうど問題の URL のみを表現します。キャッシュや内部状態は持ちません。
"""
@abstractmethod
def download_sample_cases(self, session: Optional[requests.Session] = None) -> List[TestCase]:
def download_sample_cases(self, *, session: Optional[requests.Session] = None) -> List[TestCase]:
"""
:raises SampleParsingError:
"""
raise NotImplementedError

def download_system_cases(self, session: Optional[requests.Session] = None) -> List[TestCase]:
def download_system_cases(self, *, session: Optional[requests.Session] = None) -> List[TestCase]:
"""
:raises NotLoggedInError:
"""
raise NotImplementedError

def submit_code(self, code: bytes, language_id: LanguageId, filename: Optional[str] = None, session: Optional[requests.Session] = None) -> 'Submission':
def submit_code(self, code: bytes, language_id: LanguageId, *, filename: Optional[str] = None, session: Optional[requests.Session] = None) -> 'Submission':
"""
:param code:
:arg language_id: :py:class:`LanguageId`
Expand All @@ -105,7 +143,7 @@ def submit_code(self, code: bytes, language_id: LanguageId, filename: Optional[s
"""
raise NotImplementedError

def get_available_languages(self, session: Optional[requests.Session] = None) -> List[Language]:
def get_available_languages(self, *, session: Optional[requests.Session] = None) -> List[Language]:
raise NotImplementedError

@abstractmethod
Expand All @@ -116,21 +154,21 @@ def get_url(self) -> str:
def get_service(self) -> Service:
raise NotImplementedError

def get_name(self) -> str:
def download_name(self, *, session: Optional[requests.Session] = None) -> str:
"""
example:
- `器物損壊!高橋君`
- `AtCoDeerくんと変なじゃんけん / AtCoDeer and Rock-Paper`
- `Xor Sum`
"""
raise NotImplementedError
content = self.download_content(session=session) # type: Any
return content.name

def get_input_format(self, session: Optional[requests.Session] = None) -> Optional[str]:
def download_content(self, *, session: Optional[requests.Session] = None) -> tuple:
"""
:return: the HTML in the `<pre>` tag as :py:class:`str`
:note: The returned values vary depending on the implementation.
"""

raise NotImplementedError

def __repr__(self) -> str:
Expand All @@ -146,8 +184,14 @@ def from_url(self, s: str) -> Optional['Problem']:


class Submission(ABC):
@abstractmethod
def download_code(self, session: Optional[requests.Session] = None) -> bytes:
def download_code(self, *, session: Optional[requests.Session] = None) -> bytes:
content = self.download_content(session=session) # type: Any
return content.source_code

def download_content(self, *, session: Optional[requests.Session] = None) -> tuple:
"""
:note: The returned values vary depending on the implementation.
"""
raise NotImplementedError

@abstractmethod
Expand Down

0 comments on commit 4128bee

Please sign in to comment.