未验证 提交 3a886972 编写于 作者: C Cleber Rosa

Merge branch 'pickle-exc-handler'

......@@ -34,6 +34,7 @@ from .status import mapping
from ..utils import wait
from ..utils import runtime
from ..utils import process
from ..utils import stacktrace
TEST_LOG = logging.getLogger("avocado.test")
APP_LOG = logging.getLogger("avocado.app")
......@@ -298,13 +299,20 @@ class TestRunner(object):
runtime.CURRENT_TEST = instance
early_state = instance.get_state()
early_state['early_status'] = True
queue.put(early_state)
try:
queue.put(early_state)
except Exception:
instance.error(stacktrace.str_unpickable_object(early_state))
self.result.start_test(early_state)
try:
instance.run_avocado()
finally:
queue.put(instance.get_state())
try:
state = instance.get_state()
queue.put(state)
except Exception:
instance.error(stacktrace.str_unpickable_object(state))
def setup(self):
"""
......
......@@ -4,6 +4,8 @@ Traceback standard module plus some additional APIs.
from traceback import format_exception
import logging
import inspect
import pickle
from pprint import pformat
def tb_info(exc_info):
......@@ -53,3 +55,64 @@ def log_message(message, logger='root'):
log = logging.getLogger(logger)
for line in message.splitlines():
log.error(line)
def analyze_unpickable_item(path_prefix, obj):
"""
Recursive method to obtain unpickable objects along with location
:param path_prefix: Path to this object
:param obj: The sub-object under introspection
:return: [($path_to_the_object, $value), ...]
"""
_path_prefix = path_prefix
try:
if hasattr(obj, "iteritems"):
subitems = obj.iteritems()
path_prefix += "[%s]"
elif hasattr(obj, "items"):
subitems = obj.items()
path_prefix += "[%s]"
elif isinstance(obj, list):
subitems = enumerate(obj)
path_prefix += "[%s]"
elif hasattr(obj, "__iter__"):
subitems = enumerate(obj.__iter__())
path_prefix += "<%s>"
elif hasattr(obj, "__dict__"):
subitems = obj.__dict__.iteritems()
path_prefix += ".%s"
else:
return [(path_prefix, obj)]
except Exception:
return [(path_prefix, obj)]
unpickables = []
for key, value in subitems:
try:
pickle.dumps(value)
except Exception:
ret = analyze_unpickable_item(path_prefix % key, value)
if ret:
unpickables.extend(ret)
if not unpickables:
return [(_path_prefix, obj)]
return unpickables
def str_unpickable_object(obj):
"""
Return human readable string identifying the unpickable objects
:param obj: The object for analysis
:raise ValueError: In case the object is pickable
"""
try:
pickle.dumps(obj)
except Exception:
pass
else:
raise ValueError("This object is pickable:\n%s" % pformat(obj))
unpickables = analyze_unpickable_item("this", obj)
return ("Unpickable object in:\n %s\nItems causing troubles:\n "
% "\n ".join(pformat(obj).splitlines()) +
"\n ".join("%s => %s" % obj for obj in unpickables))
#! /usr/bin/env python
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See LICENSE for more details.
#
# Copyright: 2016 Red Hat, Inc.
# Author: Lukas Doktor <ldoktor@redhat.com>
"""
avocado.utils.stacktrace unittests
"""
import re
import unittest
from avocado.utils import stacktrace
class Unpickable(object):
"""
Dummy class which does not support pickling
"""
def __getstate__(self):
raise NotImplementedError()
class InClassUnpickable(object):
"""
Dummy class containing unpickable object inside itself
"""
def __init__(self):
self.troublemaker = Unpickable()
class ListWithUnpickableAttribute(list):
"""
Dummy list class containing also unpickable attribute
"""
def __init__(self, *args, **kwargs):
self.__troublemaker = Unpickable()
super(ListWithUnpickableAttribute, self).__init__(*args, **kwargs)
class TestUnpickableObject(unittest.TestCase):
"""
Basic selftests for `avocado.utils.stacktrace.str_unpickable_object
"""
def test_basic(self):
""" Basic usage """
def check(exps, obj):
""" Search exps in the output of str_unpickable_object(obj) """
act = stacktrace.str_unpickable_object(obj)
for exp in exps:
if not re.search(exp, act):
self.fail("%r no match in:\n%s" % (exp, act))
self.assertRaises(ValueError, stacktrace.str_unpickable_object,
([{"foo": set([])}]))
check(["this => .*Unpickable"], Unpickable())
check([r"this\[0\]\[0\]\[foo\]\.troublemaker => .*Unpickable"],
[[{"foo": InClassUnpickable()}]])
check([r"this\[foo\] => \[1, 2, 3\]"],
{"foo": ListWithUnpickableAttribute([1, 2, 3])})
check([r"this\[foo\]\[3\] => .*Unpickable"],
{"foo": ListWithUnpickableAttribute([1, 2, 3, Unpickable()])})
check([r"this\[2\] => .*Unpickable",
r"this\[3\]\[foo\].troublemaker => .*Unpickable",
r"this\[4\]\[0\].troublemaker => .*Unpickable"],
[1, 2, Unpickable(), {"foo": InClassUnpickable(), "bar": None},
ListWithUnpickableAttribute(ListWithUnpickableAttribute(
[InClassUnpickable()]))])
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册