From f0068477c6ecd572e46818ebafdf01ad85e133ef Mon Sep 17 00:00:00 2001 From: Julien Langlois Date: Mon, 9 Feb 2026 13:23:41 -0800 Subject: [PATCH 1/3] Test fixup threading seg fault PySide .... --- tests/python/tank_test/tank_test_base.py | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/python/tank_test/tank_test_base.py b/tests/python/tank_test/tank_test_base.py index 14a932ac8..cec7ad18a 100644 --- a/tests/python/tank_test/tank_test_base.py +++ b/tests/python/tank_test/tank_test_base.py @@ -617,6 +617,8 @@ def _tearDown(self): # important to delete this to free memory self.tk = None + self.cleanup_qtapp() + # clear global shotgun accessor tank.util.shotgun.connection._g_sg_cached_connections = threading.local() finally: @@ -625,6 +627,37 @@ def _tearDown(self): else: del os.environ[self.SHOTGUN_HOME] + @classmethod + def cleanup_qtapp(cls): + # Process Qt events to allow deleteLater() to complete before cleanup + # This prevents random segfaults in Qt object destruction + + # Import Qt for event processing in tearDown + try: + from tank.platform.qt import QtCore + except ImportError: + print("Qt not found, skipping event processing in tearDown.") + return + + if QtCore.QCoreApplication is None: + print("No QCoreApplication instance found, skipping event processing in tearDown.") + return + + print("Processing Qt events in tearDown to allow deleteLater() to complete.") + app = QtCore.QCoreApplication.instance() + if app is None: + print("No QCoreApplication instance found, skipping event processing in tearDown.") + return + + print("QCoreApplication instance: %s" % app) + print("Call processEvents() to allow deleteLater() to complete.") + app.processEvents() + print("Wait a bit to ensure all events are processed.") + time.sleep(2) + print("Call again process events() to ensure all events are processed.") + app.processEvents() + + @timer.clock_func("TankTestBase.setup_fixtures") def setup_fixtures(self, name="config", parameters=None): """ From 2e3566436505b54aef9776281b501cc7fabf1e03 Mon Sep 17 00:00:00 2001 From: Julien Langlois Date: Mon, 9 Feb 2026 15:37:32 -0800 Subject: [PATCH 2/3] tests --- azure-pipelines.yml | 2 +- tests/python/tank_test/tank_test_base.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9fb3e0d6e..5d25883cb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -31,7 +31,7 @@ trigger: pr: branches: include: - - "*" + - nothing # This pulls in a variable group from Azure. Variables can be encrypted or not. variables: diff --git a/tests/python/tank_test/tank_test_base.py b/tests/python/tank_test/tank_test_base.py index cec7ad18a..53a3f048f 100644 --- a/tests/python/tank_test/tank_test_base.py +++ b/tests/python/tank_test/tank_test_base.py @@ -596,36 +596,57 @@ def _tearDown(self): """ Cleans up after tests. """ + + logger = sgtk.platform.get_logger(__name__) + logger.info("Tearing down test: %s" % self.short_test_name) + self._tear_down_called = True try: sgtk.set_authenticated_user(self._authenticated_user) + logger.info("status 2") + if self._do_io: # get rid of path cache from local ~/.shotgun storage pc = path_cache.PathCache(self.tk) path_cache_file = pc._get_path_cache_location() pc.close() + + logger.info("status 3") + if os.path.exists(path_cache_file): os.remove(path_cache_file) + logger.info("status 4") + # get rid of init cache if os.path.exists(pipelineconfig_factory._get_cache_location()): os.remove(pipelineconfig_factory._get_cache_location()) + logger.info("status 5") + # move project scaffold out of the way self._move_project_data() # important to delete this to free memory self.tk = None + logger.info("status 6") + self.cleanup_qtapp() + logger.info("status 7") + # clear global shotgun accessor tank.util.shotgun.connection._g_sg_cached_connections = threading.local() + + logger.info("status 8") finally: + logger.info("status finally 1") if self._old_shotgun_home is not None: os.environ[self.SHOTGUN_HOME] = self._old_shotgun_home else: del os.environ[self.SHOTGUN_HOME] + logger.info("status finally 2") @classmethod def cleanup_qtapp(cls): From fa73f415652b8cd7f58a447e1039183c6a437017 Mon Sep 17 00:00:00 2001 From: Julien Langlois Date: Mon, 9 Feb 2026 15:43:51 -0800 Subject: [PATCH 3/3] tests --- tests/python/tank_test/tank_test_base.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/python/tank_test/tank_test_base.py b/tests/python/tank_test/tank_test_base.py index 53a3f048f..b0378f0a4 100644 --- a/tests/python/tank_test/tank_test_base.py +++ b/tests/python/tank_test/tank_test_base.py @@ -653,30 +653,38 @@ def cleanup_qtapp(cls): # Process Qt events to allow deleteLater() to complete before cleanup # This prevents random segfaults in Qt object destruction + logger = sgtk.platform.get_logger(__name__) + + logger.info("cleanup_qtapp 01") # Import Qt for event processing in tearDown try: from tank.platform.qt import QtCore except ImportError: - print("Qt not found, skipping event processing in tearDown.") + logger.warning("Qt not found, skipping event processing in tearDown.") return + logger.info("cleanup_qtapp 02") + if QtCore.QCoreApplication is None: - print("No QCoreApplication instance found, skipping event processing in tearDown.") + logger.warning("No QCoreApplication instance found, skipping event processing in tearDown.") return - print("Processing Qt events in tearDown to allow deleteLater() to complete.") + logger.info("cleanup_qtapp 03") + app = QtCore.QCoreApplication.instance() if app is None: - print("No QCoreApplication instance found, skipping event processing in tearDown.") + logger.warning("No QCoreApplication instance found, skipping event processing in tearDown.") return - print("QCoreApplication instance: %s" % app) - print("Call processEvents() to allow deleteLater() to complete.") + logger.info("cleanup_qtapp 04") + app.processEvents() - print("Wait a bit to ensure all events are processed.") + logger.info("cleanup_qtapp 05") + time.sleep(2) - print("Call again process events() to ensure all events are processed.") + logger.info("cleanup_qtapp 06") app.processEvents() + logger.info("cleanup_qtapp 07") @timer.clock_func("TankTestBase.setup_fixtures")