Repository: nonebot/nonebot2

Issue:
Bug: argpraser遇到MessageSegment对象报错
**描述问题：**
https://github.com/nonebot/nonebot2/blob/master/nonebot/rule.py#L532
![image](https://user-images.githubusercontent.com/32660959/231935508-a9e3e15a-f4a7-4c1e-a58b-31ba1c90e140.png)
如果seg是图片例如 [image:file=d81284dd30e2b12f044a15a4c2830224.image, subType=0, url=https://gchat.qpic.cn/gchatpic_new/1543979464/594697041-2827320626-...]，那么state[SHELL_ARGV]这个list中除了str元素还有一个类型为MessageSegment的元素，在第542行就会报错了
![image](https://user-images.githubusercontent.com/32660959/231936180-2fe9497a-4ea2-4c6e-830a-ecb48bc710c3.png)

**如何复现？**
1.在on_shell_command的指令中带图片

**期望的结果**
不报错（state[SHELL_ARGV]这个list中过滤掉图片？）

**环境信息：**

 - OS: Ubuntu 18.04 x86_64
 - Python Version: 3.10.6
 - Nonebot Version: v2.0.0rc4

**协议端信息：**

 - 协议端: gocqhttp (nonebot-plugin-gocqhttp)
 - 协议端版本: gocqhttp v1.0.1

**补充信息**
是在使用nonebot-plugin-novelai这个插件时，在qq端发送 以图生图命令 'draw prompts [图片]'时触发报错


Discussion:
error format的时候遇到问题，得覆盖一下这块逻辑

Resolving patch:
diff --git a/nonebot/rule.py b/nonebot/rule.py
--- a/nonebot/rule.py
+++ b/nonebot/rule.py
@@ -11,6 +11,7 @@
 import re
 import shlex
 from argparse import Action
+from gettext import gettext
 from argparse import ArgumentError
 from contextvars import ContextVar
 from itertools import chain, product
@@ -450,30 +451,61 @@ class ArgumentParser(ArgParser):
     if TYPE_CHECKING:
 
         @overload
-        def parse_args(
-            self, args: Optional[Sequence[Union[str, MessageSegment]]] = ...
-        ) -> Namespace:
+        def parse_known_args(
+            self,
+            args: Optional[Sequence[Union[str, MessageSegment]]] = None,
+            namespace: None = None,
+        ) -> Tuple[Namespace, List[Union[str, MessageSegment]]]:
             ...
 
         @overload
-        def parse_args(
-            self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: None
-        ) -> Namespace:
-            ...  # type: ignore[misc]
+        def parse_known_args(
+            self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: T
+        ) -> Tuple[T, List[Union[str, MessageSegment]]]:
+            ...
 
         @overload
-        def parse_args(
-            self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: T
-        ) -> T:
+        def parse_known_args(
+            self, *, namespace: T
+        ) -> Tuple[T, List[Union[str, MessageSegment]]]:
             ...
 
-        def parse_args(
+        def parse_known_args(
             self,
             args: Optional[Sequence[Union[str, MessageSegment]]] = None,
             namespace: Optional[T] = None,
-        ) -> Union[Namespace, T]:
+        ) -> Tuple[Union[Namespace, T], List[Union[str, MessageSegment]]]:
             ...
 
+    @overload
+    def parse_args(
+        self,
+        args: Optional[Sequence[Union[str, MessageSegment]]] = None,
+        namespace: None = None,
+    ) -> Namespace:
+        ...
+
+    @overload
+    def parse_args(
+        self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: T
+    ) -> T:
+        ...
+
+    @overload
+    def parse_args(self, *, namespace: T) -> T:
+        ...
+
+    def parse_args(
+        self,
+        args: Optional[Sequence[Union[str, MessageSegment]]] = None,
+        namespace: Optional[T] = None,
+    ) -> Union[Namespace, T]:
+        result, argv = self.parse_known_args(args, namespace)
+        if argv:
+            msg = gettext("unrecognized arguments: %s")
+            self.error(msg % " ".join(map(str, argv)))
+        return cast(Union[Namespace, T], result)
+
     def _parse_optional(
         self, arg_string: Union[str, MessageSegment]
     ) -> Optional[Tuple[Optional[Action], str, Optional[str]]]:


Test patch:
diff --git a/tests/test_rule.py b/tests/test_rule.py
--- a/tests/test_rule.py
+++ b/tests/test_rule.py
@@ -371,6 +371,19 @@ async def test_shell_command():
     assert state[SHELL_ARGS].status != 0
     assert state[SHELL_ARGS].message.startswith(parser.format_usage() + "test: error:")
 
+    test_parser_remain_args = shell_command(CMD, parser=parser)
+    dependent = list(test_parser_remain_args.checkers)[0]
+    checker = dependent.call
+    assert isinstance(checker, ShellCommandRule)
+    message = MessageSegment.text("-a 1 2") + MessageSegment.image("test")
+    event = make_fake_event(_message=message)()
+    state = {PREFIX_KEY: {CMD_KEY: CMD, CMD_ARG_KEY: message}}
+    assert await dependent(event=event, state=state)
+    assert state[SHELL_ARGV] == ["-a", "1", "2", MessageSegment.image("test")]
+    assert isinstance(state[SHELL_ARGS], ParserExit)
+    assert state[SHELL_ARGS].status != 0
+    assert state[SHELL_ARGS].message.startswith(parser.format_usage() + "test: error:")
+
     test_message_parser = shell_command(CMD, parser=parser)
     dependent = list(test_message_parser.checkers)[0]
     checker = dependent.call