Пример #1
0
def try_convert_type(arg_name: str, arg_type: T_ValidTextType,
                     text_without_type: str):
    # logger.debug(pformat(text_without_type, arg_type))

    result: T_ValidTextTypeInstance

    if arg_type == str:
        result = text_without_type

    if arg_type == bool:
        if not (text_without_type in TRUE_TEXTS
                or text_without_type in FALSE_TEXTS):
            raise PatternFormotError(f"未按照格式提供参数 {arg_name} 应为bool类型")

        else:
            if text_without_type in TRUE_TEXTS:
                result = True
            else:
                result = False

    else:  # 解析int, float
        try:
            result = arg_type(text_without_type)  # type:ignore

        except Exception as e:
            raise PatternFormotError(f"未按照格式提供参数 {arg_name}应为{arg_type}类型")

    return result
Пример #2
0
def match_by_regex(text_patterns: List[Tuple[str, T_ValidTextType]],
                   segment: Text):
    """通过正则,匹配对应的text和pattern"""
    regex = r""
    arg_count = len(text_patterns)

    for index, text_pattern in enumerate(text_patterns):
        (arg_name, arg_type) = text_pattern

        # 拼接正则,所有文字参数,应该都是空格分格的
        if index != arg_count - 1:
            regex += r"(\S+)\s*"
        else:
            regex += r"(\S+)"

        # logger.debug(pformat(arg_type))

    # logger.debug(pformat(regex, segment.content))
    match = re.search(regex, segment.content)
    if not match:
        raise PatternFormotError(f"pattern匹配失败-->正则失败")

    texts = match.groups()
    # logger.debug(pformat(texts))

    if len(texts) != arg_count:
        raise PatternFormotError(f"未按照格式提供参数 参数之间使用空格分隔")

    return texts
Пример #3
0
def get_pattern_results(
    compressed_patterns: List[Union[List[Tuple[str, T_PatternArg]],
                                    Tuple[str, T_PatternArg]]],
    compressed_segments: List[T_SegmentInstance],
):
    pattern_result: OrderedDict[str, T_PatternArgResult] = OrderedDict()

    for index, (segment, pattern) in enumerate(
            zip(compressed_segments, compressed_patterns)):
        # logger.debug(pformat(type(segment)))
        # logger.debug(pformat(type(chunk)))

        if isinstance(segment, Text):
            if not isinstance(pattern,
                              list):  # 所有text都被解析为list[(arg_name, arg_type)]
                raise PatternFormotError("未按照格式提供参数")

            text_patterns = cast(List[Tuple[str, T_ValidTextType]], pattern)
            texts = match_by_regex(text_patterns, segment)

            for index, text_without_type in enumerate(texts):
                arg_name, arg_type = text_patterns[index]

                pattern_result[arg_name] = try_convert_type(
                    arg_name,
                    arg_type,
                    text_without_type,
                )

        # todo 支持pydantic的Field,比如gt,lt,对输出的报错信息,转为PatternFormotError
        # 最好能找到,pydantic中是怎么使用ModelField进行字段验证的,只是使用就好了
        # snap: int = Field(
        #     42,
        #     title="The Snap",
        #     description="this is the value of snap",
        #     gt=30,
        #     lt=50,
        # )

        # 支持pydantic的validate装饰器
        # for arg_name, validators in command_pattern.__validators__.items():
        #     for validator in validators:
        #         validator.func(command_pattern.__class__, pattern_result[arg_name])

        else:  # 检测是否是有效类型,Face,Image之类
            pattern = cast(Tuple[str, T_PatternArg], pattern)
            arg_name, arg_type = pattern

            if type(segment) != arg_type:
                raise PatternFormotError(
                    f"未按照格式提供参数 {arg_name} 应为 {arg_type} 类型")

            pattern_result[arg_name] = segment

    return pattern_result
Пример #4
0
 def check_order(cls, value):
     if value not in [11, 12, 13]:
         raise PatternFormotError("请输入有效序号")
Пример #5
0
async def parse_pattern(
    chain: MessageChain,
    sender: "CommandSender",
    method_name,
    cache: CommandMethodCache,
    prefix: str,
    context,
):
    """
    根据签名中的PatternArg,自动解析参数,并转换为对应类型,自动注入函数调用中

    满足pattern放行,如果不满足,会对方法调用进行拦截,
    """

    if not cache.compressed_patterns:
        return {}

    compressed_patterns = cache.compressed_patterns

    # todo pydantic有没有原生的功能
    # 尝试解析,解析失败,报错
    # todo List(展开), Any, Union, List[Union/Any]

    formot_hint = "请按照 "
    for arg_name, arg_type in cache.patterns:
        formot_hint += f"<{arg_name} : {arg_type.__name__}> "
    formot_hint += "的格式输入\n不需要输入<或者>,:右侧是该参数的类型"

    # formot_hint添加prefix
    # if method_name == "initial":

    results = {}

    try:

        compressed_segments = merge_text_of_segments(chain.segments)
        logger.debug(pformat(compressed_segments))

        if len(compressed_segments) != len(compressed_patterns):
            raise PatternFormotError(f"未提供足够参数,应为{len(cache.patterns)}个," +
                                     f"获得{len(chain.segments)}个")

        # 对initial应用pattern的情况,支持prefix
        # 目前仅支持文字prefix
        if method_name == "initial":
            if not isinstance(compressed_segments[0], Text):
                return PatternFormotError("目前仅支持文字前缀")

            with_prefix = compressed_segments[0].content
            without_prefix = re.sub(f"^{prefix}", "", with_prefix)
            compressed_segments[0].content = without_prefix

        results = get_pattern_results(compressed_patterns, compressed_segments)

    except PatternFormotError as e:
        # if on_format_error:
        #     return_text = await await_or_normal(
        #         on_format_error, *args, **kwargs
        #     )
        #     if return_text:
        #         await bot.group_msg(return_text)
        # else:
        await sender.send_message(
            # Text(f"{e}\n{formot_hint if with_formot_hint else ''}")
            Text(f"{e}\n{formot_hint}"))

        logger.exception("指令解析失败")
        raise e

    else:
        # todo patternResults的maxSize

        logger.debug(pformat(results))
        return results
Пример #6
0
 def check_order(cls, value):
     if value not in range(1, 8):
         raise PatternFormotError("请输入有效序号")