diff options
-rw-r--r-- | Include/object.h | 1 | ||||
-rw-r--r-- | Lib/test/test_unicode.py | 4 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Objects/object.c | 38 | ||||
-rw-r--r-- | Objects/stringobject.c | 12 |
5 files changed, 42 insertions, 17 deletions
diff --git a/Include/object.h b/Include/object.h index fd7c235..15fee96 100644 --- a/Include/object.h +++ b/Include/object.h @@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(void) _PyObject_Dump(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); +PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); #ifdef Py_USING_UNICODE PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *); diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 80242d5..d85f171 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -388,6 +388,10 @@ class UnicodeTest( self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10 abc') self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc') self.assertEqual('%c' % u'a', u'a') + class Wrapper: + def __str__(self): + return u'\u1234' + self.assertEqual('%s' % Wrapper(), u'\u1234') def test_constructor(self): # unicode(obj) tests (this maps to PyObject_Unicode() at C level) @@ -118,6 +118,10 @@ Core and builtins positions. It once again reports a syntax error if a future statement occurs after anything other than a doc string. +- Change the %s format specifier for str objects so that it returns a + unicode instance if the argument is not an instance of basestring and + calling __str__ on the argument returns a unicode instance. + Extension Modules ----------------- diff --git a/Objects/object.c b/Objects/object.c index 975c967..1895697 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v) } PyObject * -PyObject_Str(PyObject *v) +_PyObject_Str(PyObject *v) { PyObject *res; - + int type_ok; if (v == NULL) return PyString_FromString("<NULL>"); if (PyString_CheckExact(v)) { Py_INCREF(v); return v; } +#ifdef Py_USING_UNICODE + if (PyUnicode_CheckExact(v)) { + Py_INCREF(v); + return v; + } +#endif if (v->ob_type->tp_str == NULL) return PyObject_Repr(v); res = (*v->ob_type->tp_str)(v); if (res == NULL) return NULL; + type_ok = PyString_Check(res); +#ifdef Py_USING_UNICODE + type_ok = type_ok || PyUnicode_Check(res); +#endif + if (!type_ok) { + PyErr_Format(PyExc_TypeError, + "__str__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; +} + +PyObject * +PyObject_Str(PyObject *v) +{ + PyObject *res = _PyObject_Str(v); + if (res == NULL) + return NULL; #ifdef Py_USING_UNICODE if (PyUnicode_Check(res)) { PyObject* str; @@ -358,13 +384,7 @@ PyObject_Str(PyObject *v) return NULL; } #endif - if (!PyString_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__str__ returned non-string (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } + assert(PyString_Check(res)); return res; } diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 8a9dc52..9bcae0f 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v) return 1; } - /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) FORMATBUFLEN is the length of the buffer in which the floats, ints, & @@ -4079,7 +4078,9 @@ PyString_Format(PyObject *format, PyObject *args) break; case 's': #ifdef Py_USING_UNICODE - if (PyUnicode_Check(v)) { + temp = _PyObject_Str(v); + if (temp != NULL && PyUnicode_Check(temp)) { + Py_DECREF(temp); fmt = fmt_start; argidx = argidx_start; goto unicode; @@ -4087,16 +4088,11 @@ PyString_Format(PyObject *format, PyObject *args) #endif /* Fall through */ case 'r': - if (c == 's') - temp = PyObject_Str(v); - else + if (c == 'r') temp = PyObject_Repr(v); if (temp == NULL) goto error; if (!PyString_Check(temp)) { - /* XXX Note: this should never happen, - since PyObject_Repr() and - PyObject_Str() assure this */ PyErr_SetString(PyExc_TypeError, "%s argument has non-string str()"); Py_DECREF(temp); |