From d8a38c93bfbf80c8eb593e1f6b05255f41b159ec Mon Sep 17 00:00:00 2001 From: Loren Eteval Date: Wed, 9 Sep 2026 12:18:34 +0800 Subject: [PATCH] Improve readability and exception comments Signed-off-by: Loren Eteval --- Furious/Backends/Xray/AssetListView.py | 2 +- Furious/Core/ProcessOutput.py | 2 ++ Furious/Frozenlib/Win32Session.py | 2 ++ Furious/Qt/TextEditorTheme.py | 2 ++ Furious/Repository/Routings.py | 3 +++ Furious/Repository/Servers.py | 3 +++ Furious/Repository/Subscriptions.py | 3 +++ Furious/Repository/TunSettings.py | 2 ++ Furious/Service/EndpointInfoService.py | 4 ++++ Furious/Service/PluginUIManager.py | 6 ++++++ Furious/Service/ProfileTesting.py | 8 ++++++++ Furious/Window/SettingsPage.py | 4 ++++ tests/test_log_manager_generation.py | 27 ++++++++++++++++++++++++++ 13 files changed, 67 insertions(+), 1 deletion(-) diff --git a/Furious/Backends/Xray/AssetListView.py b/Furious/Backends/Xray/AssetListView.py index 11fb69b..801de93 100644 --- a/Furious/Backends/Xray/AssetListView.py +++ b/Furious/Backends/Xray/AssetListView.py @@ -173,7 +173,7 @@ class XrayAssetListView(Mixins.ThemeAware, AppQListView): # Same file imported. Do nothing pass except Exception as ex: - # Any non-exit exception + # Any non-exit exceptions _mbox = AppQMessageBox(icon=AppQMessageBox.Icon.Critical) _mbox.setText(_('Error import asset file')) diff --git a/Furious/Core/ProcessOutput.py b/Furious/Core/ProcessOutput.py index e489552..6d07a3e 100644 --- a/Furious/Core/ProcessOutput.py +++ b/Furious/Core/ProcessOutput.py @@ -76,6 +76,8 @@ class MsgQueue(multiprocessing.queues.Queue): try: return self.get_nowait() except Exception: + # Any non-exit exceptions + return '' def getTimeout(self) -> int: diff --git a/Furious/Frozenlib/Win32Session.py b/Furious/Frozenlib/Win32Session.py index caccd10..6317ac8 100644 --- a/Furious/Frozenlib/Win32Session.py +++ b/Furious/Frozenlib/Win32Session.py @@ -129,6 +129,8 @@ class _Win32Session: try: thread.start() except Exception: + # Any non-exit exceptions + if self._daemonThread is thread: self._daemonThread = None diff --git a/Furious/Qt/TextEditorTheme.py b/Furious/Qt/TextEditorTheme.py index 6349b3d..1285c4f 100644 --- a/Furious/Qt/TextEditorTheme.py +++ b/Furious/Qt/TextEditorTheme.py @@ -58,6 +58,8 @@ def _currentTheme(): try: return AppStyleSheet.normalizeTheme(themeGetter()) except Exception: + # Any non-exit exceptions + # A partially initialized application falls back to the safe default. pass diff --git a/Furious/Repository/Routings.py b/Furious/Repository/Routings.py index a5a4421..5d16246 100644 --- a/Furious/Repository/Routings.py +++ b/Furious/Repository/Routings.py @@ -56,7 +56,10 @@ class UserRoutings(Mixins.CleanupOnExit, StorageBackend): raise TypeError('routing repository root must be an object') except Exception: + # Any non-exit exceptions + self._restoreFailed = True + logger.exception('failed to restore persisted routings') return {} diff --git a/Furious/Repository/Servers.py b/Furious/Repository/Servers.py index 8ed027c..c933773 100644 --- a/Furious/Repository/Servers.py +++ b/Furious/Repository/Servers.py @@ -136,7 +136,10 @@ class UserServers(Mixins.CleanupOnExit, StorageBackend): raise TypeError('server repository root must contain a model list') except Exception: + # Any non-exit exceptions + self._restoreFailed = True + logger.exception('failed to restore persisted server configurations') return {'model': []} diff --git a/Furious/Repository/Subscriptions.py b/Furious/Repository/Subscriptions.py index f8a5b4b..b1b2db3 100644 --- a/Furious/Repository/Subscriptions.py +++ b/Furious/Repository/Subscriptions.py @@ -187,7 +187,10 @@ class UserSubs(Mixins.CleanupOnExit, StorageBackend): raise TypeError('subscription repository root must be an object') except Exception: + # Any non-exit exceptions + self._restoreFailed = True + logger.exception('failed to restore persisted subscriptions') return {} diff --git a/Furious/Repository/TunSettings.py b/Furious/Repository/TunSettings.py index 4bfc666..42f927b 100644 --- a/Furious/Repository/TunSettings.py +++ b/Furious/Repository/TunSettings.py @@ -56,6 +56,8 @@ class UserTUNSettings(Mixins.CleanupOnExit, StorageBackend): raise TypeError('TUN settings repository root must be an object') except Exception: + # Any non-exit exceptions + self._restoreFailed = True logger.exception('failed to restore persisted TUN settings') diff --git a/Furious/Service/EndpointInfoService.py b/Furious/Service/EndpointInfoService.py index 457c033..d666d0b 100644 --- a/Furious/Service/EndpointInfoService.py +++ b/Furious/Service/EndpointInfoService.py @@ -265,11 +265,13 @@ class EndpointInfoService(QtCore.QObject): self.controller = controller or AppConnectionController() self.httpClient = httpClient or ProxyEndpointHttpClient(self) self.proxyResolver = proxyResolver or Storage.Extras.UserHttpProxy + self._enabled = ( AppSettings.isStateON_(PROXY_ENDPOINT_INFO_SETTING) if enabled is None else bool(enabled) ) + self.state = EndpointInfoState.Disabled self.result = EndpointInfo() self._generation = 0 @@ -578,6 +580,8 @@ class EndpointInfoService(QtCore.QObject): organization=str(payload.get('org') or '').strip(), ) except Exception as ex: + # Any non-exit exceptions + logger.warning(f'approximate endpoint geolocation failed: {ex}') self._publishResult( diff --git a/Furious/Service/PluginUIManager.py b/Furious/Service/PluginUIManager.py index 95aa76a..96bb58c 100644 --- a/Furious/Service/PluginUIManager.py +++ b/Furious/Service/PluginUIManager.py @@ -76,6 +76,8 @@ class PluginNavigationManager: try: descriptors = tuple(provider.pageDescriptors()) except Exception as ex: + # Any non-exit exceptions + logger.error( f'plugin navigation provider ' f'{provider.capabilityId!r} failed: {ex}' @@ -102,6 +104,8 @@ class PluginNavigationManager: try: page = descriptor.factory(parent=navigationView) except Exception as ex: + # Any non-exit exceptions + logger.error(f'failed to create plugin page {pageId!r}: {ex}') continue @@ -123,6 +127,8 @@ class PluginNavigationManager: translatable=descriptor.translatable, ) except Exception as ex: + # Any non-exit exceptions + logger.error(f'failed to register plugin page {pageId!r}: {ex}') page.deleteLater() diff --git a/Furious/Service/ProfileTesting.py b/Furious/Service/ProfileTesting.py index 7968f8f..f8af4fc 100644 --- a/Furious/Service/ProfileTesting.py +++ b/Furious/Service/ProfileTesting.py @@ -259,6 +259,8 @@ class _PingWorker(QtCore.QRunnable): interval=1, ) except Exception as ex: + # Any non-exit exceptions + latency = classname(ex) else: if response.address and response.is_alive: @@ -393,6 +395,8 @@ class _LatencyScheduler(QtCore.QObject): try: endpointKey, address, port = self.tcpingEndpoint(job.target.snapshot) except Exception as ex: + # Any non-exit exceptions + self.completeJob(job, classname(ex)) continue @@ -693,6 +697,7 @@ class _DownloadSpeedWorker(HttpGetManager): self.profile = profile self.port = port self.options = options + self.result = ProfileTestResult( ProfileTestField.DownloadSpeed, '', @@ -701,6 +706,7 @@ class _DownloadSpeedWorker(HttpGetManager): self.hasSpeedResult = False self.totalBytesRead = 0 self.hasDataCounter = 0 + self.cancelled = False self._startInProgress = False self._completionInProgress = False @@ -1029,6 +1035,8 @@ class _DownloadSpeedWorker(HttpGetManager): try: value = networkReply.error().name except Exception: + # Any non-exit exceptions + value = 'UnknownError' if isinstance(value, bytes): diff --git a/Furious/Window/SettingsPage.py b/Furious/Window/SettingsPage.py index 263300a..ba09a8d 100644 --- a/Furious/Window/SettingsPage.py +++ b/Furious/Window/SettingsPage.py @@ -1094,6 +1094,8 @@ class SettingsPage(Mixins.QTranslatable, QMainWindow): for section in sections: self._addPluginDescriptorSection(section) except Exception as ex: + # Any non-exit exceptions + logger.error( f'failed to create settings from plugin ' f'{metadata.id!r}: {ex}' @@ -1103,6 +1105,8 @@ class SettingsPage(Mixins.QTranslatable, QMainWindow): try: self._addPluginActionSection(plugin, metadata, registry) except Exception as ex: + # Any non-exit exceptions + logger.error( f'failed to create management settings from plugin ' f'{metadata.id!r}: {ex}' diff --git a/tests/test_log_manager_generation.py b/tests/test_log_manager_generation.py index 8545930..3984bab 100644 --- a/tests/test_log_manager_generation.py +++ b/tests/test_log_manager_generation.py @@ -396,6 +396,7 @@ class GenerationLogManagerContractTest(unittest.TestCase): def testSeededModelBasedStateMachine(self): """Compare arbitrary public transitions to a flat reference model.""" seeds = (0, 1, 7, 19, 41, 97, 313, 997) + for seed in seeds: with self.subTest(seed=seed): randomizer = random.Random(seed) @@ -407,6 +408,7 @@ class GenerationLogManagerContractTest(unittest.TestCase): for operationIndex in range(350): operation = randomizer.randrange(100) + try: if operation < 66: categoryId = randomizer.choice(categories) @@ -414,6 +416,7 @@ class GenerationLogManagerContractTest(unittest.TestCase): ('', 'x', 'line\n', 'šŸ˜€é', '\0', 'z' * 93) ) history.append(('append', categoryId, len(message))) + self.appendBoth(manager, model, message, categoryId) elif operation < 73: categoryId = randomizer.choice(categories) @@ -1028,30 +1031,41 @@ class GenerationLogManagerContractTest(unittest.TestCase): autoClearEnabled=False, ) manager.RetiredCleanupBudget = 64 + for index in range(size): manager.append(f'entry {index}', CORE_LOG_CATEGORY) + historical = manager.entries(CORE_LOG_CATEGORY) self.assertEqual(len(historical), size) + references = tuple(weakref.ref(entry) for entry in historical) externallyOwned = historical[-1] + manager.clear(runtimeOnly=True) + self.assertTrue( all(reference() is not None for reference in references) ) + while manager.retiredEntryCount: with manager._lock: manager._cleanupRetiredLocked() + self.assertTrue( all(reference() is not None for reference in references) ) + del historical gc.collect() + self.assertTrue( all(reference() is None for reference in references[:-1]) ) self.assertIs(references[-1](), externallyOwned) + del externallyOwned gc.collect() + self.assertIsNone(references[-1]()) def testRetentionThreeWayMergeAndLargeSequences(self): @@ -1195,9 +1209,11 @@ class GenerationLogManagerContractTest(unittest.TestCase): def observedGeneration(category): generation = original(category) + if threading.get_ident() in appendThreadId and not selected.is_set(): selected.set() self.assertTrue(release.wait(5)) + return generation manager._generationForCategoryLocked = observedGeneration @@ -1205,6 +1221,7 @@ class GenerationLogManagerContractTest(unittest.TestCase): def append(): appendThreadId.append(threading.get_ident()) + try: manager.append('racing', CORE_LOG_CATEGORY) except Exception as error: @@ -1212,14 +1229,18 @@ class GenerationLogManagerContractTest(unittest.TestCase): producer = threading.Thread(target=append) clearer = threading.Thread(target=lambda: manager.clear(runtimeOnly=True)) + producer.start() self.assertTrue(selected.wait(5)) + clearer.start() time.sleep(0.01) self.assertTrue(clearer.is_alive()) + release.set() producer.join(5) clearer.join(5) + self.assertFalse(producer.is_alive()) self.assertFalse(clearer.is_alive()) self.assertEqual(errors, []) @@ -1579,11 +1600,13 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase): autoClearMaximumEntries=100, ) manager.RetiredCleanupBudget = 64 + ordinary = [] rollover = [] retention = [] maximumRetired = 0 maximumBatches = 0 + for index in range(50_000): categoryId = CORE_LOG_CATEGORY if index % 3 else APPLICATION_LOG_CATEGORY triggersRollover = ( @@ -1597,15 +1620,18 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase): manager.entryCount() + 1 > manager.maximumEntries or manager.retainedCharacters + len(message) > manager.maximumCharacters ) + started = time.perf_counter_ns() manager.append(message, categoryId) elapsed = time.perf_counter_ns() - started + if triggersRollover: rollover.append(elapsed) elif atRetention or causesRetention: retention.append(elapsed) else: ordinary.append(elapsed) + maximumRetired = max(maximumRetired, manager.retiredEntryCount) maximumBatches = max(maximumBatches, len(manager._retiredBatches)) @@ -1623,6 +1649,7 @@ class VeryHeavyGenerationLogManagerTest(unittest.TestCase): self.assertTrue(rollover) self.assertLessEqual(maximumRetired, manager.maximumEntries) _assertManagerInvariants(self, manager) + self.report( 'append-latency', ordinary=distribution(ordinary),