pyside6-reviewer
SKILL.md
PySide6 Code Reviewer
Expert code review for modern PySide6/Qt 6.8+ applications.
Review Process
- Identify Qt version assumptions — Verify code targets Qt 6.8+ (no Qt5 compat)
- Check thread safety — All GUI operations on main thread, proper worker patterns
- Validate signal/slot usage — Modern connection syntax, proper signatures
- Assess Model/View implementation — Role usage, data method patterns, index validity
- Review resource management — Parent-child ownership, prevent leaks
- Evaluate async patterns — QThread, QtConcurrent, asyncio integration
- Check QML integration — Property bindings, type registration, context exposure
Critical Anti-Patterns (Always Flag)
# 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!
Modern Patterns (Require These)
Signal/Slot Connections
# 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
Thread-Safe Worker Pattern
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()
Async Integration (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())
Detailed Reference Files
- references/signals-slots.md — Signal/slot patterns, connection types, thread-safe emission
- references/model-view.md — QAbstractItemModel, roles, proxies, delegates
- references/threading.md — QThread, QtConcurrent, async patterns, thread pools
- references/widgets.md — Widget lifecycle, layouts, styling, high-DPI
- references/qml-integration.md — QML/Python bridge, properties, type registration
- references/performance.md — Paint optimization, model efficiency, lazy loading
- references/anti-patterns.md — Comprehensive anti-pattern catalog with fixes
Review Checklist (Use for PRs)
Thread Safety
- All widget/GUI calls on main thread only
- Workers use signal/slot for UI updates
- No
time.sleep()or blocking calls in main thread -
QThreadsubclass only overridesrun(), not constructor work -
moveToThread()used correctly (object has no parent)
Memory Management
- Widgets have parents OR are added to layouts
-
deleteLater()used for QObjects, neverdel - Lambda connections don't capture stale references
- Circular signal connections avoided
- Model data returned by value, not reference
Signal/Slot Correctness
- Modern connection syntax (no strings)
- Signal signatures match slot signatures
-
@Slot()decorator on all slots -
Qt.QueuedConnectionfor cross-thread signals - Signals defined as class attributes
Model/View
-
beginInsertRows()/endInsertRows()bracket changes -
dataChangedemitted for updates -
index.isValid()checked before access - Custom roles use
Qt.UserRole + n -
roleNames()override for QML compatibility
Performance
- No widget creation in paint events
-
update()notrepaint()for redraws - Large lists use QAbstractItemModel (not QListWidget)
- Lazy loading for expensive data
-
blockSignals()during batch updates
Qt 6.8+ Specifics
- Using new enum scoping (
Qt.AlignmentFlag.AlignCenter) -
QtAsynciofor async patterns (not third-party) -
QML_ELEMENTmacro equivalents for type registration - Property bindings via
QPropertywhere appropriate - New
QPermissionAPI for platform permissions
Weekly Installs
22
Repository
akiselev/qt-llm-templateGitHub Stars
1
First Seen
Feb 21, 2026
Security Audits
Installed on
codex22
github-copilot21
amp21
kimi-cli21
gemini-cli21
cursor21