From d512e4268c94e5f76f232ec1cb15b74436e5354e Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Tue, 5 Mar 2024 07:36:55 -0500 Subject: [PATCH] diagnostics: Handle TypeError when copying results Display and log an error, including contents of current_results. Clear the contents of current_results. Tests: - View the diagnostics results as normal. - Introduce a TypeError before the results are copied. See the error message shown in the interface. (The error details are cleared when the page is refreshed.) Helps: #2410 Signed-off-by: James Valleroy [sunil: Fix a mypy error] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/diagnostics/__init__.py | 20 ++++++++++++++++---- plinth/modules/diagnostics/views.py | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/plinth/modules/diagnostics/__init__.py b/plinth/modules/diagnostics/__init__.py index cdef381a5..16180b5a8 100644 --- a/plinth/modules/diagnostics/__init__.py +++ b/plinth/modules/diagnostics/__init__.py @@ -103,7 +103,8 @@ def _run_on_all_enabled_modules(): current_results = { 'apps': [], 'results': collections.OrderedDict(), - 'progress_percentage': 0 + 'progress_percentage': 0, + 'exception': None, } for app in app_module.App.list(): @@ -335,15 +336,26 @@ def are_results_available(): return bool(results) -def get_results(): +def get_results() -> dict: """Return the latest results of full diagnostics.""" + global current_results + with results_lock: - results = deepcopy(current_results) + try: + results = deepcopy(current_results) + except TypeError as error: + # See #2410: cannot pickle 'dict_values' object + logger.error('Cannot get diagnostic results: %s - %s', error, + current_results) + exception = str(error) + ' - ' + str(current_results) + # Clear the results that can't be used. + current_results = {} + return {'exception': exception} # If no results are available in memory, then load from database. if not results: results = kvstore.get_default('diagnostics_results', '{}') - results = json.loads(results, cls=CheckJSONDecoder) + results = json.loads(str(results), cls=CheckJSONDecoder) results = {'results': results, 'progress_percentage': 100} # Add a translated name for each app diff --git a/plinth/modules/diagnostics/views.py b/plinth/modules/diagnostics/views.py index c9bd1ab8b..6a9437631 100644 --- a/plinth/modules/diagnostics/views.py +++ b/plinth/modules/diagnostics/views.py @@ -75,6 +75,10 @@ class DiagnosticsFullView(TemplateView): context['is_task_running'] = is_task_running context['results'] = diagnostics.get_results() context['refresh_page_sec'] = 3 if is_task_running else None + exception = context['results'].pop('exception', None) + if exception: + messages.error(self.request, exception) + return context