Skip to content

Conversation

@shangxueink
Copy link
Contributor

@shangxueink shangxueink commented Sep 16, 2025

承接自 #2686 (comment)

由于上次通过PR之后,我观察到 satori_adapter.py 文件没有得到更新,所以此前的改动内容与本次xml相关优化改动 在此次PR中一并提交


Motivation / 动机

此PR旨在优化Satori平台适配器中的XML解析逻辑,完全移除对正则表达式的依赖。

原先的代码在处理XML命名空间前缀和<quote>标签时使用了正则表达式,不够安全和可靠。

混合使用正则表达式和XML解析器导致代码不一致。

Modifications / 改动点

核心改动文件:
astrbot/core/platform/sources/satori/satori_adapter.py

主要改动:

  1. 新增 _extract_namespace_prefixes 方法,使用字符串遍历方式替代正则表达式提取XML命名空间前缀
  2. 新增 _extract_quote_element 方法,使用统一的XML解析器处理quote标签
  3. 移除所有正则表达式的使用,确保XML处理逻辑的一致性

Verification Steps / 验证步骤

  1. 启动AstrBot并连接到 liteloader onebot 实现的 Satori协议的平台

注意:不同Satori协议实现可能有不同的消息格式。

在koishi平台使用adapter-satori并开启server-satori实现的Satori协议中,小程序内容会被直接解析为ark消息;

而在koishi平台使用adapter-onebot并开启server-satori实现的Satori协议中,小程序内容会被adapter-onebot适配器解析为json内容,进而被上报为json消息。

  1. 发送包含XML标签的消息(如包含<quote><at><img>等标签)

  2. 验证消息能被正确解析和处理

  3. 特别测试包含命名空间前缀的XML内容是否能正确处理(例如音乐卡片、小程序卡片)

Screenshots or Test Results / 运行截图或测试结果

 [20:34:34] [Core] [INFO] [satori.satori_adapter:123]: Satori 适配器正在连接到 WebSocket: ws://localhost:5600/v1/events
 [20:34:34] [Core] [INFO] [satori.satori_adapter:124]: Satori 适配器 HTTP API 地址: http://localhost:5600/v1
 [20:34:34] [Core] [INFO] [core.core_lifecycle:201]: AstrBot 启动完成。
[2025-09-16 20:34:34 +0800] [13456] [INFO] Running on http://0.0.0.0:6185 (CTRL + C to quit)
 [20:34:36] [Core] [INFO] [satori.satori_adapter:235]: Satori 连接成功 - Bot 1: platform=llonebot, user_id=1787850032, user_name=猫猫不是喵喵
 [20:34:38] [Core] [INFO] [core.event_bus:52]: [default] [satori(satori)] 上学/1919892171: [ARK卡片数据: {"ver":"1.0.0.19","prompt":"[QQ小程序]千早爱音和丰川祥子暴风骤雨开一局","config":{"type":"normal","width":0,"height":0,"forward":1,"autoSize":0,"ctime":1757412165,"token":"7f1b79e050f9b2975ae956a0f8283924"},"needShareCallBack":false,"app":"com.tencent.miniapp_01","view":"view_8C8E89B49BE609866298ADDFF2DBABA4","meta":{"detail_1":{"appid":"1109937557","appType":0,"title":"哔哩哔哩","desc":"千早爱音和丰川祥子暴风骤雨开一局","icon":"https:\/\/open.gtimg.cn\/open\/app_icon\/00\/95\/17\/76\/100951776_100_m.png?t=1757003233","preview":"https:\/\/qq.ugcimg.cn\/v1\/qa0m914o2lsi0n44b3j7qiv2ocj68196vf72di8k9u5krpsmjftt39m57fnvfko9o81kcnc0g87kbahte9q0928lgoqoapo1f34a838a4up767n43rgh68m2b10p5vvkiejrauk0dv3quku97emc1ids2k\/e9vf2tsqr6j29hl2kodb3vahlc","url":"m.q.qq.com\/a\/s\/b3e7ce16fa80252c94a01a4accc83b5a","scene":1036,"host":{"uin":3075693513,"nick":"薪尽自然凉"},"shareTemplateId":"8C8E89B49BE609866298ADDFF2DBABA4","shareTemplateData":{},"qqdocurl":"https:\/\/b23.tv\/0AsJQoT?share_medium=android&share_source=qq&bbid=XXC0516CA6B10221D0DCE8B753857D333BFE3&ts=1757412165309","showLittleTail":"","gamePoints":"","gamePointsUrl":"","shareOrigin":0}}}]

Compatibility & Breaking Changes / 兼容性与破坏性变更

  • 所有正则表达式已被移除
  • XML解析逻辑统一且更加安全
  • 代码可读性和可维护性得到提升

此变更为内部实现优化,不改变任何对外接口和功能行为,完全向后兼容。

  • 这是一个破坏性变更 (Breaking Change)。/ This is a breaking change.
  • 这不是一个破坏性变更。/ This is NOT a breaking change.

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了"验证步骤"和"运行截图"。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Sourcery 总结

优化 Satori 平台适配器,移除所有基于正则表达式的 XML 解析并统一消息元素处理

新功能:

  • 实现命名空间前缀提取,不使用正则表达式
  • 添加 <quote> 元素的专用提取并转换为 Reply 组件的功能
  • 支持将 face、ark 和 JSON 卡片元素结构化解析为纯文本

改进:

  • 将混合的正则表达式和 XML 解析替换为一致的 XML 解析器,并在出错时回退到纯文本
  • __init__ 中引入 PlatformMetadata 初始化,并在 meta() 中返回它
  • 通过使用统一的元素构造函数简化图像、文件和音频元素处理

杂项:

  • 将默认 Satori 端点更新为 ws://localhost:5140
  • satori_adapter 中移除所有剩余的正则表达式依赖
Original summary in English

Summary by Sourcery

Optimize the Satori platform adapter by removing all regex-based XML parsing and unifying message element handling

New Features:

  • Implement namespace prefix extraction without using regular expressions
  • Add dedicated extraction and conversion of elements into Reply components
  • Support structured parsing of face, ark, and JSON card elements as plain text

Enhancements:

  • Replace mixed regex and XML parsing with a consistent XML parser and fallback to plain text on errors
  • Introduce PlatformMetadata initialization in init and return it in meta()
  • Simplify image, file, and audio element handling by using unified element constructors

Chores:

  • Update default Satori endpoint to ws://localhost:5140
  • Remove all remaining regular expression dependencies from satori_adapter

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 - 我已经审阅了你的更改 - 这里有一些反馈:

  • 自定义的 _extract_namespace_prefixes 方法可能会遗漏或错误处理复杂的命名空间场景——考虑使用 ElementTree 或 lxml 内置的命名空间支持,而不是手动字符串扫描。
  • 通过 content.replace() 移除 <quote> 可能会意外删除不必要的文本;更安全的方法是从解析后的 XML 树中直接删除该元素,然后重新序列化。
  • 注入 <root> 和命名空间声明的包装逻辑在多个方法中重复——将其提取到一个单独的辅助函数中,以减少重复并确保一致性。
供 AI 代理使用的提示
请解决此代码审查中的评论:

## 总体评论
- 自定义的 `_extract_namespace_prefixes` 方法可能会遗漏或错误处理复杂的命名空间场景——考虑使用 ElementTree 或 lxml 内置的命名空间支持,而不是手动字符串扫描。
- 通过 `content.replace()` 移除 `<quote>` 可能会意外删除不必要的文本;更安全的方法是从解析后的 XML 树中直接删除该元素,然后重新序列化。
- 注入 `<root>` 和命名空间声明的包装逻辑在多个方法中重复——将其提取到一个单独的辅助函数中,以减少重复并确保一致性。

## 单独评论

### 评论 1
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:475-476` </location>
<code_context>
+                        inner_content += child.tail
+                
+                # 构造移除了<quote>标签的内容
+                content_without_quote = content.replace(
+                    ET.tostring(quote_element, encoding='unicode', method='xml'), "")
+                
+                return {
</code_context>

<issue_to_address>
**issue (bug_risk):** 使用字符串替换来移除 <quote> 可能不适用于所有情况。

如果 XML 格式发生变化,使用字符串替换可能会失败。请使用 XML 解析器可靠地移除 <quote> 元素。
</issue_to_address>

### 评论 2
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:452-459` </location>
<code_context>
+            quote_element = None
+            for elem in root.iter():
+                tag_name = elem.tag
+                if '}' in tag_name:
+                    tag_name = tag_name.split('}')[1]
+                if tag_name.lower() == "quote":
</code_context>

<issue_to_address>
**suggestion:** 命名空间剥离假设命名空间标签中始终存在 '}'。

如果 XML 格式发生变化或使用不同的分隔符,此方法可能会失效。使用 xml.etree.ElementTree 的命名空间处理将使代码更健壮。

```suggestion
            quote_element = None
            for elem in root.iter():
                # Use ElementTree's QName to get the local name robustly
                try:
                    local_name = ET.QName(elem.tag).localname
                except AttributeError:
                    # Fallback for older Python versions or non-namespaced tags
                    local_name = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag
                if local_name.lower() == "quote":
                    quote_element = elem
                    break
```
</issue_to_address>

### 评论 3
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:605` </location>
<code_context>
-                    elements.append(Record.fromBase64(src))
-                elif src.startswith("http"):
-                    elements.append(Record.fromURL(src))
+                elements.append(Record(file=src))
+
+            elif tag_name == "quote":
</code_context>

<issue_to_address>
**issue (bug_risk):** 音频/记录处理现在仅使用文件参数,丢失了以前的格式检测。

此更新移除了特定于格式的处理,这可能会影响对 base64 和 URL 源的支持。请确认此更改是否是故意的,并审查可能存在的回归。
</issue_to_address>

### 评论 4
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:382` </location>
<code_context>
    def _extract_namespace_prefixes(self, content: str) -> set:
        """提取XML内容中的命名空间前缀"""
        prefixes = set()

        # 查找所有标签
        i = 0
        while i < len(content):
            # 查找开始标签
            if content[i] == '<' and i + 1 < len(content) and content[i + 1] != '/':
                # 找到标签结束位置
                tag_end = content.find('>', i)
                if tag_end != -1:
                    # 提取标签内容
                    tag_content = content[i + 1:tag_end]
                    # 检查是否有命名空间前缀
                    if ':' in tag_content and 'xmlns:' not in tag_content:
                        # 分割标签名
                        parts = tag_content.split()
                        if parts:
                            tag_name = parts[0]
                            if ':' in tag_name:
                                prefix = tag_name.split(':')[0]
                                # 确保是有效的命名空间前缀
                                if prefix.isalnum() or prefix.replace('_', '').isalnum():
                                    prefixes.add(prefix)
                    i = tag_end + 1
                else:
                    i += 1
            # 查找结束标签
            elif content[i] == '<' and i + 1 < len(content) and content[i + 1] == '/':
                # 找到标签结束位置
                tag_end = content.find('>', i)
                if tag_end != -1:
                    # 提取标签内容
                    tag_content = content[i + 2:tag_end]
                    # 检查是否有命名空间前缀
                    if ':' in tag_content:
                        prefix = tag_content.split(':')[0]
                        # 确保是有效的命名空间前缀
                        if prefix.isalnum() or prefix.replace('_', '').isalnum():
                            prefixes.add(prefix)
                    i = tag_end + 1
                else:
                    i += 1
            else:
                i += 1

        return prefixes

</code_context>

<issue_to_address>
**issue (code-quality):** 我们发现了这些问题:

- 使用命名表达式简化赋值和条件 ([`use-named-expression`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-named-expression/))
- 移除冗余条件 ([`remove-redundant-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/remove-redundant-if/))
- 在 SatoriPlatformAdapter.\_extract\_namespace\_prefixes 中发现低代码质量 - 16% ([`low-code-quality`](https://docs.sourcery.ai/Reference/Default-Rules/comments/low-code-quality/))

<br/><details><summary>解释</summary>

此函数的质量得分低于 25% 的质量阈值。
此得分是方法长度、认知复杂度和工作内存的组合。

如何解决这个问题?

重构此函数以使其更短、更具可读性可能是有益的。

- 通过将部分功能提取到自己的函数中来减少函数长度。这是你能做的最重要的事情——理想情况下,一个函数应该少于 10 行。
- 减少嵌套,例如通过引入守卫子句来提前返回。
- 确保变量的作用域紧密,以便使用相关概念的代码在函数内部紧密地放在一起,而不是分散开来。</details>
</issue_to_address>

### 评论 5
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:498` </location>
<code_context>
    async def _convert_quote_message(self, quote: dict) -> Optional[AstrBotMessage]:
        """转换引用消息"""
        try:
            quote_abm = AstrBotMessage()
            quote_abm.message_id = quote.get("id", "")

            # 解析引用消息的发送者
            quote_author = quote.get("author", {})
            if quote_author:
                quote_abm.sender = MessageMember(
                    user_id=quote_author.get("id", ""),
                    nickname=quote_author.get("nick", quote_author.get("name", "")),
                )
            else:
                # 如果没有作者信息,使用默认值
                quote_abm.sender = MessageMember(
                    user_id=quote.get("user_id", ""),
                    nickname="内容",
                )

            # 解析引用消息内容
            quote_content = quote.get("content", "")
            quote_abm.message = await self.parse_satori_elements(quote_content)

            quote_abm.message_str = ""
            for comp in quote_abm.message:
                if isinstance(comp, Plain):
                    quote_abm.message_str += comp.text

            quote_abm.timestamp = int(quote.get("timestamp", time.time()))

            # 如果没有任何内容,使用默认文本
            if not quote_abm.message_str.strip():
                quote_abm.message_str = "[引用消息]"

            return quote_abm
        except Exception as e:
            logger.error(f"转换引用消息失败: {e}")
            return None

</code_context>

<issue_to_address>
**issue (code-quality):** 使用命名表达式简化赋值和条件 ([`use-named-expression`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-named-expression/))
</issue_to_address>

Sourcery 对开源免费 - 如果你喜欢我们的评论,请考虑分享它们 ✨
帮助我更有用!请点击每个评论上的 👍 或 👎,我将使用这些反馈来改进你的评论。
Original comment in English

Hey there - I've reviewed your changes - here's some feedback:

  • The custom _extract_namespace_prefixes approach may miss or mis-handle complex namespace scenarios—consider using ElementTree’s or lxml’s built-in namespace support instead of manual string scanning.
  • Dropping the <quote> via content.replace() risks removing unintended text; it’s safer to remove the element directly from the parsed XML tree and then re-serialize.
  • The wrapping logic that injects <root> and namespace declarations is duplicated in several methods—extract it into a single helper to reduce repetition and ensure consistency.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The custom `_extract_namespace_prefixes` approach may miss or mis-handle complex namespace scenarios—consider using ElementTree’s or lxml’s built-in namespace support instead of manual string scanning.
- Dropping the `<quote>` via `content.replace()` risks removing unintended text; it’s safer to remove the element directly from the parsed XML tree and then re-serialize.
- The wrapping logic that injects `<root>` and namespace declarations is duplicated in several methods—extract it into a single helper to reduce repetition and ensure consistency.

## Individual Comments

### Comment 1
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:475-476` </location>
<code_context>
+                        inner_content += child.tail
+                
+                # 构造移除了<quote>标签的内容
+                content_without_quote = content.replace(
+                    ET.tostring(quote_element, encoding='unicode', method='xml'), "")
+                
+                return {
</code_context>

<issue_to_address>
**issue (bug_risk):** Using string replace to remove <quote> may not work for all cases.

Using string replacement may fail if XML formatting changes. Use an XML parser to reliably remove the <quote> element.
</issue_to_address>

### Comment 2
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:452-459` </location>
<code_context>
+            quote_element = None
+            for elem in root.iter():
+                tag_name = elem.tag
+                if '}' in tag_name:
+                    tag_name = tag_name.split('}')[1]
+                if tag_name.lower() == "quote":
</code_context>

<issue_to_address>
**suggestion:** Namespace stripping assumes '}' is always present for namespaced tags.

This approach may break if the XML format changes or uses different delimiters. Using xml.etree.ElementTree's namespace handling would make the code more robust.

```suggestion
            quote_element = None
            for elem in root.iter():
                # Use ElementTree's QName to get the local name robustly
                try:
                    local_name = ET.QName(elem.tag).localname
                except AttributeError:
                    # Fallback for older Python versions or non-namespaced tags
                    local_name = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag
                if local_name.lower() == "quote":
                    quote_element = elem
                    break
```
</issue_to_address>

### Comment 3
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:605` </location>
<code_context>
-                    elements.append(Record.fromBase64(src))
-                elif src.startswith("http"):
-                    elements.append(Record.fromURL(src))
+                elements.append(Record(file=src))
+
+            elif tag_name == "quote":
</code_context>

<issue_to_address>
**issue (bug_risk):** Audio/record handling now only uses the file parameter, losing previous format detection.

The update removes format-specific handling, which may affect support for base64 and URL sources. Please confirm if this change is intentional and review for possible regressions.
</issue_to_address>

### Comment 4
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:382` </location>
<code_context>
    def _extract_namespace_prefixes(self, content: str) -> set:
        """提取XML内容中的命名空间前缀"""
        prefixes = set()

        # 查找所有标签
        i = 0
        while i < len(content):
            # 查找开始标签
            if content[i] == '<' and i + 1 < len(content) and content[i + 1] != '/':
                # 找到标签结束位置
                tag_end = content.find('>', i)
                if tag_end != -1:
                    # 提取标签内容
                    tag_content = content[i + 1:tag_end]
                    # 检查是否有命名空间前缀
                    if ':' in tag_content and 'xmlns:' not in tag_content:
                        # 分割标签名
                        parts = tag_content.split()
                        if parts:
                            tag_name = parts[0]
                            if ':' in tag_name:
                                prefix = tag_name.split(':')[0]
                                # 确保是有效的命名空间前缀
                                if prefix.isalnum() or prefix.replace('_', '').isalnum():
                                    prefixes.add(prefix)
                    i = tag_end + 1
                else:
                    i += 1
            # 查找结束标签
            elif content[i] == '<' and i + 1 < len(content) and content[i + 1] == '/':
                # 找到标签结束位置
                tag_end = content.find('>', i)
                if tag_end != -1:
                    # 提取标签内容
                    tag_content = content[i + 2:tag_end]
                    # 检查是否有命名空间前缀
                    if ':' in tag_content:
                        prefix = tag_content.split(':')[0]
                        # 确保是有效的命名空间前缀
                        if prefix.isalnum() or prefix.replace('_', '').isalnum():
                            prefixes.add(prefix)
                    i = tag_end + 1
                else:
                    i += 1
            else:
                i += 1

        return prefixes

</code_context>

<issue_to_address>
**issue (code-quality):** We've found these issues:

- Use named expression to simplify assignment and conditional ([`use-named-expression`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-named-expression/))
- Remove redundant conditional ([`remove-redundant-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/remove-redundant-if/))
- Low code quality found in SatoriPlatformAdapter.\_extract\_namespace\_prefixes - 16% ([`low-code-quality`](https://docs.sourcery.ai/Reference/Default-Rules/comments/low-code-quality/))

<br/><details><summary>Explanation</summary>

The quality score for this function is below the quality threshold of 25%.
This score is a combination of the method length, cognitive complexity and working memory.

How can you solve this?

It might be worth refactoring this function to make it shorter and more readable.

- Reduce the function length by extracting pieces of functionality out into
  their own functions. This is the most important thing you can do - ideally a
  function should be less than 10 lines.
- Reduce nesting, perhaps by introducing guard clauses to return early.
- Ensure that variables are tightly scoped, so that code using related concepts
  sits together within the function rather than being scattered.</details>
</issue_to_address>

### Comment 5
<location> `astrbot/core/platform/sources/satori/satori_adapter.py:498` </location>
<code_context>
    async def _convert_quote_message(self, quote: dict) -> Optional[AstrBotMessage]:
        """转换引用消息"""
        try:
            quote_abm = AstrBotMessage()
            quote_abm.message_id = quote.get("id", "")

            # 解析引用消息的发送者
            quote_author = quote.get("author", {})
            if quote_author:
                quote_abm.sender = MessageMember(
                    user_id=quote_author.get("id", ""),
                    nickname=quote_author.get("nick", quote_author.get("name", "")),
                )
            else:
                # 如果没有作者信息,使用默认值
                quote_abm.sender = MessageMember(
                    user_id=quote.get("user_id", ""),
                    nickname="内容",
                )

            # 解析引用消息内容
            quote_content = quote.get("content", "")
            quote_abm.message = await self.parse_satori_elements(quote_content)

            quote_abm.message_str = ""
            for comp in quote_abm.message:
                if isinstance(comp, Plain):
                    quote_abm.message_str += comp.text

            quote_abm.timestamp = int(quote.get("timestamp", time.time()))

            # 如果没有任何内容,使用默认文本
            if not quote_abm.message_str.strip():
                quote_abm.message_str = "[引用消息]"

            return quote_abm
        except Exception as e:
            logger.error(f"转换引用消息失败: {e}")
            return None

</code_context>

<issue_to_address>
**issue (code-quality):** Use named expression to simplify assignment and conditional ([`use-named-expression`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/use-named-expression/))
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +475 to +476
content_without_quote = content.replace(
ET.tostring(quote_element, encoding='unicode', method='xml'), "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 使用字符串替换来移除 可能不适用于所有情况。

如果 XML 格式发生变化,使用字符串替换可能会失败。请使用 XML 解析器可靠地移除 元素。

Original comment in English

issue (bug_risk): Using string replace to remove may not work for all cases.

Using string replacement may fail if XML formatting changes. Use an XML parser to reliably remove the element.

Comment on lines +452 to +459
quote_element = None
for elem in root.iter():
tag_name = elem.tag
if '}' in tag_name:
tag_name = tag_name.split('}')[1]
if tag_name.lower() == "quote":
quote_element = elem
break
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: 命名空间剥离假设命名空间标签中始终存在 '}'。

如果 XML 格式发生变化或使用不同的分隔符,此方法可能会失效。使用 xml.etree.ElementTree 的命名空间处理将使代码更健壮。

Suggested change
quote_element = None
for elem in root.iter():
tag_name = elem.tag
if '}' in tag_name:
tag_name = tag_name.split('}')[1]
if tag_name.lower() == "quote":
quote_element = elem
break
quote_element = None
for elem in root.iter():
# Use ElementTree's QName to get the local name robustly
try:
local_name = ET.QName(elem.tag).localname
except AttributeError:
# Fallback for older Python versions or non-namespaced tags
local_name = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag
if local_name.lower() == "quote":
quote_element = elem
break
Original comment in English

suggestion: Namespace stripping assumes '}' is always present for namespaced tags.

This approach may break if the XML format changes or uses different delimiters. Using xml.etree.ElementTree's namespace handling would make the code more robust.

Suggested change
quote_element = None
for elem in root.iter():
tag_name = elem.tag
if '}' in tag_name:
tag_name = tag_name.split('}')[1]
if tag_name.lower() == "quote":
quote_element = elem
break
quote_element = None
for elem in root.iter():
# Use ElementTree's QName to get the local name robustly
try:
local_name = ET.QName(elem.tag).localname
except AttributeError:
# Fallback for older Python versions or non-namespaced tags
local_name = elem.tag.split('}')[-1] if '}' in elem.tag else elem.tag
if local_name.lower() == "quote":
quote_element = elem
break

logger.error(f"转换 Satori 消息失败: {e}")
return None

def _extract_namespace_prefixes(self, content: str) -> set:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): 我们发现了这些问题:


解释

此函数的质量得分低于 25% 的质量阈值。
此得分是方法长度、认知复杂度和工作内存的组合。

如何解决这个问题?

重构此函数以使其更短、更具可读性可能是有益的。

  • 通过将部分功能提取到自己的函数中来减少函数长度。这是你能做的最重要的事情——理想情况下,一个函数应该少于 10 行。
  • 减少嵌套,例如通过引入守卫子句来提前返回。
  • 确保变量的作用域紧密,以便使用相关概念的代码在函数内部紧密地放在一起,而不是分散开来。
Original comment in English

issue (code-quality): We've found these issues:


Explanation

The quality score for this function is below the quality threshold of 25%.
This score is a combination of the method length, cognitive complexity and working memory.

How can you solve this?

It might be worth refactoring this function to make it shorter and more readable.

  • Reduce the function length by extracting pieces of functionality out into
    their own functions. This is the most important thing you can do - ideally a
    function should be less than 10 lines.
  • Reduce nesting, perhaps by introducing guard clauses to return early.
  • Ensure that variables are tightly scoped, so that code using related concepts
    sits together within the function rather than being scattered.

quote_abm.message_id = quote.get("id", "")

# 解析引用消息的发送者
quote_author = quote.get("author", {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): 使用命名表达式简化赋值和条件 (use-named-expression)

Original comment in English

issue (code-quality): Use named expression to simplify assignment and conditional (use-named-expression)

@shangxueink shangxueink deleted the patch-3 branch October 14, 2025 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant