diff options
-rw-r--r-- | nose/plugins/capture.py | 28 | ||||
-rw-r--r-- | nose/plugins/xunit.py | 26 | ||||
-rw-r--r-- | nose/pyversion.py | 56 |
3 files changed, 59 insertions, 51 deletions
diff --git a/nose/plugins/capture.py b/nose/plugins/capture.py index d9041d8..fa4e5dc 100644 --- a/nose/plugins/capture.py +++ b/nose/plugins/capture.py @@ -13,7 +13,7 @@ import logging import os import sys from nose.plugins.base import Plugin -from nose.pyversion import is_base_exception +from nose.pyversion import exc_to_unicode, force_unicode from nose.util import ln from StringIO import StringIO @@ -87,30 +87,8 @@ class Capture(Plugin): return self.formatError(test, err) def addCaptureToErr(self, ev, output): - if is_base_exception(ev): - if hasattr(ev, '__unicode__'): - # 2.6+ - try: - ev = unicode(ev) - except UnicodeDecodeError: - # We need a unicode string... take our best shot at getting, - # since we don't know what the original encoding is in. - ev = str(ev).decode('utf8', 'replace') - else: - # 2.5- - if not hasattr(ev, 'message'): - # 2.4 - msg = len(ev.args) and ev.args[0] or '' - else: - msg = ev.message - if (isinstance(msg, basestring) and - not isinstance(msg, unicode)): - msg = msg.decode('utf8', 'replace') - ev = u'%s: %s' % (ev.__class__.__name__, msg) - elif not isinstance(ev, basestring): - ev = repr(ev) - if not isinstance(output, unicode): - output = output.decode('utf8', 'replace') + ev = exc_to_unicode(ev) + output = force_unicode(output) return u'\n'.join([ev, ln(u'>> begin captured stdout <<'), output, ln(u'>> end captured stdout <<')]) diff --git a/nose/plugins/xunit.py b/nose/plugins/xunit.py index 7899bc1..20fad24 100644 --- a/nose/plugins/xunit.py +++ b/nose/plugins/xunit.py @@ -49,7 +49,7 @@ from xml.sax import saxutils from nose.plugins.base import Plugin from nose.exc import SkipTest -from nose.pyversion import UNICODE_STRINGS +from nose.pyversion import force_unicode, format_exception # Invalid XML characters, control characters 0-31 sans \t, \n and \r CONTROL_CHARACTERS = re.compile(r"[\000-\010\013\014\016-\037]") @@ -115,30 +115,6 @@ def exc_message(exc_info): result = force_unicode(result, 'UTF-8') return xml_safe(result) -def force_unicode(s, encoding): - if not UNICODE_STRINGS: - if isinstance(s, str): - s = s.decode(encoding, 'replace') - return s - -def format_exception(exc_info, encoding): - ec, ev, tb = exc_info - - # formatError() may have turned our exception object into a string, and - # Python 3's traceback.format_exception() doesn't take kindly to that (it - # expects an actual exception object). So we work around it, by doing the - # work ourselves if ev is a string. - if isinstance(ev, basestring): - tb_data = force_unicode( - ''.join(traceback.format_tb(tb)), - encoding) - ev = force_unicode(ev, encoding) - return tb_data + ev - else: - return force_unicode( - ''.join(traceback.format_exception(*exc_info)), - encoding) - class Tee(object): def __init__(self, encoding, *args): self._encoding = encoding diff --git a/nose/pyversion.py b/nose/pyversion.py index 14a133e..268b2b7 100644 --- a/nose/pyversion.py +++ b/nose/pyversion.py @@ -3,19 +3,27 @@ This module contains fixups for using nose under different versions of Python. """ import sys import os +import traceback import types import inspect import nose.util __all__ = ['make_instancemethod', 'cmp_to_key', 'sort_list', 'ClassType', 'TypeType', 'UNICODE_STRINGS', 'unbound_method', 'ismethod', - 'bytes_', 'is_base_exception'] + 'bytes_', 'is_base_exception', 'force_unicode', 'exc_to_unicode', + 'format_exception'] # In Python 3.x, all strings are unicode (the call to 'unicode()' in the 2.x # source will be replaced with 'str()' when running 2to3, so this test will # then become true) UNICODE_STRINGS = (type(unicode()) == type(str())) +def force_unicode(s, encoding='UTF-8'): + if not UNICODE_STRINGS: + if isinstance(s, str): + s = s.decode(encoding, 'replace') + return s + # new.instancemethod() is obsolete for new-style classes (Python 3.x) # We need to use descriptor methods instead. try: @@ -156,3 +164,49 @@ if sys.version_info[:2] < (2, 5): else: def is_base_exception(exc): return isinstance(exc, BaseException) + +def exc_to_unicode(ev, encoding='utf-8'): + if is_base_exception(ev): + if hasattr(ev, '__unicode__'): + # 2.6+ + try: + ev = unicode(ev) + except UnicodeDecodeError: + # We need a unicode string... take our best shot at getting, + # since we don't know what the original encoding is in. + ev = str(ev).decode(encoding, 'replace') + else: + # 2.5- + if not hasattr(ev, 'message'): + # 2.4 + msg = len(ev.args) and ev.args[0] or '' + else: + msg = ev.message + if (isinstance(msg, basestring) and + not isinstance(msg, unicode)): + msg = msg.decode(encoding, 'replace') + ev = u'%s: %s' % (ev.__class__.__name__, msg) + elif not isinstance(ev, basestring): + ev = repr(ev) + elif not UNICODE_STRINGS and isinstance(ev, str): + ev = ev.decode(encoding, 'replace') + + return ev + +def format_exception(exc_info, encoding='UTF-8'): + ec, ev, tb = exc_info + + # Our exception object may have been turned into a string, and Python 3's + # traceback.format_exception() doesn't take kindly to that (it expects an + # actual exception object). So we work around it, by doing the work + # ourselves if ev is not an exception object. + if not is_base_exception(ev): + tb_data = force_unicode( + ''.join(traceback.format_tb(tb)), + encoding) + ev = exc_to_unicode(ev) + return tb_data + ev + else: + return force_unicode( + ''.join(traceback.format_exception(*exc_info)), + encoding) |