summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Lees <gus@inodes.org>2016-02-19 14:28:58 +1100
committerAngus Lees <gus@inodes.org>2016-02-19 15:52:23 +1100
commit9d289463957b74bed29e30f93326ee1e664d2873 (patch)
tree4409b381b8bd549cb3fb10a03fb3c9e6bf4758ab
parentfa04ee7df3493291ea66d05fa093db9f88f52048 (diff)
downloadoslo-concurrency-9d289463957b74bed29e30f93326ee1e664d2873.tar.gz
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
-rw-r--r--oslo_concurrency/processutils.py15
-rw-r--r--oslo_concurrency/tests/unit/test_processutils.py16
2 files changed, 27 insertions, 4 deletions
diff --git a/oslo_concurrency/processutils.py b/oslo_concurrency/processutils.py
index 436922a..b74e5f2 100644
--- a/oslo_concurrency/processutils.py
+++ b/oslo_concurrency/processutils.py
@@ -63,26 +63,33 @@ class UnknownArgumentError(Exception):
class ProcessExecutionError(Exception):
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
description=None):
+ super(ProcessExecutionError, self).__init__(
+ stdout, stderr, exit_code, cmd, description)
self.exit_code = exit_code
self.stderr = stderr
self.stdout = stdout
self.cmd = cmd
self.description = description
+ def __str__(self):
+ description = self.description
if description is None:
description = _("Unexpected error while running command.")
+
+ exit_code = self.exit_code
if exit_code is None:
exit_code = '-'
+
message = _('%(description)s\n'
'Command: %(cmd)s\n'
'Exit code: %(exit_code)s\n'
'Stdout: %(stdout)r\n'
'Stderr: %(stderr)r') % {'description': description,
- 'cmd': cmd,
+ 'cmd': self.cmd,
'exit_code': exit_code,
- 'stdout': stdout,
- 'stderr': stderr}
- super(ProcessExecutionError, self).__init__(message)
+ 'stdout': self.stdout,
+ 'stderr': self.stderr}
+ return message
class NoRootWrapSpecified(Exception):
diff --git a/oslo_concurrency/tests/unit/test_processutils.py b/oslo_concurrency/tests/unit/test_processutils.py
index b868cb5..0fd8045 100644
--- a/oslo_concurrency/tests/unit/test_processutils.py
+++ b/oslo_concurrency/tests/unit/test_processutils.py
@@ -19,6 +19,7 @@ import errno
import logging
import multiprocessing
import os
+import pickle
import resource
import stat
import subprocess
@@ -467,6 +468,21 @@ grep foo
def test_binary_undecodable_bytes_error(self):
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):
def setUp(self):