Issue 2517: Allow unicode messages in Exceptions again by correctly bypassing the instance dictionary when looking up __unicode__ on new-style classes

This commit is contained in:
Nick Coghlan 2008-07-08 14:08:04 +00:00
parent dbc5987e2f
commit 524b7773cc
3 changed files with 57 additions and 9 deletions

View File

@ -342,6 +342,7 @@ class ExceptionTests(unittest.TestCase):
self.failUnless(unicode(Exception)) self.failUnless(unicode(Exception))
self.failUnless(str(Exception('a'))) self.failUnless(str(Exception('a')))
self.failUnless(unicode(Exception(u'a'))) self.failUnless(unicode(Exception(u'a')))
self.failUnless(unicode(Exception(u'\xe1')))
def test_main(): def test_main():

View File

@ -117,6 +117,28 @@ BaseException_str(PyBaseExceptionObject *self)
return out; return out;
} }
#ifdef Py_USING_UNICODE
static PyObject *
BaseException_unicode(PyBaseExceptionObject *self)
{
PyObject *out;
switch (PyTuple_GET_SIZE(self->args)) {
case 0:
out = PyUnicode_FromString("");
break;
case 1:
out = PyObject_Unicode(PyTuple_GET_ITEM(self->args, 0));
break;
default:
out = PyObject_Unicode(self->args);
break;
}
return out;
}
#endif
static PyObject * static PyObject *
BaseException_repr(PyBaseExceptionObject *self) BaseException_repr(PyBaseExceptionObject *self)
{ {
@ -181,6 +203,9 @@ BaseException_setstate(PyObject *self, PyObject *state)
static PyMethodDef BaseException_methods[] = { static PyMethodDef BaseException_methods[] = {
{"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS },
{"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, {"__setstate__", (PyCFunction)BaseException_setstate, METH_O },
#ifdef Py_USING_UNICODE
{"__unicode__", (PyCFunction)BaseException_unicode, METH_NOARGS },
#endif
{NULL, NULL, 0, NULL}, {NULL, NULL, 0, NULL},
}; };

View File

@ -458,6 +458,7 @@ PyObject_Unicode(PyObject *v)
PyObject *res; PyObject *res;
PyObject *func; PyObject *func;
PyObject *str; PyObject *str;
int unicode_method_found = 0;
static PyObject *unicodestr; static PyObject *unicodestr;
if (v == NULL) { if (v == NULL) {
@ -471,21 +472,41 @@ PyObject_Unicode(PyObject *v)
Py_INCREF(v); Py_INCREF(v);
return v; return v;
} }
/* XXX As soon as we have a tp_unicode slot, we should
check this before trying the __unicode__ /* Try the __unicode__ method */
method. */
if (unicodestr == NULL) { if (unicodestr == NULL) {
unicodestr= PyString_InternFromString("__unicode__"); unicodestr= PyString_InternFromString("__unicode__");
if (unicodestr == NULL) if (unicodestr == NULL)
return NULL; return NULL;
} }
if (PyInstance_Check(v)) {
/* We're an instance of a classic class */
/* Try __unicode__ from the instance -- alas we have no type */
func = PyObject_GetAttr(v, unicodestr); func = PyObject_GetAttr(v, unicodestr);
if (func != NULL) { if (func != NULL) {
res = PyEval_CallObject(func, (PyObject *)NULL); unicode_method_found = 1;
res = PyObject_CallFunctionObjArgs(func, NULL);
Py_DECREF(func); Py_DECREF(func);
} }
else { else {
PyErr_Clear(); PyErr_Clear();
}
}
else {
/* Not a classic class instance, try __unicode__ from type */
/* _PyType_Lookup doesn't create a reference */
func = _PyType_Lookup(Py_TYPE(v), unicodestr);
if (func != NULL) {
unicode_method_found = 1;
res = PyObject_CallFunctionObjArgs(func, v, NULL);
}
else {
PyErr_Clear();
}
}
/* Didn't find __unicode__ */
if (!unicode_method_found) {
if (PyUnicode_Check(v)) { if (PyUnicode_Check(v)) {
/* For a Unicode subtype that's didn't overwrite __unicode__, /* For a Unicode subtype that's didn't overwrite __unicode__,
return a true Unicode object with the same data. */ return a true Unicode object with the same data. */
@ -503,6 +524,7 @@ PyObject_Unicode(PyObject *v)
res = PyObject_Repr(v); res = PyObject_Repr(v);
} }
} }
if (res == NULL) if (res == NULL)
return NULL; return NULL;
if (!PyUnicode_Check(res)) { if (!PyUnicode_Check(res)) {