We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bug: MessageTemplate.format 将消息段错误拼接为文本
**描述问题：**

`MessageTemplate.format` 将非文本类型消息段错误拼接为文本类型

**如何复现？**

```python
>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment
>>> Message.template("{}{}").format(MessageSegment.image("file:///"), "hello")
[MessageSegment(type='text', data={'text': '[CQ:image,file=file:///,cache=true,proxy=true]'}), MessageSegment(type='text', data={'text': 'hello'})]
```

**期望的结果**

```python
>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment
>>> Message.template("{}{}").format(MessageSegment.image("file:///"), "hello")
[MessageSegment(type='image', data={'file': 'file:///', 'type': None, 'cache': 'true', 'proxy': 'true', 'timeout': None}), MessageSegment(type='text', data={'text': 'hello'})]
```

**环境信息：**

 - OS: Windows 10
 - Python Version: 3.9.6
 - Nonebot Version: 2.0.0-beta2

**截图或日志**

![before](https://user-images.githubusercontent.com/68982190/165677394-d5679b8c-6ab8-4eb9-a796-c5e597273031.png)

**备注**

我自己写了一段修复代码（不保证稳定性）

[`template.py`](https://github.com/nonebot/nonebot2/blob/master/nonebot/internal/adapter/template.py)将原来的

```python
formatted_text = self.format_field(obj, str(format_control))
results.append(formatted_text)
```
替换为
```python
from .message import MessageSegment
if isinstance(obj, MessageSegment):
    results.append(obj)
else:
    formatted_text = self.format_field(obj, str(format_control))
    results.append(formatted_text)
```

修复后效果如下

![fix](https://user-images.githubusercontent.com/68982190/165677717-e7cff460-d2d4-47ff-907d-a8a9fc0a6a84.png)
Bug: MessageTemplate.format 将消息段错误拼接为文本
**描述问题：**

`MessageTemplate.format` 将非文本类型消息段错误拼接为文本类型

**如何复现？**

```python
>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment
>>> Message.template("{}{}").format(MessageSegment.image("file:///"), "hello")
[MessageSegment(type='text', data={'text': '[CQ:image,file=file:///,cache=true,proxy=true]'}), MessageSegment(type='text', data={'text': 'hello'})]
```

**期望的结果**

```python
>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment
>>> Message.template("{}{}").format(MessageSegment.image("file:///"), "hello")
[MessageSegment(type='image', data={'file': 'file:///', 'type': None, 'cache': 'true', 'proxy': 'true', 'timeout': None}), MessageSegment(type='text', data={'text': 'hello'})]
```

**环境信息：**

 - OS: Windows 10
 - Python Version: 3.9.6
 - Nonebot Version: 2.0.0-beta2

**截图或日志**

![before](https://user-images.githubusercontent.com/68982190/165677394-d5679b8c-6ab8-4eb9-a796-c5e597273031.png)

**备注**

我自己写了一段修复代码（不保证稳定性）

[`template.py`](https://github.com/nonebot/nonebot2/blob/master/nonebot/internal/adapter/template.py)将原来的

```python
formatted_text = self.format_field(obj, str(format_control))
results.append(formatted_text)
```
替换为
```python
from .message import MessageSegment
if isinstance(obj, MessageSegment):
    results.append(obj)
else:
    formatted_text = self.format_field(obj, str(format_control))
    results.append(formatted_text)
```

修复后效果如下

![fix](https://user-images.githubusercontent.com/68982190/165677717-e7cff460-d2d4-47ff-907d-a8a9fc0a6a84.png)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nonebot/internal/adapter/template.py`
Content:
```
1 import functools
2 from string import Formatter
3 from typing import (
4     TYPE_CHECKING,
5     Any,
6     Set,
7     Dict,
8     List,
9     Type,
10     Tuple,
11     Union,
12     Generic,
13     Mapping,
14     TypeVar,
15     Callable,
16     Optional,
17     Sequence,
18     cast,
19     overload,
20 )
21 
22 if TYPE_CHECKING:
23     from .message import Message, MessageSegment
24 
25 TM = TypeVar("TM", bound="Message")
26 TF = TypeVar("TF", str, "Message")
27 
28 FormatSpecFunc = Callable[[Any], str]
29 FormatSpecFunc_T = TypeVar("FormatSpecFunc_T", bound=FormatSpecFunc)
30 
31 
32 class MessageTemplate(Formatter, Generic[TF]):
33     """消息模板格式化实现类。
34 
35     参数:
36         template: 模板
37         factory: 消息类型工厂，默认为 `str`
38     """
39 
40     @overload
41     def __init__(
42         self: "MessageTemplate[str]", template: str, factory: Type[str] = str
43     ) -> None:
44         ...
45 
46     @overload
47     def __init__(
48         self: "MessageTemplate[TM]", template: Union[str, TM], factory: Type[TM]
49     ) -> None:
50         ...
51 
52     def __init__(self, template, factory=str) -> None:
53         self.template: TF = template
54         self.factory: Type[TF] = factory
55         self.format_specs: Dict[str, FormatSpecFunc] = {}
56 
57     def add_format_spec(
58         self, spec: FormatSpecFunc_T, name: Optional[str] = None
59     ) -> FormatSpecFunc_T:
60         name = name or spec.__name__
61         if name in self.format_specs:
62             raise ValueError(f"Format spec {name} already exists!")
63         self.format_specs[name] = spec
64         return spec
65 
66     def format(self, *args, **kwargs):
67         """根据传入参数和模板生成消息对象"""
68         return self._format(args, kwargs)
69 
70     def format_map(self, mapping: Mapping[str, Any]) -> TF:
71         """根据传入字典和模板生成消息对象, 在传入字段名不是有效标识符时有用"""
72         return self._format([], mapping)
73 
74     def _format(self, args: Sequence[Any], kwargs: Mapping[str, Any]) -> TF:
75         msg = self.factory()
76         if isinstance(self.template, str):
77             msg += self.vformat(self.template, args, kwargs)
78         elif isinstance(self.template, self.factory):
79             template = cast("Message[MessageSegment]", self.template)
80             for seg in template:
81                 msg += self.vformat(str(seg), args, kwargs) if seg.is_text() else seg
82         else:
83             raise TypeError("template must be a string or instance of Message!")
84 
85         return msg  # type:ignore
86 
87     def vformat(
88         self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]
89     ) -> TF:
90         used_args = set()
91         result, _ = self._vformat(format_string, args, kwargs, used_args, 2)
92         self.check_unused_args(list(used_args), args, kwargs)
93         return result
94 
95     def _vformat(
96         self,
97         format_string: str,
98         args: Sequence[Any],
99         kwargs: Mapping[str, Any],
100         used_args: Set[Union[int, str]],
101         recursion_depth: int,
102         auto_arg_index: int = 0,
103     ) -> Tuple[TF, int]:
104         if recursion_depth < 0:
105             raise ValueError("Max string recursion exceeded")
106 
107         results: List[Any] = [self.factory()]
108 
109         for (literal_text, field_name, format_spec, conversion) in self.parse(
110             format_string
111         ):
112 
113             # output the literal text
114             if literal_text:
115                 results.append(literal_text)
116 
117             # if there's a field, output it
118             if field_name is not None:
119                 # this is some markup, find the object and do
120                 #  the formatting
121 
122                 # handle arg indexing when empty field_names are given.
123                 if field_name == "":
124                     if auto_arg_index is False:
125                         raise ValueError(
126                             "cannot switch from manual field specification to "
127                             "automatic field numbering"
128                         )
129                     field_name = str(auto_arg_index)
130                     auto_arg_index += 1
131                 elif field_name.isdigit():
132                     if auto_arg_index:
133                         raise ValueError(
134                             "cannot switch from manual field specification to "
135                             "automatic field numbering"
136                         )
137                     # disable auto arg incrementing, if it gets
138                     # used later on, then an exception will be raised
139                     auto_arg_index = False
140 
141                 # given the field_name, find the object it references
142                 #  and the argument it came from
143                 obj, arg_used = self.get_field(field_name, args, kwargs)
144                 used_args.add(arg_used)
145 
146                 assert format_spec is not None
147 
148                 # do any conversion on the resulting object
149                 obj = self.convert_field(obj, conversion) if conversion else obj
150 
151                 # expand the format spec, if needed
152                 format_control, auto_arg_index = self._vformat(
153                     format_spec,
154                     args,
155                     kwargs,
156                     used_args,
157                     recursion_depth - 1,
158                     auto_arg_index,
159                 )
160 
161                 # format the object and append to the result
162                 formatted_text = self.format_field(obj, str(format_control))
163                 results.append(formatted_text)
164 
165         return functools.reduce(self._add, results), auto_arg_index
166 
167     def format_field(self, value: Any, format_spec: str) -> Any:
168         formatter: Optional[FormatSpecFunc] = self.format_specs.get(format_spec)
169         if formatter is None and not issubclass(self.factory, str):
170             segment_class: Type["MessageSegment"] = self.factory.get_segment_class()
171             method = getattr(segment_class, format_spec, None)
172             if callable(method) and not cast(str, method.__name__).startswith("_"):
173                 formatter = getattr(segment_class, format_spec)
174         return (
175             super().format_field(value, format_spec)
176             if formatter is None
177             else formatter(value)
178         )
179 
180     def _add(self, a: Any, b: Any) -> Any:
181         try:
182             return a + b
183         except TypeError:
184             return a + str(b)
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nonebot/internal/adapter/template.py b/nonebot/internal/adapter/template.py
--- a/nonebot/internal/adapter/template.py
+++ b/nonebot/internal/adapter/template.py
@@ -49,7 +49,9 @@
     ) -> None:
         ...
 
-    def __init__(self, template, factory=str) -> None:
+    def __init__(  # type:ignore
+        self, template, factory=str
+    ) -> None:  # TODO: fix type hint here
         self.template: TF = template
         self.factory: Type[TF] = factory
         self.format_specs: Dict[str, FormatSpecFunc] = {}
@@ -72,25 +74,37 @@
         return self._format([], mapping)
 
     def _format(self, args: Sequence[Any], kwargs: Mapping[str, Any]) -> TF:
-        msg = self.factory()
+        full_message = self.factory()
+        used_args, arg_index = set(), 0
+
         if isinstance(self.template, str):
-            msg += self.vformat(self.template, args, kwargs)
+            msg, arg_index = self._vformat(
+                self.template, args, kwargs, used_args, arg_index
+            )
+            full_message += msg
         elif isinstance(self.template, self.factory):
             template = cast("Message[MessageSegment]", self.template)
             for seg in template:
-                msg += self.vformat(str(seg), args, kwargs) if seg.is_text() else seg
+                if not seg.is_text():
+                    full_message += seg
+                else:
+                    msg, arg_index = self._vformat(
+                        str(seg), args, kwargs, used_args, arg_index
+                    )
+                    full_message += msg
         else:
             raise TypeError("template must be a string or instance of Message!")
 
-        return msg  # type:ignore
+        self.check_unused_args(list(used_args), args, kwargs)
+        return cast(TF, full_message)
 
     def vformat(
-        self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]
+        self,
+        format_string: str,
+        args: Sequence[Any],
+        kwargs: Mapping[str, Any],
     ) -> TF:
-        used_args = set()
-        result, _ = self._vformat(format_string, args, kwargs, used_args, 2)
-        self.check_unused_args(list(used_args), args, kwargs)
-        return result
+        raise NotImplementedError("`vformat` has merged into `_format`")
 
     def _vformat(
         self,
@@ -98,12 +112,8 @@
         args: Sequence[Any],
         kwargs: Mapping[str, Any],
         used_args: Set[Union[int, str]],
-        recursion_depth: int,
         auto_arg_index: int = 0,
     ) -> Tuple[TF, int]:
-        if recursion_depth < 0:
-            raise ValueError("Max string recursion exceeded")
-
         results: List[Any] = [self.factory()]
 
         for (literal_text, field_name, format_spec, conversion) in self.parse(
@@ -143,23 +153,13 @@
                 obj, arg_used = self.get_field(field_name, args, kwargs)
                 used_args.add(arg_used)
 
-                assert format_spec is not None
-
                 # do any conversion on the resulting object
                 obj = self.convert_field(obj, conversion) if conversion else obj
 
-                # expand the format spec, if needed
-                format_control, auto_arg_index = self._vformat(
-                    format_spec,
-                    args,
-                    kwargs,
-                    used_args,
-                    recursion_depth - 1,
-                    auto_arg_index,
-                )
-
                 # format the object and append to the result
-                formatted_text = self.format_field(obj, str(format_control))
+                formatted_text = (
+                    self.format_field(obj, format_spec) if format_spec else obj
+                )
                 results.append(formatted_text)
 
         return functools.reduce(self._add, results), auto_arg_index

{"golden_diff": "diff --git a/nonebot/internal/adapter/template.py b/nonebot/internal/adapter/template.py\n--- a/nonebot/internal/adapter/template.py\n+++ b/nonebot/internal/adapter/template.py\n@@ -49,7 +49,9 @@\n     ) -> None:\n         ...\n \n-    def __init__(self, template, factory=str) -> None:\n+    def __init__(  # type:ignore\n+        self, template, factory=str\n+    ) -> None:  # TODO: fix type hint here\n         self.template: TF = template\n         self.factory: Type[TF] = factory\n         self.format_specs: Dict[str, FormatSpecFunc] = {}\n@@ -72,25 +74,37 @@\n         return self._format([], mapping)\n \n     def _format(self, args: Sequence[Any], kwargs: Mapping[str, Any]) -> TF:\n-        msg = self.factory()\n+        full_message = self.factory()\n+        used_args, arg_index = set(), 0\n+\n         if isinstance(self.template, str):\n-            msg += self.vformat(self.template, args, kwargs)\n+            msg, arg_index = self._vformat(\n+                self.template, args, kwargs, used_args, arg_index\n+            )\n+            full_message += msg\n         elif isinstance(self.template, self.factory):\n             template = cast(\"Message[MessageSegment]\", self.template)\n             for seg in template:\n-                msg += self.vformat(str(seg), args, kwargs) if seg.is_text() else seg\n+                if not seg.is_text():\n+                    full_message += seg\n+                else:\n+                    msg, arg_index = self._vformat(\n+                        str(seg), args, kwargs, used_args, arg_index\n+                    )\n+                    full_message += msg\n         else:\n             raise TypeError(\"template must be a string or instance of Message!\")\n \n-        return msg  # type:ignore\n+        self.check_unused_args(list(used_args), args, kwargs)\n+        return cast(TF, full_message)\n \n     def vformat(\n-        self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]\n+        self,\n+        format_string: str,\n+        args: Sequence[Any],\n+        kwargs: Mapping[str, Any],\n     ) -> TF:\n-        used_args = set()\n-        result, _ = self._vformat(format_string, args, kwargs, used_args, 2)\n-        self.check_unused_args(list(used_args), args, kwargs)\n-        return result\n+        raise NotImplementedError(\"`vformat` has merged into `_format`\")\n \n     def _vformat(\n         self,\n@@ -98,12 +112,8 @@\n         args: Sequence[Any],\n         kwargs: Mapping[str, Any],\n         used_args: Set[Union[int, str]],\n-        recursion_depth: int,\n         auto_arg_index: int = 0,\n     ) -> Tuple[TF, int]:\n-        if recursion_depth < 0:\n-            raise ValueError(\"Max string recursion exceeded\")\n-\n         results: List[Any] = [self.factory()]\n \n         for (literal_text, field_name, format_spec, conversion) in self.parse(\n@@ -143,23 +153,13 @@\n                 obj, arg_used = self.get_field(field_name, args, kwargs)\n                 used_args.add(arg_used)\n \n-                assert format_spec is not None\n-\n                 # do any conversion on the resulting object\n                 obj = self.convert_field(obj, conversion) if conversion else obj\n \n-                # expand the format spec, if needed\n-                format_control, auto_arg_index = self._vformat(\n-                    format_spec,\n-                    args,\n-                    kwargs,\n-                    used_args,\n-                    recursion_depth - 1,\n-                    auto_arg_index,\n-                )\n-\n                 # format the object and append to the result\n-                formatted_text = self.format_field(obj, str(format_control))\n+                formatted_text = (\n+                    self.format_field(obj, format_spec) if format_spec else obj\n+                )\n                 results.append(formatted_text)\n \n         return functools.reduce(self._add, results), auto_arg_index\n", "issue": "Bug: MessageTemplate.format \u5c06\u6d88\u606f\u6bb5\u9519\u8bef\u62fc\u63a5\u4e3a\u6587\u672c\n**\u63cf\u8ff0\u95ee\u9898\uff1a**\r\n\r\n`MessageTemplate.format` \u5c06\u975e\u6587\u672c\u7c7b\u578b\u6d88\u606f\u6bb5\u9519\u8bef\u62fc\u63a5\u4e3a\u6587\u672c\u7c7b\u578b\r\n\r\n**\u5982\u4f55\u590d\u73b0\uff1f**\r\n\r\n```python\r\n>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment\r\n>>> Message.template(\"{}{}\").format(MessageSegment.image(\"file:///\"), \"hello\")\r\n[MessageSegment(type='text', data={'text': '[CQ:image,file=file:///,cache=true,proxy=true]'}), MessageSegment(type='text', data={'text': 'hello'})]\r\n```\r\n\r\n**\u671f\u671b\u7684\u7ed3\u679c**\r\n\r\n```python\r\n>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment\r\n>>> Message.template(\"{}{}\").format(MessageSegment.image(\"file:///\"), \"hello\")\r\n[MessageSegment(type='image', data={'file': 'file:///', 'type': None, 'cache': 'true', 'proxy': 'true', 'timeout': None}), MessageSegment(type='text', data={'text': 'hello'})]\r\n```\r\n\r\n**\u73af\u5883\u4fe1\u606f\uff1a**\r\n\r\n - OS: Windows 10\r\n - Python Version: 3.9.6\r\n - Nonebot Version: 2.0.0-beta2\r\n\r\n**\u622a\u56fe\u6216\u65e5\u5fd7**\r\n\r\n![before](https://user-images.githubusercontent.com/68982190/165677394-d5679b8c-6ab8-4eb9-a796-c5e597273031.png)\r\n\r\n**\u5907\u6ce8**\r\n\r\n\u6211\u81ea\u5df1\u5199\u4e86\u4e00\u6bb5\u4fee\u590d\u4ee3\u7801\uff08\u4e0d\u4fdd\u8bc1\u7a33\u5b9a\u6027\uff09\r\n\r\n[`template.py`](https://github.com/nonebot/nonebot2/blob/master/nonebot/internal/adapter/template.py)\u5c06\u539f\u6765\u7684\r\n\r\n```python\r\nformatted_text = self.format_field(obj, str(format_control))\r\nresults.append(formatted_text)\r\n```\r\n\u66ff\u6362\u4e3a\r\n```python\r\nfrom .message import MessageSegment\r\nif isinstance(obj, MessageSegment):\r\n    results.append(obj)\r\nelse:\r\n    formatted_text = self.format_field(obj, str(format_control))\r\n    results.append(formatted_text)\r\n```\r\n\r\n\u4fee\u590d\u540e\u6548\u679c\u5982\u4e0b\r\n\r\n![fix](https://user-images.githubusercontent.com/68982190/165677717-e7cff460-d2d4-47ff-907d-a8a9fc0a6a84.png)\nBug: MessageTemplate.format \u5c06\u6d88\u606f\u6bb5\u9519\u8bef\u62fc\u63a5\u4e3a\u6587\u672c\n**\u63cf\u8ff0\u95ee\u9898\uff1a**\r\n\r\n`MessageTemplate.format` \u5c06\u975e\u6587\u672c\u7c7b\u578b\u6d88\u606f\u6bb5\u9519\u8bef\u62fc\u63a5\u4e3a\u6587\u672c\u7c7b\u578b\r\n\r\n**\u5982\u4f55\u590d\u73b0\uff1f**\r\n\r\n```python\r\n>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment\r\n>>> Message.template(\"{}{}\").format(MessageSegment.image(\"file:///\"), \"hello\")\r\n[MessageSegment(type='text', data={'text': '[CQ:image,file=file:///,cache=true,proxy=true]'}), MessageSegment(type='text', data={'text': 'hello'})]\r\n```\r\n\r\n**\u671f\u671b\u7684\u7ed3\u679c**\r\n\r\n```python\r\n>>> from nonebot.adapters.onebot.v11 import Message, MessageSegment\r\n>>> Message.template(\"{}{}\").format(MessageSegment.image(\"file:///\"), \"hello\")\r\n[MessageSegment(type='image', data={'file': 'file:///', 'type': None, 'cache': 'true', 'proxy': 'true', 'timeout': None}), MessageSegment(type='text', data={'text': 'hello'})]\r\n```\r\n\r\n**\u73af\u5883\u4fe1\u606f\uff1a**\r\n\r\n - OS: Windows 10\r\n - Python Version: 3.9.6\r\n - Nonebot Version: 2.0.0-beta2\r\n\r\n**\u622a\u56fe\u6216\u65e5\u5fd7**\r\n\r\n![before](https://user-images.githubusercontent.com/68982190/165677394-d5679b8c-6ab8-4eb9-a796-c5e597273031.png)\r\n\r\n**\u5907\u6ce8**\r\n\r\n\u6211\u81ea\u5df1\u5199\u4e86\u4e00\u6bb5\u4fee\u590d\u4ee3\u7801\uff08\u4e0d\u4fdd\u8bc1\u7a33\u5b9a\u6027\uff09\r\n\r\n[`template.py`](https://github.com/nonebot/nonebot2/blob/master/nonebot/internal/adapter/template.py)\u5c06\u539f\u6765\u7684\r\n\r\n```python\r\nformatted_text = self.format_field(obj, str(format_control))\r\nresults.append(formatted_text)\r\n```\r\n\u66ff\u6362\u4e3a\r\n```python\r\nfrom .message import MessageSegment\r\nif isinstance(obj, MessageSegment):\r\n    results.append(obj)\r\nelse:\r\n    formatted_text = self.format_field(obj, str(format_control))\r\n    results.append(formatted_text)\r\n```\r\n\r\n\u4fee\u590d\u540e\u6548\u679c\u5982\u4e0b\r\n\r\n![fix](https://user-images.githubusercontent.com/68982190/165677717-e7cff460-d2d4-47ff-907d-a8a9fc0a6a84.png)\n", "before_files": [{"content": "import functools\nfrom string import Formatter\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Set,\n    Dict,\n    List,\n    Type,\n    Tuple,\n    Union,\n    Generic,\n    Mapping,\n    TypeVar,\n    Callable,\n    Optional,\n    Sequence,\n    cast,\n    overload,\n)\n\nif TYPE_CHECKING:\n    from .message import Message, MessageSegment\n\nTM = TypeVar(\"TM\", bound=\"Message\")\nTF = TypeVar(\"TF\", str, \"Message\")\n\nFormatSpecFunc = Callable[[Any], str]\nFormatSpecFunc_T = TypeVar(\"FormatSpecFunc_T\", bound=FormatSpecFunc)\n\n\nclass MessageTemplate(Formatter, Generic[TF]):\n    \"\"\"\u6d88\u606f\u6a21\u677f\u683c\u5f0f\u5316\u5b9e\u73b0\u7c7b\u3002\n\n    \u53c2\u6570:\n        template: \u6a21\u677f\n        factory: \u6d88\u606f\u7c7b\u578b\u5de5\u5382\uff0c\u9ed8\u8ba4\u4e3a `str`\n    \"\"\"\n\n    @overload\n    def __init__(\n        self: \"MessageTemplate[str]\", template: str, factory: Type[str] = str\n    ) -> None:\n        ...\n\n    @overload\n    def __init__(\n        self: \"MessageTemplate[TM]\", template: Union[str, TM], factory: Type[TM]\n    ) -> None:\n        ...\n\n    def __init__(self, template, factory=str) -> None:\n        self.template: TF = template\n        self.factory: Type[TF] = factory\n        self.format_specs: Dict[str, FormatSpecFunc] = {}\n\n    def add_format_spec(\n        self, spec: FormatSpecFunc_T, name: Optional[str] = None\n    ) -> FormatSpecFunc_T:\n        name = name or spec.__name__\n        if name in self.format_specs:\n            raise ValueError(f\"Format spec {name} already exists!\")\n        self.format_specs[name] = spec\n        return spec\n\n    def format(self, *args, **kwargs):\n        \"\"\"\u6839\u636e\u4f20\u5165\u53c2\u6570\u548c\u6a21\u677f\u751f\u6210\u6d88\u606f\u5bf9\u8c61\"\"\"\n        return self._format(args, kwargs)\n\n    def format_map(self, mapping: Mapping[str, Any]) -> TF:\n        \"\"\"\u6839\u636e\u4f20\u5165\u5b57\u5178\u548c\u6a21\u677f\u751f\u6210\u6d88\u606f\u5bf9\u8c61, \u5728\u4f20\u5165\u5b57\u6bb5\u540d\u4e0d\u662f\u6709\u6548\u6807\u8bc6\u7b26\u65f6\u6709\u7528\"\"\"\n        return self._format([], mapping)\n\n    def _format(self, args: Sequence[Any], kwargs: Mapping[str, Any]) -> TF:\n        msg = self.factory()\n        if isinstance(self.template, str):\n            msg += self.vformat(self.template, args, kwargs)\n        elif isinstance(self.template, self.factory):\n            template = cast(\"Message[MessageSegment]\", self.template)\n            for seg in template:\n                msg += self.vformat(str(seg), args, kwargs) if seg.is_text() else seg\n        else:\n            raise TypeError(\"template must be a string or instance of Message!\")\n\n        return msg  # type:ignore\n\n    def vformat(\n        self, format_string: str, args: Sequence[Any], kwargs: Mapping[str, Any]\n    ) -> TF:\n        used_args = set()\n        result, _ = self._vformat(format_string, args, kwargs, used_args, 2)\n        self.check_unused_args(list(used_args), args, kwargs)\n        return result\n\n    def _vformat(\n        self,\n        format_string: str,\n        args: Sequence[Any],\n        kwargs: Mapping[str, Any],\n        used_args: Set[Union[int, str]],\n        recursion_depth: int,\n        auto_arg_index: int = 0,\n    ) -> Tuple[TF, int]:\n        if recursion_depth < 0:\n            raise ValueError(\"Max string recursion exceeded\")\n\n        results: List[Any] = [self.factory()]\n\n        for (literal_text, field_name, format_spec, conversion) in self.parse(\n            format_string\n        ):\n\n            # output the literal text\n            if literal_text:\n                results.append(literal_text)\n\n            # if there's a field, output it\n            if field_name is not None:\n                # this is some markup, find the object and do\n                #  the formatting\n\n                # handle arg indexing when empty field_names are given.\n                if field_name == \"\":\n                    if auto_arg_index is False:\n                        raise ValueError(\n                            \"cannot switch from manual field specification to \"\n                            \"automatic field numbering\"\n                        )\n                    field_name = str(auto_arg_index)\n                    auto_arg_index += 1\n                elif field_name.isdigit():\n                    if auto_arg_index:\n                        raise ValueError(\n                            \"cannot switch from manual field specification to \"\n                            \"automatic field numbering\"\n                        )\n                    # disable auto arg incrementing, if it gets\n                    # used later on, then an exception will be raised\n                    auto_arg_index = False\n\n                # given the field_name, find the object it references\n                #  and the argument it came from\n                obj, arg_used = self.get_field(field_name, args, kwargs)\n                used_args.add(arg_used)\n\n                assert format_spec is not None\n\n                # do any conversion on the resulting object\n                obj = self.convert_field(obj, conversion) if conversion else obj\n\n                # expand the format spec, if needed\n                format_control, auto_arg_index = self._vformat(\n                    format_spec,\n                    args,\n                    kwargs,\n                    used_args,\n                    recursion_depth - 1,\n                    auto_arg_index,\n                )\n\n                # format the object and append to the result\n                formatted_text = self.format_field(obj, str(format_control))\n                results.append(formatted_text)\n\n        return functools.reduce(self._add, results), auto_arg_index\n\n    def format_field(self, value: Any, format_spec: str) -> Any:\n        formatter: Optional[FormatSpecFunc] = self.format_specs.get(format_spec)\n        if formatter is None and not issubclass(self.factory, str):\n            segment_class: Type[\"MessageSegment\"] = self.factory.get_segment_class()\n            method = getattr(segment_class, format_spec, None)\n            if callable(method) and not cast(str, method.__name__).startswith(\"_\"):\n                formatter = getattr(segment_class, format_spec)\n        return (\n            super().format_field(value, format_spec)\n            if formatter is None\n            else formatter(value)\n        )\n\n    def _add(self, a: Any, b: Any) -> Any:\n        try:\n            return a + b\n        except TypeError:\n            return a + str(b)\n", "path": "nonebot/internal/adapter/template.py"}], "after_files": [{"content": "import functools\nfrom string import Formatter\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Set,\n    Dict,\n    List,\n    Type,\n    Tuple,\n    Union,\n    Generic,\n    Mapping,\n    TypeVar,\n    Callable,\n    Optional,\n    Sequence,\n    cast,\n    overload,\n)\n\nif TYPE_CHECKING:\n    from .message import Message, MessageSegment\n\nTM = TypeVar(\"TM\", bound=\"Message\")\nTF = TypeVar(\"TF\", str, \"Message\")\n\nFormatSpecFunc = Callable[[Any], str]\nFormatSpecFunc_T = TypeVar(\"FormatSpecFunc_T\", bound=FormatSpecFunc)\n\n\nclass MessageTemplate(Formatter, Generic[TF]):\n    \"\"\"\u6d88\u606f\u6a21\u677f\u683c\u5f0f\u5316\u5b9e\u73b0\u7c7b\u3002\n\n    \u53c2\u6570:\n        template: \u6a21\u677f\n        factory: \u6d88\u606f\u7c7b\u578b\u5de5\u5382\uff0c\u9ed8\u8ba4\u4e3a `str`\n    \"\"\"\n\n    @overload\n    def __init__(\n        self: \"MessageTemplate[str]\", template: str, factory: Type[str] = str\n    ) -> None:\n        ...\n\n    @overload\n    def __init__(\n        self: \"MessageTemplate[TM]\", template: Union[str, TM], factory: Type[TM]\n    ) -> None:\n        ...\n\n    def __init__(  # type:ignore\n        self, template, factory=str\n    ) -> None:  # TODO: fix type hint here\n        self.template: TF = template\n        self.factory: Type[TF] = factory\n        self.format_specs: Dict[str, FormatSpecFunc] = {}\n\n    def add_format_spec(\n        self, spec: FormatSpecFunc_T, name: Optional[str] = None\n    ) -> FormatSpecFunc_T:\n        name = name or spec.__name__\n        if name in self.format_specs:\n            raise ValueError(f\"Format spec {name} already exists!\")\n        self.format_specs[name] = spec\n        return spec\n\n    def format(self, *args, **kwargs):\n        \"\"\"\u6839\u636e\u4f20\u5165\u53c2\u6570\u548c\u6a21\u677f\u751f\u6210\u6d88\u606f\u5bf9\u8c61\"\"\"\n        return self._format(args, kwargs)\n\n    def format_map(self, mapping: Mapping[str, Any]) -> TF:\n        \"\"\"\u6839\u636e\u4f20\u5165\u5b57\u5178\u548c\u6a21\u677f\u751f\u6210\u6d88\u606f\u5bf9\u8c61, \u5728\u4f20\u5165\u5b57\u6bb5\u540d\u4e0d\u662f\u6709\u6548\u6807\u8bc6\u7b26\u65f6\u6709\u7528\"\"\"\n        return self._format([], mapping)\n\n    def _format(self, args: Sequence[Any], kwargs: Mapping[str, Any]) -> TF:\n        full_message = self.factory()\n        used_args, arg_index = set(), 0\n\n        if isinstance(self.template, str):\n            msg, arg_index = self._vformat(\n                self.template, args, kwargs, used_args, arg_index\n            )\n            full_message += msg\n        elif isinstance(self.template, self.factory):\n            template = cast(\"Message[MessageSegment]\", self.template)\n            for seg in template:\n                if not seg.is_text():\n                    full_message += seg\n                else:\n                    msg, arg_index = self._vformat(\n                        str(seg), args, kwargs, used_args, arg_index\n                    )\n                    full_message += msg\n        else:\n            raise TypeError(\"template must be a string or instance of Message!\")\n\n        self.check_unused_args(list(used_args), args, kwargs)\n        return cast(TF, full_message)\n\n    def vformat(\n        self,\n        format_string: str,\n        args: Sequence[Any],\n        kwargs: Mapping[str, Any],\n    ) -> TF:\n        raise NotImplementedError(\"`vformat` has merged into `_format`\")\n\n    def _vformat(\n        self,\n        format_string: str,\n        args: Sequence[Any],\n        kwargs: Mapping[str, Any],\n        used_args: Set[Union[int, str]],\n        auto_arg_index: int = 0,\n    ) -> Tuple[TF, int]:\n        results: List[Any] = [self.factory()]\n\n        for (literal_text, field_name, format_spec, conversion) in self.parse(\n            format_string\n        ):\n\n            # output the literal text\n            if literal_text:\n                results.append(literal_text)\n\n            # if there's a field, output it\n            if field_name is not None:\n                # this is some markup, find the object and do\n                #  the formatting\n\n                # handle arg indexing when empty field_names are given.\n                if field_name == \"\":\n                    if auto_arg_index is False:\n                        raise ValueError(\n                            \"cannot switch from manual field specification to \"\n                            \"automatic field numbering\"\n                        )\n                    field_name = str(auto_arg_index)\n                    auto_arg_index += 1\n                elif field_name.isdigit():\n                    if auto_arg_index:\n                        raise ValueError(\n                            \"cannot switch from manual field specification to \"\n                            \"automatic field numbering\"\n                        )\n                    # disable auto arg incrementing, if it gets\n                    # used later on, then an exception will be raised\n                    auto_arg_index = False\n\n                # given the field_name, find the object it references\n                #  and the argument it came from\n                obj, arg_used = self.get_field(field_name, args, kwargs)\n                used_args.add(arg_used)\n\n                # do any conversion on the resulting object\n                obj = self.convert_field(obj, conversion) if conversion else obj\n\n                # format the object and append to the result\n                formatted_text = (\n                    self.format_field(obj, format_spec) if format_spec else obj\n                )\n                results.append(formatted_text)\n\n        return functools.reduce(self._add, results), auto_arg_index\n\n    def format_field(self, value: Any, format_spec: str) -> Any:\n        formatter: Optional[FormatSpecFunc] = self.format_specs.get(format_spec)\n        if formatter is None and not issubclass(self.factory, str):\n            segment_class: Type[\"MessageSegment\"] = self.factory.get_segment_class()\n            method = getattr(segment_class, format_spec, None)\n            if callable(method) and not cast(str, method.__name__).startswith(\"_\"):\n                formatter = getattr(segment_class, format_spec)\n        return (\n            super().format_field(value, format_spec)\n            if formatter is None\n            else formatter(value)\n        )\n\n    def _add(self, a: Any, b: Any) -> Any:\n        try:\n            return a + b\n        except TypeError:\n            return a + str(b)\n", "path": "nonebot/internal/adapter/template.py"}]}