Skip to content

Commit 524b777

Browse files
committed
Issue 2517: Allow unicode messages in Exceptions again by correctly bypassing the instance dictionary when looking up __unicode__ on new-style classes
1 parent dbc5987 commit 524b777

3 files changed

Lines changed: 57 additions & 9 deletions

File tree

Lib/test/test_exceptions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ def testUnicodeStrUsage(self):
342342
self.failUnless(unicode(Exception))
343343
self.failUnless(str(Exception('a')))
344344
self.failUnless(unicode(Exception(u'a')))
345+
self.failUnless(unicode(Exception(u'\xe1')))
345346

346347

347348
def test_main():

Objects/exceptions.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,28 @@ BaseException_str(PyBaseExceptionObject *self)
117117
return out;
118118
}
119119

120+
#ifdef Py_USING_UNICODE
121+
static PyObject *
122+
BaseException_unicode(PyBaseExceptionObject *self)
123+
{
124+
PyObject *out;
125+
126+
switch (PyTuple_GET_SIZE(self->args)) {
127+
case 0:
128+
out = PyUnicode_FromString("");
129+
break;
130+
case 1:
131+
out = PyObject_Unicode(PyTuple_GET_ITEM(self->args, 0));
132+
break;
133+
default:
134+
out = PyObject_Unicode(self->args);
135+
break;
136+
}
137+
138+
return out;
139+
}
140+
#endif
141+
120142
static PyObject *
121143
BaseException_repr(PyBaseExceptionObject *self)
122144
{
@@ -181,6 +203,9 @@ BaseException_setstate(PyObject *self, PyObject *state)
181203
static PyMethodDef BaseException_methods[] = {
182204
{"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS },
183205
{"__setstate__", (PyCFunction)BaseException_setstate, METH_O },
206+
#ifdef Py_USING_UNICODE
207+
{"__unicode__", (PyCFunction)BaseException_unicode, METH_NOARGS },
208+
#endif
184209
{NULL, NULL, 0, NULL},
185210
};
186211

Objects/object.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ PyObject_Unicode(PyObject *v)
458458
PyObject *res;
459459
PyObject *func;
460460
PyObject *str;
461+
int unicode_method_found = 0;
461462
static PyObject *unicodestr;
462463

463464
if (v == NULL) {
@@ -471,26 +472,46 @@ PyObject_Unicode(PyObject *v)
471472
Py_INCREF(v);
472473
return v;
473474
}
474-
/* XXX As soon as we have a tp_unicode slot, we should
475-
check this before trying the __unicode__
476-
method. */
475+
476+
/* Try the __unicode__ method */
477477
if (unicodestr == NULL) {
478478
unicodestr= PyString_InternFromString("__unicode__");
479479
if (unicodestr == NULL)
480480
return NULL;
481481
}
482-
func = PyObject_GetAttr(v, unicodestr);
483-
if (func != NULL) {
484-
res = PyEval_CallObject(func, (PyObject *)NULL);
485-
Py_DECREF(func);
482+
if (PyInstance_Check(v)) {
483+
/* We're an instance of a classic class */
484+
/* Try __unicode__ from the instance -- alas we have no type */
485+
func = PyObject_GetAttr(v, unicodestr);
486+
if (func != NULL) {
487+
unicode_method_found = 1;
488+
res = PyObject_CallFunctionObjArgs(func, NULL);
489+
Py_DECREF(func);
490+
}
491+
else {
492+
PyErr_Clear();
493+
}
486494
}
487495
else {
488-
PyErr_Clear();
496+
/* Not a classic class instance, try __unicode__ from type */
497+
/* _PyType_Lookup doesn't create a reference */
498+
func = _PyType_Lookup(Py_TYPE(v), unicodestr);
499+
if (func != NULL) {
500+
unicode_method_found = 1;
501+
res = PyObject_CallFunctionObjArgs(func, v, NULL);
502+
}
503+
else {
504+
PyErr_Clear();
505+
}
506+
}
507+
508+
/* Didn't find __unicode__ */
509+
if (!unicode_method_found) {
489510
if (PyUnicode_Check(v)) {
490511
/* For a Unicode subtype that's didn't overwrite __unicode__,
491512
return a true Unicode object with the same data. */
492513
return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v),
493-
PyUnicode_GET_SIZE(v));
514+
PyUnicode_GET_SIZE(v));
494515
}
495516
if (PyString_CheckExact(v)) {
496517
Py_INCREF(v);
@@ -503,6 +524,7 @@ PyObject_Unicode(PyObject *v)
503524
res = PyObject_Repr(v);
504525
}
505526
}
527+
506528
if (res == NULL)
507529
return NULL;
508530
if (!PyUnicode_Check(res)) {

0 commit comments

Comments
 (0)