summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Szakmeister <john@szakmeister.net>2013-08-11 07:33:16 -0400
committerJohn Szakmeister <john@szakmeister.net>2013-08-11 07:52:56 -0400
commit47c8d89e601e93e0606f810d1cb75f834fd81f77 (patch)
treecf8680ea9ad42a6a19dab217222aa6a9382eb955
parentb3198e0c8586030d3366d5c5ea762d6b4e4b2e29 (diff)
downloadnose-47c8d89e601e93e0606f810d1cb75f834fd81f77.tar.gz
Centralize some unicode and exception helpers into pyversion.
While we're at it, teach format_exception() to use the new exc_to_unicode() helper derived from work done in capture.py.
-rw-r--r--nose/plugins/capture.py28
-rw-r--r--nose/plugins/xunit.py26
-rw-r--r--nose/pyversion.py56
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)