From 569f5584b0194fa6d2c52df65a50e26154f7d72a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 2 Oct 2024 16:28:52 -0700 Subject: [PATCH] actions: Handle exceptions with Path-like objects - When subprocess.call() fails and one of the arguments is a Path-like object, the exception also contains a Path-like object. The default JSON encoder can't handle this and will lead to failure when encoding the exception altogether resulting in a generic exception. Tests: - Add an invalid .zim file to kiwix. It fails and shows a default error exception. Without this patch, it fails. - Functional tests for kiwix pass. - Backups app can list archives. This is a result returned from a privileged method. Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/actions.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plinth/actions.py b/plinth/actions.py index 01e296961..02cad2bd3 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -8,6 +8,7 @@ import inspect import json import logging import os +import pathlib import subprocess import sys import threading @@ -305,6 +306,19 @@ def _log_action(func, module_name, action_name, args, kwargs, run_as_user, formatted_args, suffix) +class JSONEncoder(json.JSONEncoder): + """Handle to special types that default JSON encoder does not.""" + + def default(self, obj): + """Handle special object types.""" + # When subprocess.call() fails and one of the arguments is a Path-like + # object, the exception also contains a Path-like object. + if isinstance(obj, pathlib.Path): + return str(obj) + + return super().default(obj) + + def privileged_main(): """Parse arguments for the program spawned as a privileged action.""" log.action_init() @@ -330,7 +344,7 @@ def privileged_main(): return_value = _privileged_call(args.module, args.action, arguments) with os.fdopen(args.write_fd, 'w') as write_file_handle: - write_file_handle.write(json.dumps(return_value)) + write_file_handle.write(json.dumps(return_value, cls=JSONEncoder)) except PermissionError as exception: logger.error(exception.args[0]) sys.exit(EXIT_PERM)