mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-09-22 23:08:08 +03:00
5.3 KiB
5.3 KiB
Qt foundation guidance
Use the manage-qt-pyside6-lifetimes skill for QObject ownership, transient/reusable UI, signal retention, or packaged
PySide6 lifetime work.
Inherit the root and package guides. This scope owns reusable Qt presentation, translation/theme behavior, and lifetime primitives; pages and services consume them without creating parallel registries.
Canonical presentation
- Reuse
Furious.QtAppQ*controls,AppStyleSheet, translation/theme mixins, and shared dialog/window infrastructure. Do not create parallel style, theme-transition, translation, or lifetime registries. - Controls that retranslate retain source text; semantic/user-defined values stay untranslated. Preserve keyboard focus, shortcut scope, accessibility, translated-text growth, responsive layout, high-DPI behavior, and both themes.
- Application-owned theme transitions commit destination state immediately; snapshots are non-interactive presentation objects that are interrupted/disposed on replacement, geometry change, window destruction, or application cleanup.
Ownership and destruction
- Classify each Qt object as application-lifetime, reusable, or transient. Record its Python owner, QObject parent, close/hide/destroy path, and every timer, model, delegate, action, menu, animation, effect, event filter, reply, worker, callback, cache, and signal edge that may extend the lifetime.
- Reusable windows retain one explicit owner and reset on reopen. One-shot dialogs use
AppQTransientDialogorAppQMessageBox;open()registers their strong async owner through native destruction and releases the token on the next event-loop turn. Plain dialogshow()does not enter that registry and needs another durable owner.finishedends interaction, not native lifetime; operation context may be released then only if later callbacks do not need it. AppQDialog/AppQMainWindowregistries bridge asynchronous presentation/visibility; they are not substitute application owners. Registry cleanup captures opaque tokens, never the object being released.- A Qt parent alone does not prove the Python wrapper or logical feature lifetime. Bare Qt
.show()does not retain an unparented wrapper;AppQMainWindow.show()adds its own visible-window retention until accepted close. Do not solve ambiguity by global retention, indiscriminate delete-on-close, routinegc.collect(), or broad deleted-wrapper suppression.
Signals, threads, and async Qt work
- Only the GUI thread mutates widgets/live GUI models. Slots do not sleep or perform unbounded file, host, process, or network work; split work into bounded event-loop units or an owned worker and reject stale results on return.
- Native and Nuitka PySide6 can retain Python callbacks differently. A transient/repeated receiver must not be connected
through a compiled bound method or a closure/partial that strongly captures it. Use
connectWeakly()with a static method name andsender=when the sender is independent/longer-lived; useforwardSender=Trueinstead of relying onQObject.sender()andsingleShotWeakly()for deferred named-method delivery. - Direct connections are appropriate for deliberately shared persistent lifetimes; syntax alone does not prove a leak. Recheck the selected Nuitka/PySide6 callback protection when the toolchain changes. Static weak method names are runtime contracts, so renames must update registrations and tests. Weak dispatch itself does not marshal arbitrary worker calls to the GUI thread; choose an explicit queued owner-thread delivery boundary.
AppQAction.callbackis strong by design, so the action owner cannot outlive the captured receiver.- Every
QNetworkReplyhas one manager/context owner, one freshness rule, and one terminal deletion path. Do not attach ad-hoc attributes to third-party Qt objects or multiply timers/connections across show/hide cycles. - Queued delivery never transfers ownership implicitly. The sender may finish before delivery, so callbacks resolve a still-valid receiver and current generation in the receiver's Qt thread before touching widgets, models, or wrappers.
Geometry and verification
- Top-level windows use canonical first-show preparation. Save geometry/state only after a native presentation; a never-shown Qt fallback must not overwrite persisted user geometry. Do not call overridable geometry hooks from constructors or manipulate private first-show state.
- When behavior depends on focus, selection, proxy mapping, modifiers, shortcuts, queued delivery, animation, geometry,
or destruction, construct real widgets and use
QTestplus the real event loop. Test semantic state and lifecycle, not private coordinates or pixel-perfect screenshots. - For lifetime-sensitive changes, repeat open/close/accept/reject paths and assert destroyed signals, weak wrappers,
registries, timers, callbacks, replies, threads, handles, and child counts return to baseline. Run a
representative Nuitka probe when compiled callback retention or packaged-only behavior is part of the defect.
Start with
tests/test_qt_lifetime.py,tests/test_dialog_geometry.py, andtests/test_main_window_geometry.py; use thetests/fixtures/editor_lifetime_probe.pyfixture for compiled investigation. Treat unrun packaged probes as unverified, and update these rules when measured ownership or the toolchain changes.