Skip to content

Commit

Permalink
made sure custom strings like MessageID are not converted
Browse files Browse the repository at this point in the history
  • Loading branch information
Unknown committed Aug 1, 2005
0 parents commit 8ed5b83
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
84 changes: 84 additions & 0 deletions tests/testustr.py
@@ -0,0 +1,84 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ustr unit tests.
$Id$
"""

import unittest

from DocumentTemplate.ustr import ustr


class force_str:
# A class whose string representation is not always a plain string:
def __init__(self,s):
self.s = s
def __str__(self):
return self.s


class Foo(str):

pass


class Bar(unicode):

pass


class UnicodeTests(unittest.TestCase):

def testPlain(self):
a = ustr('hello')
assert a=='hello', `a`
a = ustr(force_str('hello'))
assert a=='hello', `a`
a = ustr(chr(200))
assert a==chr(200), `a`
a = ustr(force_str(chr(200)))
assert a==chr(200), `a`
a = ustr(22)
assert a=='22', `a`
a = ustr([1,2,3])
assert a=='[1, 2, 3]', `a`

def testUnicode(self):
a = ustr(u'hello')
assert a=='hello', `a`
a = ustr(force_str(u'hello'))
assert a=='hello', `a`
a = ustr(unichr(200))
assert a==unichr(200), `a`
a = ustr(force_str(unichr(200)))
assert a==unichr(200), `a`

def testExceptions(self):
a = ustr(ValueError(unichr(200)))
assert a==unichr(200), `a`

def testCustomStrings(self):
a = ustr(Foo('foo'))
self.failUnlessEqual(type(a), Foo)
a = ustr(Bar('bar'))
self.failUnlessEqual(type(a), Bar)


def test_suite():
suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( UnicodeTests ) )
return suite

if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
62 changes: 62 additions & 0 deletions ustr.py
@@ -0,0 +1,62 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ustr function.
$Id$
"""

nasty_exception_str = Exception.__str__.im_func

def ustr(v):
"""Convert any object to a plain string or unicode string,
minimising the chance of raising a UnicodeError. This
even works with uncooperative objects like Exceptions
"""
if isinstance(v, basestring):
return v
else:
fn = getattr(v,'__str__',None)
if fn is not None:
# An object that wants to present its own string representation,
# but we dont know what type of string. We cant use any built-in
# function like str() or unicode() to retrieve it because
# they all constrain the type which potentially raises an exception.
# To avoid exceptions we have to call __str__ direct.
if getattr(fn,'im_func',None)==nasty_exception_str:
# Exception objects have been optimised into C, and their
# __str__ function fails when given a unicode object.
# Unfortunately this scenario is all too common when
# migrating to unicode, because of code which does:
# raise ValueError(something_I_wasnt_expecting_to_be_unicode)
return _exception_str(v)
else:
# Trust the object to do this right
v = fn()
if isinstance(v, basestring):
return v
else:
raise ValueError('__str__ returned wrong type')
# Drop through for non-instance types, and instances that
# do not define a special __str__
return str(v)


def _exception_str(exc):
if hasattr(exc, 'args'):
if not exc.args:
return ''
elif len(exc.args) == 1:
return ustr(exc.args[0])
else:
return str(exc.args)
return str(exc)

0 comments on commit 8ed5b83

Please sign in to comment.