Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SG-17742 Attempt to fix the crash issue with Houdini #83

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions python/app/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from .note_updater import NoteUpdater
from .widget_all_fields import AllFieldsWidget
from .work_area_dialog import WorkAreaDialog
from .utils import monitor_qobject_lifetime

shotgun_model = sgtk.platform.import_framework(
"tk-framework-shotgunutils", "shotgun_model"
Expand Down Expand Up @@ -135,8 +136,10 @@ def __init__(self, parent=None):

# create a background task manager
self._task_manager = task_manager.BackgroundTaskManager(
self, start_processing=True, max_threads=2
self, max_threads=2
)
monitor_qobject_lifetime(self._task_manager, "Main task manager")
self._task_manager.start_processing()

# register the data fetcher with the global schema manager
shotgun_globals.register_bg_task_manager(self._task_manager)
Expand Down Expand Up @@ -278,6 +281,10 @@ def closeEvent(self, event):
# close splash
self._overlay.hide()

# destroy the current Qt Model
self._overlay.destroy()
self.destroy()

# okay to close dialog
event.accept()

Expand Down Expand Up @@ -869,7 +876,7 @@ def _change_work_area(self, entity_type, entity_id):
}

self._app.log_debug(
"Creating new task:\n%s" % pprint.pprint(sg_data)
"Creating new task:\n%s" % pprint.pformat(sg_data)
)
task_data = self._app.shotgun.create("Task", sg_data)
(entity_type, entity_id) = (task_data["type"], task_data["id"])
Expand Down Expand Up @@ -1208,6 +1215,8 @@ def setup_entity_model_view(self, entity_data):
entity_data["model"] = ModelClass(
entity_data["entity_type"], entity_data["view"], self._task_manager
)
monitor_qobject_lifetime(entity_data["model"])


# create proxy for sorting
entity_data["sort_proxy"] = FilterItemProxyModel(self)
Expand Down
60 changes: 60 additions & 0 deletions python/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,63 @@ def create_human_readable_timestamp(datetime_obj):
time_str = datetime_obj.strftime("%H:%M")

return (time_str, full_time_str)


# storage for any tracked qobjects
_g_monitored_qobjects = {}


def monitor_qobject_lifetime(obj, name=""):
"""
Debug method to help track the lifetime of a QObject derived instance. Hooks into
the instances destroyed signal to report when the QObject has been destroyed.

:param obj: The QObject instance to monitor
:param name: An optional name to be appended to the debug output, useful for identifying
a specific instance of a class.
"""
msg = type(obj).__name__
if name:
msg = "%s [%s]" % (msg, name)

app = sgtk.platform.current_bundle()

global _g_monitored_qobjects
uid = len(_g_monitored_qobjects)
_g_monitored_qobjects[uid] = msg
obj.destroyed.connect(lambda m=msg, u=uid: _on_qobject_destroyed(m, u))


def _on_qobject_destroyed(name, uid):
"""
Slot triggered whenever a monitored qobject is destroyed - reports to debug that the object
was destroyed.

:param name: Name of the instance that was destroyed
:param uid: Unique id of the QObject used to look it up in the monitored list
"""
app = sgtk.platform.current_bundle()
app.log_debug("%s destroyed" % name)
global _g_monitored_qobjects
if uid in _g_monitored_qobjects:
del _g_monitored_qobjects[uid]
carlos-villavicencio-adsk marked this conversation as resolved.
Show resolved Hide resolved


def report_non_destroyed_qobjects(clear_list=True):
"""
Report any monitored QObjects that have not yet been destroyed. Care should be taken to
account for QObjects that are pending destruction via deleteLater signals that may be
pending.

:param clear_list: If true then the list of monitored QObjects will be cleared after
this function has reported them.
"""
app = sgtk.platform.current_bundle()
global _g_monitored_qobjects
app.log_debug(
"%d monitored QObjects have not been destroyed!" % len(_g_monitored_qobjects)
)
for msg in _g_monitored_qobjects.values():
app.log_debug(" - %s" % msg)
if clear_list:
_g_monitored_qobjects = {}
carlos-villavicencio-adsk marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion python/app/widget_all_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def clear(self):
# set it's parent to None so that it is removed from the widget hierarchy
x.setParent(None)
# mark it to be deleted when event processing returns to the main loop
x.deleteLater()
x.destroy()
julien-lang marked this conversation as resolved.
Show resolved Hide resolved

self._widgets = []

Expand Down
Loading