Index: Include/object.h =================================================================== --- Include/object.h (revision 63954) +++ Include/object.h (working copy) @@ -408,6 +408,11 @@ /* Type attribute cache version tag. Added in version 2.6 */ unsigned int tp_version_tag; +#ifdef Py_USING_UNICODE + /* Added in version 2.6 */ + reprfunc tp_unicode; +#endif + #ifdef COUNT_ALLOCS /* these must be last and never explicitly initialized */ Py_ssize_t tp_allocs; Index: Objects/object.c =================================================================== --- Objects/object.c (revision 63954) +++ Objects/object.c (working copy) @@ -471,14 +471,15 @@ Py_INCREF(v); return v; } - /* XXX As soon as we have a tp_unicode slot, we should - check this before trying the __unicode__ - method. */ - if (unicodestr == NULL) { + if (Py_TYPE(v)->tp_unicode != NULL) { + unicodestr = (*Py_TYPE(v)->tp_unicode)(v); + return unicodestr; + } else { unicodestr= PyBytes_InternFromString("__unicode__"); if (unicodestr == NULL) return NULL; } + func = PyObject_GetAttr(v, unicodestr); if (func != NULL) { res = PyEval_CallObject(func, (PyObject *)NULL); Index: Objects/exceptions.c =================================================================== --- Objects/exceptions.c (revision 63954) +++ Objects/exceptions.c (working copy) @@ -117,7 +117,29 @@ 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 * BaseException_repr(PyBaseExceptionObject *self) { PyObject *repr_suffix; @@ -352,6 +374,16 @@ (initproc)BaseException_init, /* tp_init */ 0, /* tp_alloc */ BaseException_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + (reprfunc)BaseException_unicode, /*tp_unicode*/ }; /* the CPython API expects exceptions to be (PyObject *) - both a hold-over from the previous implmentation and also allowing Python objects to be used @@ -374,6 +406,7 @@ (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ 0, 0, 0, offsetof(PyBaseExceptionObject, dict), \ (initproc)BaseException_init, 0, BaseException_new,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)BaseException_unicode,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME @@ -390,6 +423,7 @@ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ (initproc)EXCSTORE ## _init, 0, BaseException_new,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)BaseException_unicode,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME @@ -407,6 +441,7 @@ EXCMEMBERS, 0, &_ ## EXCBASE, \ 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ (initproc)EXCSTORE ## _init, 0, BaseException_new,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)BaseException_unicode,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME Index: Lib/test/test_exceptions.py =================================================================== --- Lib/test/test_exceptions.py (revision 63954) +++ Lib/test/test_exceptions.py (working copy) @@ -340,8 +340,13 @@ # representation. self.failUnless(str(Exception)) self.failUnless(unicode(Exception)) + self.failUnless(unicode(BaseException)) + self.failUnless(unicode(ValueError)) self.failUnless(str(Exception('a'))) self.failUnless(unicode(Exception(u'a'))) + self.failUnless(unicode(Exception(u'\xe1'))) + self.failUnless(unicode(BaseException(u'\xe1'))) + self.failUnless(unicode(ValueError(u'\xe1'))) def test_main():