|
import collections.abc |
|
from dataclasses import dataclass |
|
from typing import Union, Mapping, Literal, Callable, Tuple, List, Optional |
|
|
|
LangTyping = Literal['en', 'cn'] |
|
MultiLangCheckerTyping = Callable[[str, str, str, str], Tuple[bool, Optional[str]]] |
|
SingleLangCheckerTyping = Callable[[str, str, str], Tuple[bool, Optional[str]]] |
|
|
|
|
|
@dataclass |
|
class Question: |
|
texts: Mapping[str, str] |
|
checker: MultiLangCheckerTyping |
|
names: Mapping[str, str] |
|
level: int |
|
|
|
|
|
_KNOWN_PROBLEMS = [] |
|
|
|
class Checker: |
|
|
|
def __init__(self, checkers, required_input_keys=None) -> None: |
|
self._origin_checkers = checkers |
|
if isinstance(checkers, collections.abc.Mapping): |
|
self.checker = self._integrated_checker |
|
else: |
|
self.checker = checkers |
|
|
|
if required_input_keys == None: |
|
required_input_keys = ['question_text', 'user_text', 'answer_text', 'lang'] |
|
self.required_input_keys = required_input_keys |
|
|
|
def _integrated_checker(self, question_text: str, user_text: str, answer_text: str, lang: str): |
|
return self._origin_checkers[lang](question_text, user_text, answer_text) |
|
|
|
def __call__(self, inputs): |
|
return self.checker(*[inputs[key] for key in self.required_input_keys]) |
|
|
|
def register_question(text: Union[Mapping[str, str], str], |
|
checkers: Union[Mapping[str, SingleLangCheckerTyping], MultiLangCheckerTyping], |
|
name=Union[Mapping[str, str], str], |
|
level: int = 1, default_lang='cn'): |
|
|
|
checker = checkers if isinstance(checkers, Checker) else Checker(checkers) |
|
|
|
if isinstance(text, str): |
|
texts = {default_lang: text} |
|
else: |
|
texts = text |
|
|
|
if isinstance(name, str): |
|
names = {default_lang: name} |
|
else: |
|
names = name |
|
|
|
_KNOWN_PROBLEMS.append(Question(texts, checker, names, level)) |
|
|
|
|
|
def list_ordered_questions() -> List[Question]: |
|
return [ |
|
problem for _, problem in |
|
sorted(enumerate(_KNOWN_PROBLEMS), key=lambda x: (x[1].level, x[0])) |
|
] |
|
|