跳转至

util

消息链处理器用到的工具函数, 类

ElementType 🔗

用于标记类型为消息链元素, 在 ArgumentMatch 上使用

Source code in src/graia/ariadne/message/parser/util.py
115
116
117
118
119
120
121
122
123
124
class ElementType:
    """用于标记类型为消息链元素, 在 ArgumentMatch 上使用"""

    def __init__(self, pattern: Type[Element_T]):
        self.regex = re.compile(f"\x02(\\d+)_{pattern.__fields__['type'].default}\x03")

    def __call__(self, string: str) -> Element:
        if not self.regex.fullmatch(string):
            raise ValueError(f"{string} not matching {self.regex.pattern}")
        return MessageChain._from_mapping_string(string, elem_mapping_ctx.get())[0]

MessageChainType 🔗

用于标记类型为消息链, 在 ArgumentMatch 上使用

Source code in src/graia/ariadne/message/parser/util.py
107
108
109
110
111
112
class MessageChainType:
    """用于标记类型为消息链, 在 ArgumentMatch 上使用"""

    @staticmethod
    def __call__(string: str) -> MessageChain:
        return MessageChain._from_mapping_string(string, elem_mapping_ctx.get())

TwilightHelpManager 🔗

Source code in src/graia/ariadne/message/parser/util.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
class TwilightHelpManager:
    AUTO_ID: Final[str] = "&auto_id" + hex(id("&auto_id"))
    _manager_ref: ClassVar[Dict[str, "TwilightHelpManager"]] = {}

    name: str
    display_name: Optional[str]
    help_map: Dict[str, "Twilight"]

    def __init__(self, name: str, display_name: Optional[str] = AUTO_ID):
        self.name: str = name
        self.help_map: Dict[str, Twilight] = {}
        if display_name == self.AUTO_ID:
            self.display_name = None if name.startswith(("global", "local", "_")) else name
        else:
            self.display_name = display_name
        if name in TwilightHelpManager._manager_ref:
            global_ref = TwilightHelpManager._manager_ref[name]
            global_ref.display_name = global_ref.display_name or display_name
            self.help_map = global_ref.help_map
        else:
            TwilightHelpManager._manager_ref[name] = self

    def register(self, twilight: "Twilight") -> None:
        if twilight.help_id == self.AUTO_ID:
            from .twilight import ElementMatch, ParamMatch, RegexMatch, UnionMatch

            extracted_ids: List[str] = []
            for match in twilight.matcher.origin_match_list:
                if isinstance(match, UnionMatch):
                    extracted_ids.extend(match.pattern)
                elif isinstance(match, ElementMatch):
                    extracted_ids.append(match.type.__name__)
                elif isinstance(match, RegexMatch) and not isinstance(match, ParamMatch):
                    extracted_ids.append(match.pattern)
            if not extracted_ids:
                raise ValueError(f"Unable to extract help_id from {twilight}")
            help_id = extracted_ids[0]
        else:
            help_id = twilight.help_id
        if help_id in self.help_map and self.help_map[help_id] is not twilight:
            raise ValueError(
                f"Help Manager {self.name}'s help id {help_id} has been registered", self.help_map[help_id]
            )
        self.help_map[help_id] = twilight

    @classmethod
    def get_help_mgr(cls, mgr: Union["TwilightHelpManager", str]) -> "TwilightHelpManager":
        return TwilightHelpManager(mgr) if isinstance(mgr, str) else mgr

    @overload
    def get_help(
        self,
        description: str = "",
        epilog: str = "",
        *,
        prefix_src: Literal["brief", "usage", "description"] = "brief",
        fmt_cls: Type[argparse.HelpFormatter] = argparse.HelpFormatter,
    ) -> str:
        ...

    @overload
    def get_help(
        self,
        description: str = "",
        epilog: str = "",
        *,
        prefix_src: Literal["brief", "usage", "description"] = "brief",
        fmt_func: Callable[[str], T],
        fmt_cls: Type[argparse.HelpFormatter] = argparse.HelpFormatter,
    ) -> T:
        ...

    def get_help(
        self,
        description: str = "",
        epilog: str = "",
        *,
        prefix_src: Literal["brief", "usage", "description"] = "brief",
        fmt_func: Optional[Callable[[str], T]] = None,
        fmt_cls: Type[argparse.HelpFormatter] = argparse.HelpFormatter,
    ) -> Union[T, str]:
        """获取本管理器总的帮助信息

        Args:
            fmt_func (Optional[Callable[[str], T]]): 如果指定, 则使用该函数来转换帮助信息格式
            fmt_cls (Type[argparse.HelpFormatter], optional): 如果指定, 则使用该类来格式化帮助信息. \
                默认为 argparse.HelpFormatter
        """
        formatter = fmt_cls("")
        formatter.add_usage(self.display_name or "", [], [], "")

        formatter.add_text(description)

        if self.help_map:
            formatter.start_section(f"共有 {len(self.help_map)} 个子匹配")
            for help_id, twilight in self.help_map.items():
                if twilight.help_data is not None:
                    prefixes: Dict[str, str] = {
                        "brief": twilight.help_brief,
                        "usage": twilight.help_data["usage"],
                        "description": twilight.help_data["description"],
                    }
                    formatter.add_text(f"{help_id} - {prefixes[prefix_src]}")
                else:
                    formatter.add_text(f"{help_id}")
            formatter.end_section()

        formatter.add_text(epilog)

        help_string: str = formatter.format_help()
        return fmt_func(help_string) if fmt_func else help_string

get_help 🔗

get_help(
    description: str = "",
    epilog: str = "",
    *,
    prefix_src: Literal["brief", "usage", "description"] = "brief",
    fmt_func: Optional[Callable[[str], T]] = None,
    fmt_cls: Type[argparse.HelpFormatter] = argparse.HelpFormatter
) -> Union[T, str]

获取本管理器总的帮助信息

Parameters:

  • fmt_func (Optional[Callable[[str], T]]) –

    如果指定, 则使用该函数来转换帮助信息格式

  • fmt_cls (Type[argparse.HelpFormatter]) –

    如果指定, 则使用该类来格式化帮助信息. 默认为 argparse.HelpFormatter

Source code in src/graia/ariadne/message/parser/util.py
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
def get_help(
    self,
    description: str = "",
    epilog: str = "",
    *,
    prefix_src: Literal["brief", "usage", "description"] = "brief",
    fmt_func: Optional[Callable[[str], T]] = None,
    fmt_cls: Type[argparse.HelpFormatter] = argparse.HelpFormatter,
) -> Union[T, str]:
    """获取本管理器总的帮助信息

    Args:
        fmt_func (Optional[Callable[[str], T]]): 如果指定, 则使用该函数来转换帮助信息格式
        fmt_cls (Type[argparse.HelpFormatter], optional): 如果指定, 则使用该类来格式化帮助信息. \
            默认为 argparse.HelpFormatter
    """
    formatter = fmt_cls("")
    formatter.add_usage(self.display_name or "", [], [], "")

    formatter.add_text(description)

    if self.help_map:
        formatter.start_section(f"共有 {len(self.help_map)} 个子匹配")
        for help_id, twilight in self.help_map.items():
            if twilight.help_data is not None:
                prefixes: Dict[str, str] = {
                    "brief": twilight.help_brief,
                    "usage": twilight.help_data["usage"],
                    "description": twilight.help_data["description"],
                }
                formatter.add_text(f"{help_id} - {prefixes[prefix_src]}")
            else:
                formatter.add_text(f"{help_id}")
        formatter.end_section()

    formatter.add_text(epilog)

    help_string: str = formatter.format_help()
    return fmt_func(help_string) if fmt_func else help_string

TwilightParser 🔗

Bases: argparse.ArgumentParser

适于 Twilight 使用的 argparse.ArgumentParser 子类 移除了报错时自动退出解释器的行为

Source code in src/graia/ariadne/message/parser/util.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
class TwilightParser(argparse.ArgumentParser):
    """适于 Twilight 使用的 argparse.ArgumentParser 子类
    移除了报错时自动退出解释器的行为
    """

    def error(self, message) -> NoReturn:
        raise ValueError(message)

    def accept_type(self, action: Union[str, type]) -> bool:
        """检查一个 action 是否接受 type 参数

        Args:
            action (Union[str, type]): 检查的 action

        Returns:
            bool: 是否接受 type 参数
        """
        if action is ...:
            action = "store"
        if isinstance(action, str):
            action_cls: Type[argparse.Action] = self._registry_get("action", action, action)
        elif isinstance(action, type) and issubclass(action, argparse.Action):
            action_cls = action
        else:
            return False
        action_init_sig = inspect.signature(action_cls.__init__)
        if "type" not in action_init_sig.parameters:
            return False
        return True

accept_type 🔗

accept_type(action: Union[str, type]) -> bool

检查一个 action 是否接受 type 参数

Parameters:

Returns:

  • bool( bool ) –

    是否接受 type 参数

Source code in src/graia/ariadne/message/parser/util.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def accept_type(self, action: Union[str, type]) -> bool:
    """检查一个 action 是否接受 type 参数

    Args:
        action (Union[str, type]): 检查的 action

    Returns:
        bool: 是否接受 type 参数
    """
    if action is ...:
        action = "store"
    if isinstance(action, str):
        action_cls: Type[argparse.Action] = self._registry_get("action", action, action)
    elif isinstance(action, type) and issubclass(action, argparse.Action):
        action_cls = action
    else:
        return False
    action_init_sig = inspect.signature(action_cls.__init__)
    if "type" not in action_init_sig.parameters:
        return False
    return True

gen_flags_repr 🔗

gen_flags_repr(flags: re.RegexFlag) -> str

通过 RegexFlag 生成对应的字符串

Parameters:

Returns:

  • str( str ) –

    对应的标记字符串

Source code in src/graia/ariadne/message/parser/util.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def gen_flags_repr(flags: re.RegexFlag) -> str:
    """通过 RegexFlag 生成对应的字符串

    Args:
        flags (re.RegexFlag): 正则表达式的标记

    Returns:
        str: 对应的标记字符串
    """
    flags_list: List[str] = []

    if re.ASCII in flags:
        flags_list.append("a")
    if re.IGNORECASE in flags:
        flags_list.append("i")
    if re.LOCALE in flags:
        flags_list.append("L")
    if re.MULTILINE in flags:
        flags_list.append("m")
    if re.DOTALL in flags:
        flags_list.append("s")
    if re.UNICODE in flags:
        flags_list.append("u")
    if re.VERBOSE in flags:
        flags_list.append("x")

    return "".join(flags_list)

split 🔗

split(string: str, keep_quote: bool = False) -> List[str]

尊重引号与转义的字符串切分

Parameters:

  • string (str) –

    要切割的字符串

  • keep_quote (bool) –

    是否保留引号, 默认 False.

Returns:

  • List[str]

    List[str]: 切割后的字符串, 可能含有空格

Source code in src/graia/ariadne/message/parser/util.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def split(string: str, keep_quote: bool = False) -> List[str]:
    """尊重引号与转义的字符串切分

    Args:
        string (str): 要切割的字符串
        keep_quote (bool): 是否保留引号, 默认 False.

    Returns:
        List[str]: 切割后的字符串, 可能含有空格
    """
    result: List[str] = []
    quote = ""
    cache: List[str] = []
    for index, char in enumerate(string):
        if char in {"'", '"'}:
            if not quote:
                quote = char
            elif char == quote and index and string[index - 1] != "\\":  # is current quote, not transfigured
                quote = ""
            else:
                cache.append(char)
                continue
            if keep_quote:
                cache.append(char)
        elif not quote and char == " ":
            result.append("".join(cache))
            cache = []
        elif char != "\\":
            cache.append(char)
    if cache:
        result.append("".join(cache))
    return result

transform_regex 🔗

transform_regex(flag: re.RegexFlag, regex_pattern: str) -> str

生成嵌套正则表达式字符串来达到至少最外层含有一个捕获组的效果

Parameters:

  • flag (re.RegexFlag) –

    正则表达式标记

  • regex_pattern (str) –

    正则表达式字符串

Returns:

  • str( str ) –

    转换后的正则表达式字符串

Source code in src/graia/ariadne/message/parser/util.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def transform_regex(flag: re.RegexFlag, regex_pattern: str) -> str:
    """生成嵌套正则表达式字符串来达到至少最外层含有一个捕获组的效果

    Args:
        flag (re.RegexFlag): 正则表达式标记
        regex_pattern (str): 正则表达式字符串

    Returns:
        str: 转换后的正则表达式字符串
    """
    return f"(?{gen_flags_repr(flag)}:({regex_pattern}))" if flag else f"({regex_pattern})"