Make ProcessExecutionError picklable
Serialising/deserialising exceptions in python follows the protocol defined by pickle. It relies on the base Exception.__init__ setting self.args, and later resurrects exceptions with class(*args). This change rewrites processutils.ProcessExecutionError so it survives a pickle.dumps/loads round-trip. Change-Id: I9b8d104f60df868be7b808c72c932d08f1752777
This commit is contained in:
parent
fa04ee7df3
commit
9d28946395
@ -63,26 +63,33 @@ class UnknownArgumentError(Exception):
|
|||||||
class ProcessExecutionError(Exception):
|
class ProcessExecutionError(Exception):
|
||||||
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
||||||
description=None):
|
description=None):
|
||||||
|
super(ProcessExecutionError, self).__init__(
|
||||||
|
stdout, stderr, exit_code, cmd, description)
|
||||||
self.exit_code = exit_code
|
self.exit_code = exit_code
|
||||||
self.stderr = stderr
|
self.stderr = stderr
|
||||||
self.stdout = stdout
|
self.stdout = stdout
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
description = self.description
|
||||||
if description is None:
|
if description is None:
|
||||||
description = _("Unexpected error while running command.")
|
description = _("Unexpected error while running command.")
|
||||||
|
|
||||||
|
exit_code = self.exit_code
|
||||||
if exit_code is None:
|
if exit_code is None:
|
||||||
exit_code = '-'
|
exit_code = '-'
|
||||||
|
|
||||||
message = _('%(description)s\n'
|
message = _('%(description)s\n'
|
||||||
'Command: %(cmd)s\n'
|
'Command: %(cmd)s\n'
|
||||||
'Exit code: %(exit_code)s\n'
|
'Exit code: %(exit_code)s\n'
|
||||||
'Stdout: %(stdout)r\n'
|
'Stdout: %(stdout)r\n'
|
||||||
'Stderr: %(stderr)r') % {'description': description,
|
'Stderr: %(stderr)r') % {'description': description,
|
||||||
'cmd': cmd,
|
'cmd': self.cmd,
|
||||||
'exit_code': exit_code,
|
'exit_code': exit_code,
|
||||||
'stdout': stdout,
|
'stdout': self.stdout,
|
||||||
'stderr': stderr}
|
'stderr': self.stderr}
|
||||||
super(ProcessExecutionError, self).__init__(message)
|
return message
|
||||||
|
|
||||||
|
|
||||||
class NoRootWrapSpecified(Exception):
|
class NoRootWrapSpecified(Exception):
|
||||||
|
@ -19,6 +19,7 @@ import errno
|
|||||||
import logging
|
import logging
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
|
import pickle
|
||||||
import resource
|
import resource
|
||||||
import stat
|
import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -467,6 +468,21 @@ grep foo
|
|||||||
def test_binary_undecodable_bytes_error(self):
|
def test_binary_undecodable_bytes_error(self):
|
||||||
self.check_undecodable_bytes_error(True)
|
self.check_undecodable_bytes_error(True)
|
||||||
|
|
||||||
|
def test_picklable(self):
|
||||||
|
exc = processutils.ProcessExecutionError(
|
||||||
|
stdout='my stdout', stderr='my stderr',
|
||||||
|
exit_code=42, cmd='my cmd',
|
||||||
|
description='my description')
|
||||||
|
exc_message = str(exc)
|
||||||
|
|
||||||
|
exc = pickle.loads(pickle.dumps(exc))
|
||||||
|
self.assertEqual('my stdout', exc.stdout)
|
||||||
|
self.assertEqual('my stderr', exc.stderr)
|
||||||
|
self.assertEqual(42, exc.exit_code)
|
||||||
|
self.assertEqual('my cmd', exc.cmd)
|
||||||
|
self.assertEqual('my description', exc.description)
|
||||||
|
self.assertEqual(exc_message, str(exc))
|
||||||
|
|
||||||
|
|
||||||
class ProcessExecutionErrorLoggingTest(test_base.BaseTestCase):
|
class ProcessExecutionErrorLoggingTest(test_base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user