mcpField
P
pyside6-reviewer

pyside6-reviewer

github.com/akiselev测试与质量4214 次安装39 周前更新
代码仓库

关于 pyside6-reviewer

面向现代 PySide6 和 Qt 6.8+ 应用的代码审查技能,供审查者检查线程、信号槽、模型、资源生命周期、异步代码和 QML 集成,并提供参考资料与 PR 清单。

主要功能

  1. 01检查 Qt 6.8+ 兼容性
  2. 02审查线程安全
  3. 03验证信号与槽
  4. 04检查模型/视图和 QML
  5. 05审查资源与异步模式
  6. 06提供参考资料和 PR 清单

适用场景

  1. 01审查 PySide6 拉取请求
  2. 02查找跨线程 GUI 访问风险
  3. 03检查信号与槽签名
  4. 04评估模型/视图或 QML 代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/akiselev/qt-llm-template --skill pyside6-reviewer

安装后在 Claude Code 中输入/pyside6-reviewer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

anti-patterns.md
model-view.md
performance.md
qml-integration.md
review.py
signals-slots.md
threading.md
widgets.md

详细介绍

PySide6 代码审查

针对现代 PySide6/Qt 6.8+ 应用的专业代码审查。

审查流程

  1. 确认 Qt 版本假设 — 验证代码面向 Qt 6.8+(不兼容 Qt5)
  2. 检查线程安全 — 所有 GUI 操作都在主线程上执行,并采用正确的工作线程模式
  3. 验证信号/槽用法 — 使用现代连接语法,并确保签名正确
  4. 评估 Model/View 实现 — 检查角色用法、数据方法模式和索引有效性
  5. 检查资源管理 — 检查父子所有权,防止泄漏
  6. 评估异步模式 — 检查 QThread、QtConcurrent、asyncio 集成
  7. 检查 QML 集成 — 检查属性绑定、类型注册和上下文公开

必须指出的关键反模式

# WRONG: GUI operation from worker thread
class Worker(QThread):
    def run(self):
        self.label.setText("Done")  # CRASH: Cross-thread GUI access

# WRONG: Blocking the event loop
def on_button_click(self):
    time.sleep(5)  # FREEZES UI
    requests.get(url)  # FREEZES UI

# WRONG: Old-style signal connection (Qt4/5 legacy)
self.connect(button, SIGNAL("clicked()"), self.handler)

# WRONG: String-based slot connection
button.clicked.connect("self.handler")  # Should be callable

# WRONG: No parent = memory leak risk
label = QLabel("text")  # Should have parent or be assigned to layout

# WRONG: Deleting QObject while signals pending
obj.deleteLater()  # OK
del obj  # WRONG if signals/slots active

# WRONG: Direct widget manipulation in QThread.run()
class BadWorker(QThread):
    def run(self):
        self.progress_bar.setValue(50)  # Thread violation!

必须采用的现代模式

信号/槽连接
# Qt 6 style - always use this
button.clicked.connect(self.on_click)
button.clicked.connect(lambda: self.handler(arg))

# Typed signals with modern syntax
class Worker(QObject):
    progress = Signal(int)          # Single type
    result = Signal(str, list)      # Multiple types
    error = Signal(Exception)       # Exception passing
    finished = Signal()             # No arguments
线程安全的工作线程模式
class Worker(QObject):
    finished = Signal()
    progress = Signal(int)
    result = Signal(object)
    error = Signal(str)

    @Slot()
    def run(self):
        try:
            for i in range(100):
                # Do work
                self.progress.emit(i)
            self.result.emit(data)
        except Exception as e:
            self.error.emit(str(e))
        finally:
            self.finished.emit()

# Usage
thread = QThread()
worker = Worker()
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.finished.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater)
thread.start()
异步集成(Qt 6.8+)
import asyncio
from PySide6.QtAsyncio import QAsyncioEventLoopPolicy

# Set up asyncio with Qt event loop
asyncio.set_event_loop_policy(QAsyncioEventLoopPolicy())

class AsyncWidget(QWidget):
    async def fetch_data(self):
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                return await response.json()
    
    def start_fetch(self):
        asyncio.ensure_future(self.fetch_data())

详细参考文件

审查清单(用于 PR)

线程安全
  • 所有 widget/GUI 调用仅在主线程上执行
  • 工作线程使用信号/槽更新 UI
  • 主线程中没有 time.sleep() 或阻塞调用
  • QThread 子类仅重写 run(),不在构造函数中执行工作
  • 正确使用 moveToThread()(对象没有父对象)
内存管理
  • Widget 有父对象,或已添加到布局中
  • 对 QObject 使用 deleteLater(),绝不使用 del
  • Lambda 连接不会捕获过期引用
  • 避免循环信号连接
  • 模型数据按值而非按引用返回
信号/槽正确性
  • 使用现代连接语法(不使用字符串)
  • 信号签名与槽签名匹配
  • 所有槽都使用 @Slot() 装饰器
  • 跨线程信号使用 Qt.QueuedConnection
  • 信号定义为类属性
Model/View
  • 使用 beginInsertRows()/endInsertRows() 包围更改操作
  • 更新时发射 dataChanged
  • 访问前检查 index.isValid()
  • 自定义角色使用 Qt.UserRole + n
  • 为兼容 QML 重写 roleNames()
性能
  • 不在绘制事件中创建 widget
  • 重绘时使用 update(),而非 repaint()
  • 大型列表使用 QAbstractItemModel(而非 QListWidget)
  • 对开销较大的数据进行延迟加载
  • 批量更新期间使用 blockSignals()
Qt 6.8+ 特性
  • 使用新的枚举作用域(Qt.AlignmentFlag.AlignCenter)
  • 异步模式使用 QtAsyncio(而非第三方库)
  • 使用 QML_ELEMENT 宏对应的方式注册类型
  • 适用时通过 QProperty 进行属性绑定
  • 使用新的 QPermission API 管理平台权限

评论

支持 Markdown